Code Monkey home page Code Monkey logo

scooby's Introduction

🐶🕵️ Scooby

Downloads Tests PyPI Status Conda Status codecov

Great Dane turned Python environment detective

This is a lightweight tool for easily reporting your Python environment's package versions and hardware resources.

Install from PyPI

pip install scooby

or from conda-forge

conda install -c conda-forge scooby

Jupyter Notebook Formatting

Scooby has HTML formatting for Jupyter notebooks and rich text formatting for just about every other environment. We designed this module to be lightweight such that it could easily be added as a dependency to Python projects for environment reporting when debugging. Simply add scooby to your dependencies and implement a function to have scooby report on the aspects of the environment you care most about.

If scooby is unable to detect aspects of an environment that you'd like to know, please share this with us as a feature requests or pull requests.

The scooby reporting is derived from the versioning-scripts created by Dieter Werthmüller for empymod, emg3d, and the SimPEG framework. It was heavily inspired by ipynbtools.py from qutip and watermark.py. This package has been altered to create a lightweight implementation so that it can easily be used as an environment reporting tool in any Python library with minimal impact.

Usage

Generating Reports

Reports are rendered as html-tables in Jupyter notebooks as shown in the screenshot above, and otherwise as plain text lists. If you do not output the Report object either at the end of a notebook cell or it is generated somewhere in a vanilla Python script, you may have to print the Report object: print(scooby.Report()), but note that this will only output the plain text representation of the script.

>>> import scooby
>>> scooby.Report()
--------------------------------------------------------------------------------
  Date: Wed Feb 12 15:35:43 2020 W. Europe Standard Time

                OS : Windows
            CPU(s) : 16
           Machine : AMD64
      Architecture : 64bit
               RAM : 31.9 GiB
       Environment : IPython

  Python 3.7.6 | packaged by conda-forge | (default, Jan  7 2020, 21:48:41)
  [MSC v.1916 64 bit (AMD64)]

             numpy : 1.18.1
             scipy : 1.3.1
           IPython : 7.12.0
        matplotlib : 3.0.3
            scooby : 0.5.0

  Intel(R) Math Kernel Library Version 2019.0.4 Product Build 20190411 for
  Intel(R) 64 architecture applications
--------------------------------------------------------------------------------

For all the Scooby-Doo fans out there, doo is an alias for Report so you can oh-so satisfyingly do:

>>> import scooby
>>> scooby.doo()
--------------------------------------------------------------------------------
  Date: Thu Nov 25 09:47:50 2021 MST

                OS : Darwin
            CPU(s) : 12
           Machine : x86_64
      Architecture : 64bit
               RAM : 32.0 GiB
       Environment : Python
       File system : apfs

  Python 3.8.12 | packaged by conda-forge | (default, Oct 12 2021, 21:50:38)
  [Clang 11.1.0 ]

             numpy : 1.21.4
             scipy : 1.7.3
           IPython : 7.29.0
        matplotlib : 3.5.0
            scooby : 0.5.8
--------------------------------------------------------------------------------

Or better yet:

from scooby import doo as doobiedoo

On top of the default (optional) packages you can provide additional packages, either as strings or give already imported packages:

>>> import pyvista
>>> import scooby
>>> scooby.Report(additional=[pyvista, 'vtk', 'no_version', 'does_not_exist'])
--------------------------------------------------------------------------------
  Date: Wed Feb 12 16:15:15 2020 W. Europe Standard Time

                OS : Windows
            CPU(s) : 16
           Machine : AMD64
      Architecture : 64bit
               RAM : 31.9 GiB
       Environment : IPython

  Python 3.7.6 | packaged by conda-forge | (default, Jan  7 2020, 21:48:41)
  [MSC v.1916 64 bit (AMD64)]

           pyvista : 0.23.1
               vtk : 8.1.2
        no_version : Version unknown
    does_not_exist : Could not import
             numpy : 1.18.1
             scipy : 1.3.1
           IPython : 7.12.0
        matplotlib : 3.0.3
            scooby : 0.5.0

  Intel(R) Math Kernel Library Version 2019.0.4 Product Build 20190411 for
  Intel(R) 64 architecture applications
--------------------------------------------------------------------------------

Furthermore, scooby reports if a package could not be imported or if the version of a package could not be determined.

Other useful parameters are

  • ncol: number of columns in the html-table;
  • text_width: text width of the plain-text version;
  • sort: list is sorted alphabetically if True.

Besides additional there are two more lists, core and optional, which can be used to provide package names. However, they are mostly useful for package maintainers wanting to use scooby to create their reporting system (see below).

Implementing scooby in your project

You can easily generate a custom Report instance using scooby within your project:

class Report(scooby.Report):
    def __init__(self, additional=None, ncol=3, text_width=80, sort=False):
        """Initiate a scooby.Report instance."""

        # Mandatory packages.
        core = ['yourpackage', 'your_core_packages', 'e.g.', 'numpy', 'scooby']

        # Optional packages.
        optional = ['your_optional_packages', 'e.g.', 'matplotlib']

        scooby.Report.__init__(self, additional=additional, core=core,
                               optional=optional, ncol=ncol,
                               text_width=text_width, sort=sort)

This makes it particularly easy for a user of your project to quickly generate a report on all of the relevant package versions and environment details when sumbitting a bug.

>>> import your_package
>>> your_package.Report()

The packages on the core-list are the mandatory ones for your project, while the optional-list can be used for optional packages. Keep the additional-list free to allow your users to add packages to the list.

Implementing as a soft dependency

If you would like to implement scooby, but are hesitant to add another dependency to your package, here is an easy way how you can use scooby as a soft dependency. Instead of import scooby use the following snippet:

# Make scooby a soft dependency:
try:
    from scooby import Report as ScoobyReport
except ImportError:
    class ScoobyReport:
        def __init__(self, *args, **kwargs):
            message = (
                '\n  *ERROR*: `Report` requires `scooby`.'
                '\n           Install it via `pip install scooby` or'
                '\n           `conda install -c conda-forge scooby`.\n'
            )
            raise ImportError(message)

and then create your own Report class same as above,

class Report(ScoobyReport):
    def __init__(self, additional=None, ncol=3, text_width=80, sort=False):
        """Initiate a scooby.Report instance."""

        # Mandatory packages.
        core = ['yourpackage', 'your_core_packages', 'e.g.', 'numpy', 'scooby']

        # Optional packages.
        optional = ['your_optional_packages', 'e.g.', 'matplotlib']

        scooby.Report.__init__(self, additional=additional, core=core,
                               optional=optional, ncol=ncol,
                               text_width=text_width, sort=sort)

If a user has scooby installed, all works as expected. If scooby is not installed, it will raise the following exception:

>>> import your_package
>>> your_package.Report()

  *ERROR*: `Report` requires `scooby`
           Install it via `pip install scooby` or
           `conda install -c conda-forge scooby`.

Autogenerate Reports for any Packages

Scooby can automatically generate a Report for any package and its distribution requirements with the AutoReport class:

>>> import scooby
>>> scooby.AutoReport('matplotlib')
--------------------------------------------------------------------------------
  Date: Fri Oct 20 16:49:34 2023 PDT

                OS : Darwin
            CPU(s) : 8
           Machine : arm64
      Architecture : 64bit
               RAM : 16.0 GiB
       Environment : Python
       File system : apfs

  Python 3.11.3 | packaged by conda-forge | (main, Apr  6 2023, 08:58:31)
  [Clang 14.0.6 ]

        matplotlib : 3.7.1
         contourpy : 1.0.7
            cycler : 0.11.0
         fonttools : 4.39.4
        kiwisolver : 1.4.4
             numpy : 1.24.3
         packaging : 23.1
            pillow : 9.5.0
         pyparsing : 3.0.9
   python-dateutil : 2.8.2
--------------------------------------------------------------------------------

Solving Mysteries

Are you struggling with the mystery of whether or not code is being executed in IPython, Jupyter, or normal Python? Try using some of scooby's investigative functions to solve these kinds of mysteries:

import scooby

if scooby.in_ipykernel():
    # Do Jupyter/IPyKernel stuff
elif scooby.in_ipython():
    # Do IPython stuff
else:
    # Do normal, boring Python stuff

How does scooby get version numbers?

A couple of locations are checked, and we are happy to implement more if needed, just open an issue!

Currently, it looks in the following places:

  • __version__
  • version
  • lookup VERSION_ATTRIBUTES in the scooby knowledge base
  • lookup VERSION_METHODS in the scooby knowledge base

VERSION_ATTRIBUTES is a dictionary of attributes for known python packages with a non-standard place for the version. You can add other known places via:

scooby.knowledge.VERSION_ATTRIBUTES['a_module'] = 'Awesome_version_location'

Similarly, VERSION_METHODS is a dictionary for methods to retrieve the version, and you can similarly add your methods which will get the version of a package.

Using scooby to get version information.

If you are only interested in the version of a single package then you can use scooby as well. A few examples:

>>> import scooby, numpy
>>> scooby.get_version(numpy)
('numpy', '1.16.4')
>>> scooby.get_version('no_version')
('no_version', 'Version unknown')
>>> scooby.get_version('does_not_exist')
('does_not_exist', 'Could not import')

Note that modules can be provided as already loaded ones or as strings.

Tracking Imports in a Session

Scooby has the ability to track all imported modules during a Python session such that any imported, non-standard lib package that is used in the session is reported by a TrackedReport. For instance, start a session by importing scooby and enabling tracking with the track_imports() function. Then all subsequent packages that are imported during the session will be tracked and scooby can report their versions. Once you are ready to generate a Report, instantiate a TrackedReport object.

In the following example, we import a constant from scipy which will report the versions of scipy and numpy as both packages are loaded in the session (note that numpy is internally loaded by scipy).

>>> import scooby
>>> scooby.track_imports()

>>> from scipy.constants import mu_0 # a float value

>>> scooby.TrackedReport()
--------------------------------------------------------------------------------
  Date: Thu Apr 16 15:33:11 2020 MDT

                OS : Linux
            CPU(s) : 8
           Machine : x86_64
      Architecture : 64bit
               RAM : 62.7 GiB
       Environment : IPython

  Python 3.7.7 (default, Mar 10 2020, 15:16:38)  [GCC 7.5.0]

            scooby : 0.5.2
             numpy : 1.18.1
             scipy : 1.4.1
--------------------------------------------------------------------------------

Command-Line Interface

Scooby comes with a command-line interface. Simply typing

scooby

in a terminal will display the default report. You can also use the CLI to show the scooby Report of another package if that package has implemented a Report class as suggested above, using packagename.Report().

As an example, to print the report of pyvista you can run

scooby -r pyvista

which will show the Report implemented in PyVista.

The CLI can also generate a report based on the dependencies of a package's distribution where that package hasn't implemented a Report class. For example, we can generate a Report for matplotlib and its dependencies:

$ scooby -r matplotlib
--------------------------------------------------------------------------------
  Date: Fri Oct 20 17:03:45 2023 PDT

                 OS : Darwin
             CPU(s) : 8
            Machine : arm64
       Architecture : 64bit
                RAM : 16.0 GiB
        Environment : Python
        File system : apfs

  Python 3.11.3 | packaged by conda-forge | (main, Apr  6 2023, 08:58:31)
  [Clang 14.0.6 ]

         matplotlib : 3.7.1
          contourpy : 1.0.7
             cycler : 0.11.0
          fonttools : 4.39.4
         kiwisolver : 1.4.4
              numpy : 1.24.3
          packaging : 23.1
             pillow : 9.5.0
          pyparsing : 3.0.9
    python-dateutil : 2.8.2
importlib-resources : 5.12.0
--------------------------------------------------------------------------------

Simply type

scooby --help

to see all the possibilities.

Optional Requirements

The following is a list of optional requirements and their purpose:

  • psutil: report total RAM in GiB
  • mkl-services: report Intel(R) Math Kernel Library version

scooby's People

Contributors

adam-grant-hendry avatar akaszynski avatar alexfikl avatar artistmatej avatar banesullivan avatar carsten-forty2 avatar fabaff avatar gryfenfer97 avatar prisae avatar schwehr avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

scooby's Issues

Scooby upwards of version 0.5.7 segfaults Python

Coming from: pyvista/pyvista#1961

I get an immediate segfault when importing scooby, versions 0.5.8, 0.5.9, and 0.5.10.

I'll try and see if I can narrow it down a little more.

System information, for completeness (collected with 0.5.7 ^^):

--------------------------------------------------------------------------------
  Date: Thu Dec 23 16:28:20 2021 W. Europe Standard Time

                OS : Windows
            CPU(s) : 8
           Machine : AMD64
      Architecture : 64bit
               RAM : 31.9 GiB
       Environment : Python

  Python 3.8.12 | packaged by conda-forge | (default, Oct 12 2021, 21:22:46)
  [MSC v.1916 64 bit (AMD64)]

             numpy : 1.20.3
             scipy : 1.7.3
           IPython : 7.30.1
        matplotlib : 3.5.1
            scooby : 0.5.7
--------------------------------------------------------------------------------

pip freeze

Try the possibility of grep'ing pip freeze to get the version information. Works also if there is no __version__-information.

Off-spin from #36

psutil ImportError

Python 3.8.12 | packaged by conda-forge | (default, Oct 12 2021, 21:50:56)
[Clang 11.1.0 ] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from scooby import Report
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/bane/Software/personal/scooby/scooby/__init__.py", line 18, in <module>
    from scooby.report import Report, get_version
  File "/Users/bane/Software/personal/scooby/scooby/report.py", line 16, in <module>
    import psutil
ModuleNotFoundError: No module named 'psutil'
>>>

After install psutil, here is my Report:

--------------------------------------------------------------------------------
  Date: Wed Nov 24 17:33:06 2021 MST

                OS : Darwin
            CPU(s) : 12
           Machine : x86_64
      Architecture : 64bit
               RAM : 32.0 GiB
       Environment : Python
       File system : apfs

  Python 3.8.12 | packaged by conda-forge | (default, Oct 12 2021, 21:50:56)
  [Clang 11.1.0 ]

             numpy : 1.21.4
             scipy : 1.7.3
           IPython : 7.29.0
        matplotlib : 3.5.0
            scooby : 0.5.7
--------------------------------------------------------------------------------

Improved BLAS/LAPACK guessing

If OK with @seberg we should include this
https://gist.github.com/seberg/ce4563f3cb00e33997e4f80675b80953
instead of our often unsuccessful approach

try:
    import mkl
    mkl.get_version_string()
except (ImportError, AttributeError):
    mkl = False

try:
    import numexpr
except ImportError:
    numexpr = False

# Get mkl info from numexpr or mkl, if available
if mkl:
    MKL_INFO = mkl.get_version_string()
elif numexpr:
    MKL_INFO = numexpr.get_vml_version()
else:
    MKL_INFO = False

What do you think @banesullivan ?

GDAL Version

How do you get the version for GDAL and what else is important about GDAL?

This doesn't seem very useful:

>>> import gdal
>>> gdal.VersionInfo()
'3000000'

or is '3000000' legitimately my version of GDAL and that would be insightful to developers around GDAL when bug reporting?

I feel like there are probably different compilation options that are important. Also what about osgeo.gdal, is that different?

distutils deprecated in python 3.10

I know this is early but on python 3.10, I notice the following:

/opt/hostedtoolcache/Python/3.10.2/x64/lib/python3.10/site-packages/scooby/__init__.py:18: in <module>
    from scooby.knowledge import (  # noqa
/opt/hostedtoolcache/Python/3.10.2/x64/lib/python3.10/site-packages/scooby/knowledge.py:14: in <module>
    import distutils.sysconfig as sysconfig
/opt/hostedtoolcache/Python/3.10.2/x64/lib/python3.10/distutils/__init__.py:19: in <module>
    warnings.warn(_DEPRECATION_MESSAGE,
E   DeprecationWarning: The distutils package is deprecated and slated for removal in Python 3.12. Use setuptools or check PEP 632 for potential alternatives

Related to pyvista/pyvistaqt#147

File System unknown

I get a

File system : unknown

Related to #76

Before, this section was omitted if not found (mainly because psutil is not installed). With #76, it is shown even if unknown.

[Message was edited to reflect what I found for creating #80.]

Code style: Black?

I'm playing around with Black and it's super easy to integrate into projects with a pre-commit hook.

@prisae - how would you feel about trying this out here? Since this project is in its infancy, it'd be much easier to start something like this

Inspired by pyvista/pyvista#288

Handle errors during import

Some packages might throw an error on import if improperly configured. On my machine, I don't have pyvips properly installed and it throws an OSError on import which isn't handled by scooby:

>>> import scooby
>>> scooby.Report(['pyvips'])
Traceback (most recent call last):
  File "/Users/bane/anaconda3/envs/geospatial/lib/python3.8/site-packages/pyvips/__init__.py", line 19, in <module>
    import _libvips
ModuleNotFoundError: No module named '_libvips'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/bane/anaconda3/envs/geospatial/lib/python3.8/site-packages/scooby/report.py", line 170, in __init__
    PythonInfo.__init__(self, additional=additional, core=core,
  File "/Users/bane/anaconda3/envs/geospatial/lib/python3.8/site-packages/scooby/report.py", line 82, in __init__
    self._add_packages(additional)               # Provided by the user
  File "/Users/bane/anaconda3/envs/geospatial/lib/python3.8/site-packages/scooby/report.py", line 99, in _add_packages
    name, version = get_version(pckg)
  File "/Users/bane/anaconda3/envs/geospatial/lib/python3.8/site-packages/scooby/report.py", line 377, in get_version
    module = importlib.import_module(name)
  File "/Users/bane/anaconda3/envs/geospatial/lib/python3.8/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1014, in _gcd_import
  File "<frozen importlib._bootstrap>", line 991, in _find_and_load
  File "<frozen importlib._bootstrap>", line 975, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 671, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 843, in exec_module
  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
  File "/Users/bane/anaconda3/envs/geospatial/lib/python3.8/site-packages/pyvips/__init__.py", line 71, in <module>
    vips_lib = ffi.dlopen(_vips_libname)
  File "/Users/bane/anaconda3/envs/geospatial/lib/python3.8/site-packages/cffi/api.py", line 150, in dlopen
    lib, function_cache = _make_ffi_library(self, name, flags)
  File "/Users/bane/anaconda3/envs/geospatial/lib/python3.8/site-packages/cffi/api.py", line 832, in _make_ffi_library
    backendlib = _load_backend_lib(backend, libname, flags)
  File "/Users/bane/anaconda3/envs/geospatial/lib/python3.8/site-packages/cffi/api.py", line 827, in _load_backend_lib
    raise OSError(msg)
OSError: cannot load library 'libvips.42.dylib': dlopen(libvips.42.dylib, 0x0002): tried: '/Users/bane/anaconda3/envs/geospatial/lib/libvips.42.dylib' (no such file), '/Users/bane/anaconda3/envs/geospatial/lib/libvips.42.dylib' (no such file), '/Users/bane/anaconda3/envs/geospatial/lib/python3.8/site-packages/../../libvips.42.dylib' (no such file), '/Users/bane/anaconda3/envs/geospatial/lib/libvips.42.dylib' (no such file), '/Users/bane/anaconda3/envs/geospatial/bin/../lib/libvips.42.dylib' (no such file), 'libvips.42.dylib' (no such file), '/usr/local/lib/libvips.42.dylib' (no such file), '/usr/lib/libvips.42.dylib' (no such file), '/Users/bane/Software/personal/localtileserver/libvips.42.dylib' (no such file), '/usr/local/lib/libvips.42.dylib' (no such file), '/usr/lib/libvips.42.dylib' (no such file).  Additionally, ctypes.util.find_library() did not manage to locate a library called 'libvips.42.dylib'
>>>

support command line usage

might be nice to allow python -m scooby

it would just be a matter of creating scooby/__main__.py, containing:

from . import Report

def main():
    print(Report())

if __name__ == "__main__":
    main()

maybe adding argparse support later to allow things like HTML output

Add `reproducibility` to topics

I can not edit the topics. But I suggest you add reproducibility to the topics. Currently you have python, bug-reporting, system-information, and python-versions.

Show info about Scooby in the report

We should also add a header line to show info about the version of Scooby being used to make the report. Perhaps something light-hearted and simple like:

>>> scooby.investigate()
------------------------------------------------------
  Looks like we've got another mystery on our hands!
  Scooby 0.2.1 reporting for duty!
  Date: Sat Jun 29 14:32:01 2019 MDT
...

Restrict to two files

scooby is small, and it should stay like that. Minimal impact, acceptable for each and every project.

Would it make sense to have it all in one file? Would just be around 400 lines of code (including comments and blank lines).

Cell sorting

There seems to be an issue with the cell sorting. In the below image, I would expect

|  pyvista  |   pandas   |  joblib |
|   panel   | matplotlib |   vtk   |
|   numpy   |    scipy   | IPython |

hence only three rows nicely filled instead of four rows, partly half-filled.

Selection_001

Add soft-dependency example to docs

Something we should add to the docs once they exist: There is an easy, neat solution to make scooby a soft dependency:

# Make scooby a soft dependency:
try:
    from scooby import Report as ScoobyReport
except ImportError:
    class ScoobyReport:
        def __init__(self, additional, core, optional, ncol, text_width, sort):
            print('\n  *ERROR*: `Report` requires `scooby`.'
                  '\n           Install it via `pip install scooby`.\n')

class Report(ScoobyReport):
    def __init__(self, additional=None, ncol=3, text_width=80, sort=False):
        """Initiate a scooby.Report instance."""

        # Mandatory packages.
        core = ['yourpackage', 'your_core_packages', 'e.g.', 'numpy', 'scooby']

        # Optional packages.
        optional = ['your_optional_packages', 'e.g.', 'matplotlib']

        super().__init__(additional=additional, core=core, optional=optional,
                         ncol=ncol, text_width=text_width, sort=sort)

If a user has scooby installed, all works as expected. If scooby is not installed, it will just print the following message:

>>> import your_package
>>> your_package.Report()

  *ERROR*: `Report` requires `scooby`
           Install it via `pip install scooby`.

Use distutils instead of meets_version

Saw a snippet of code in pyvista today and figured it would be better to use distutils rather than reinventing the wheel:

>>> from distutils.version import LooseVersion
>>> LooseVersion('2.3.0b') > LooseVersion('2.2.0b')
True

This probably captures other edge cases (like LooseVersion('2.3.4.3.1')) that we would have to write from scratch.

@banesullivan, think it's ok to push a warning that we're going to remove the feature, or should we just use LooseVersion under the hood? Guess it sorta simplifies other people's code to use meets_version instead (if only just slightly).

To narrow width if there are packages with looong names

Currently we have the width for packages hardcoded to 18. Maybe we have to make this bigger, or check all package names and take a max(min_width, max_package_width) approach, where min_width is 18 (or similar), and max_package_width the width of the longest package name.

Selection_001

`in_jupyter`

scooby has the scooby.in_jupyter and scooby.in_ipython. Unfortunately it is not that simple. Particularly, as the kernels are not only used by the notebooks, but also by other frontends, e.g., QtConsole:

Jupyter QtConsole_001

I tried many things in the beginning of the Versions, but all the googling did not help. I do not know any way how to define if you are actually in a notebook or not. Or, in other words, if it can render html or not. So the QtConsole uses the kernel, but doesn't render html, for instance.

Long story short: The scooby.in_jupyter-promise is wrong. What do you think?

CLI wishlist

Wishlist for improvements / extensions of the CLI (copied over from #86 (comment))

  • Be able to grep for package names so that I could do scooby django-* and get a list of all the django-* packages like django-allauth, etc. This would be analogous to pip list | grep django-
  • Have scooby execute a Python script/command with tracked imports. This might look like scooby --track foo.py which would use tracking features to output a tracked report after completion.

org

How big are you thinking scooby will go? Maybe we should move it out to its own org rather sooner than later. The only thing missing for it is probably a logo. (We could make an 8bit-image of your dog-emoticon.)

I thought of https://github.com/opengeophysics first, but it is much more general than that, so it should have its own org I think. Later there might come other modules to it for similar tasks.

Additional info in report

What else should be in the report?

Also, checkout mne-python's mne.sys_info method from pyvista/pyvista#186 (comment)

additional info (as given by import mne; mne.sys_info()):

Platform:      Windows-10-10.0.17763-SP0
Python:        3.6.6 |Anaconda, Inc.| (default, Jun 28 2018, 11:27:44) [MSC v.1900 64 bit (AMD64)]
Executable:    C:\Users\mmagn\Continuum\anaconda3\python.exe
CPU:           Intel64 Family 6 Model 158 Stepping 10, GenuineIntel: 12 cores
Memory:        15.9 GB

numpy:         1.16.2 {blas=mkl_rt, lapack=mkl_rt}
matplotlib:    3.0.2 {backend=module://ipykernel.pylab.backend_inline}
mayavi:        4.6.2 {qt_api=pyqt5, PyQt5=5.9.2}

Showing the report in Python scripts

Recently, a user became a bit stumped on how to show a report in their Python script: see pyvista/pyvista-support#20 (comment)

They wanted to generate and show the report right after importing all their modules because they were experiencing a bug that would crash the kernel

Should we add a note in the README that users might have to call print(scooby.Report())

Copy table as plain text button

The HTML table representation should have a "copy" button to copy the plain text representation for easier use/sharing from Jupyter

non-standard lib dependencies

Should we allow non-standard lib dependencies like psutil which I just added?

I think it's rather important to report the total amount of RAM and psutil has a solution that works for all OS - which I'm not sure how to implement without psutil.

Also, we will definitely need GPU details for PyVista as #1 requests which I think will have to depend on more than one external lib for inspecting the different types of GPUs that could be present (NVIDIA, Radeon, etc.)

Perhaps these should be optional requirements so that this could remain a lightweight package for users that do not need RAM or GPU details?

Ensure __repr__ and _repr_html_ are the same

I think the two versions should be as similar as possible, so it doesn't matter from where you call it. You started to introduce differences. Three come to my mind:

  • OS: HTML: OS : Linux; Text: Platform: Linux-4.15.0-54-generic-x86_64-with-debian-buster-sid
  • Environment: printed in Text version, not in HTML version.
  • unavailable: reported in HTML as a normal package with version number unavailable; In the Text version there is a message printed that it wasn't found, and listed on its own list. I prefer the HTML version (again, as minimalistic as possible)

textwrap AttributeError: 'NoneType' object has no attribute 'expandtabs'

$ python -c "import pyvista;print(pyvista.Report())"
  
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/opt/hostedtoolcache/Python/3.10.6/x64/lib/python3.10/site-packages/scooby/report.py", line 298, in __repr__
    for txt in textwrap.wrap(self._mkl_info, self.text_width - 4):
  File "/opt/hostedtoolcache/Python/3.10.6/x64/lib/python3.10/textwrap.py", line 387, in wrap
    return w.wrap(text)
  File "/opt/hostedtoolcache/Python/3.10.6/x64/lib/python3.10/textwrap.py", line 359, in wrap
    chunks = self._split_chunks(text)
  File "/opt/hostedtoolcache/Python/3.10.6/x64/lib/python3.10/textwrap.py", line 345, in _split_chunks
    text = self._munge_whitespace(text)
  File "/opt/hostedtoolcache/Python/3.10.6/x64/lib/python3.10/textwrap.py", line 154, in _munge_whitespace
    text = text.expandtabs(self.tabsize)
AttributeError: 'NoneType' object has no attribute 'expandtabs'
Error: Process completed with exit code 1.

`codecov` PyPI package removed as deprecated

Issue

codecov was removed from PyPI as deprecated, but scooby's requirements_test.txt still includes codecov. Thus, pip installing the test dependencies fails.

Also, for those using poetry, installing with poetry add fails since poetry requires all dependencies to be compatible with each other and resolvable during install regardless of whether they are required for install. Hence, using poetry add scooby results in the error Package codecov (2.1.12) not found..

Recommendation

Per the deprecation guide:

  1. Remove codecov from requirements_test.txt
  2. Replace any calls to Codecov with the new Codecov Uploader
  3. If you are using coveragepy to collect code coverage, you will need to add
    coverage xml
    
    before calling the new uploader.

NOTE: Version 2.1.13, but not 2.1.12, was reinstated to PyPI see post-mortem message 1 and 2, but it appears all language-specific uploaders will eventually be deprecated (they haven't released the schedule yet, AFAIK). Using 2.1.13 might be a temporary workaround, but it may be wiser to focus the energy on following the deprecation guide steps instead.

Should warnings be thrown or...?

@staticmethod
def _safe_import_by_name(name, optional=False):
try:
module = importlib.import_module(name)
except ImportError:
if not optional:
logging.warning('RUH-ROH! Could not import module `{}`. This will be skipped.'.format(name))
module = None
return module

>>> import scooby
>>> scooby.investigate(additional=['foo',])
WARNING:root:RUH-ROH! Could not import module `foo`. This will be skipped.

------------------------------------------------------
  Date: Tue Jun 25 17:53:55 2019 MDT
  Platform: Darwin-18.5.0-x86_64-i386-64bit

             12 : CPU(s)
         x86_64 : Machine
          64bit : Architecture
        32.0 GB : RAM

  3.7.3 | packaged by conda-forge | (default, Mar 27
  2019, 15:43:19)  [Clang 4.0.1
  (tags/RELEASE_401/final)]

         1.16.3 : numpy
          1.3.0 : scipy
          7.5.0 : IPython
          3.1.0 : matplotlib

  Intel(R) Math Kernel Library Version 2018.0.3
  Product Build 20180406 for Intel(R) 64
  architecture applications
------------------------------------------------------

Should a warning be thrown like this and then skipped when reporting, or should we include the missing package in the report with a "not installed" flag of some sort? Maybe something like this:

------------------------------------------------------
  Date: Tue Jun 25 17:53:55 2019 MDT
  Platform: Darwin-18.5.0-x86_64-i386-64bit

             12 : CPU(s)
         x86_64 : Machine
          64bit : Architecture
        32.0 GB : RAM

  3.7.3 | packaged by conda-forge | (default, Mar 27
  2019, 15:43:19)  [Clang 4.0.1
  (tags/RELEASE_401/final)]

         1.16.3 : numpy
          1.3.0 : scipy
          7.5.0 : IPython
          3.1.0 : matplotlib
    unavailable : foo

  Intel(R) Math Kernel Library Version 2018.0.3
  Product Build 20180406 for Intel(R) 64
  architecture applications
------------------------------------------------------

And for:

scooby/scooby/versions.py

Lines 159 to 167 in 06df681

try:
attr = VERSION_ATTRIBUTES[name]
version = getattr(module, attr)
except (KeyError, AttributeError):
try:
version = module.__version__
except AttributeError:
logging.warning('RUH-ROH! Version attribute for `{}` is unknown.'.format(name))
version = 'unknown'

Should a warning be thrown at all since it reports unknown version? Even though the package is available..

Knowledge base

What packages should be in the knowledge base?

Should we make it only for packages that do not have a __version__ attribute?

Feature request: detect whether in script/jupyter/ipython

I imagine this is something that a lot of visualization libraries would want. There are some ways of telling if the kernel is IPython but I'm not sure if there is any robust way of knowing if on a notebook. It might expand the usage of Scooby beyond capturing an environment metadata in a notebook.

sphinx-gallery rendering

Would be nice to define style-settings to achieve a nicer rendering with sphinx-gallery.

nbviewer

Nicest and closest to how it actually looks in a notebook.

nbviewer

GitHub

Acceptable, readable, but not perfect.

GitHub

Sphinx-Gallery with RTD theme

Not nice, crowded and hard to read.

sphinx-gallery

Printing Report from `requirements.txt`

Hey there!

Had a potential feature to suggest:

I find myself often wanting to quickly make a Report based on the contents of a project's requirements.txt file. Maybe we could shorthand that by adding a new function to scooby with a call signature like scooby.report.from_requirements(filename) -> scooby.Report?

The output of such a function would be to create a scooby Report with all the packages mentioned in a requirements.txt file.

Here's the minimal code I've been using for this, type-hinted for readability:

import scooby
import re
from typing import List

with open("requirements.txt", "r") as f:
    packages: List[str] = f.read().split("\n")


def clean_package_name(s: str) -> str:
    """
    Takes in a line from a `requirements.txt` file and returns only the package name associated with that line.

    E.g.: "numpy >= 1.20" -> "numpy"
    """
    return re.split("<|>|=|!|~", s)[0].strip()


packages = [
    clean_package_name(p)
    for p in packages if p.strip() != ""
]
print(scooby.Report(core=packages, optional=[]))

LMK if interested and I can PR it.

Testing

We need real tests and we need to report code coverage. The current tests are minimal at best.

Remove `investigate`

I am not sure about the rationale behind investigate, as scooby.investigate() and scooby.Report() are identical. And there shouldn't be functions in an __init__.py-file. The only thing to do is move all the docstring from investigate() to Report.

I'll do a PR for that. But then there might have been some thinking/reasoning behind the decision I am not aware...?

create requirements.txt or conda env YAML based on Report

We should implement the ability to create a minimalist requirements.txt or conda environment YAML config file based on the Report

All too often, I need some sort of environment config to specify hard versions of what was used in an experiment when sharing it with others for reproducibility but exporting the entire environment is not necessary - I simply want to specify a few packages (like 10-20... so doing it manually is cumbersome) that are relevant to the project and leave it at that. I think scooby is well poised to implement this kind of feature.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.