diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..29af768f --- /dev/null +++ b/.dockerignore @@ -0,0 +1,9 @@ +.venv/* +.hypothesis/* +.pytest_cache/* +.vscode/* +htmlcov/* +pip-wheel-metadata/* +dist/* +*Dockerfile +postgres-data \ No newline at end of file diff --git a/.gitignore b/.gitignore index 3c015e25..e85f8f71 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,6 @@ api/config.ini scratchpad.ipynb .mypy_cache/ .coverage* +postgres-data/ + +.DS_Store \ No newline at end of file diff --git a/.isort.cfg b/.isort.cfg new file mode 100644 index 00000000..a68711eb --- /dev/null +++ b/.isort.cfg @@ -0,0 +1,2 @@ +[isort] +skip=tests/,.venv/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b8795781..4830d638 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,13 +1,17 @@ repos: - repo: https://github.com/pre-commit/mirrors-isort - rev: HEAD # Use the revision sha / tag you want to point at + rev: v4.3.21 # Use the revision sha / tag you want to point at hooks: - id: isort - repo: https://github.com/ambv/black - rev: stable + rev: 19.3b0 hooks: - id: black - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v1.2.3 + rev: v2.3.0 hooks: - id: flake8 +- repo: https://github.com/pre-commit/mirrors-mypy + rev: v0.730 # Use the sha / tag you want to point at + hooks: + - id: mypy \ No newline at end of file diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 00000000..27182b49 --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,8 @@ +python: + version: 3.7 + install: + - method: pip + path: . + extra_requirements: + - docs + system_packages: true diff --git a/.travis.yml b/.travis.yml index 043de72c..65eaab64 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,43 +4,48 @@ stages: - "Static code analysis" - test - deploy +notifications: + email: false python: - - "3.5" - "3.6" - "3.7" -notifications: - email: false -install: - - pip install --upgrade pip - - pip install poetry - - poetry install script: # run tests, and get coverage: - - poetry run python -m pytest --cov=src/ + - python -m pytest --cov=superintendent/ # test that the notebooks all run smoothly - - find docs -name '*.ipynb' -o -name 'examples/*.ipynb' | xargs poetry run jupyter nbconvert --to notebook --execute + - find docs -name '*.ipynb' -o -name 'examples/*.ipynb' | xargs jupyter nbconvert --to notebook --execute # submit coverage report to coveralls - - poetry run coveralls + - python -m coveralls +install: + - pip install -qq --upgrade pip + - pip install -q '.[test,examples]' jobs: include: - stage: "Static code analysis" name: "black formatting test" - script: + install: - pip install -qq black - - black --check src/ + script: + - black --check superintendent/ python: "3.7" - install: skip - stage: "Static code analysis" name: "flake8 check" - script: + install: - pip install -qq flake8 docargs - - flake8 src/ + script: + - flake8 superintendent/ + python: "3.7" + - stage: "Static code analysis" + name: "mypy check" + script: + - mypy --ignore-missing-imports superintendent/ python: "3.7" - install: skip + install: + - pip install -qq mypy - stage: deploy name: "Deploy to pypi" if: tag IS present script: - - poetry build - - poetry publish --username $PYPI_USER --password $PYPI_PASSWORD + - flit build + - env FLIT_USERNAME=$PYPI_USER FLIT_PASSWORD=$PYPI_PASSWORD flit publish python: "3.7" diff --git a/README.md b/README.md index 2ba08da5..861dea3c 100644 --- a/README.md +++ b/README.md @@ -12,15 +12,20 @@ ![](logo.png) -**`superintendent`** provides an `ipywidget`-based interactive labelling tool for your data. It allows you to flexibly label all kinds of data. It also allows you to combine your data-labelling task with a statistical or machine learning model to enable quick and practical active learning. +**`superintendent`** provides an `ipywidget`-based interactive labelling tool +for your data. It allows you to flexibly label all kinds of data. It also allows +you to combine your data-labelling task with a statistical or machine learning +model to enable quick and practical active learning. ## Getting started Take a look at the documentation: http://www.janfreyberg.com/superintendent/ -It has some explanations of how the library works, and it also has many examples. +It has some explanations of how the library works, and it also has many +examples. -If you'd like to try the library without installing it, check out the [repository on binder](https://mybinder.org/v2/gh/janfreyberg/superintendent/master?filepath=examples.ipynb). +If you'd like to try the library without installing it, check out the +[repository on binder](https://mybinder.org/v2/gh/janfreyberg/superintendent/master?filepath=examples.ipynb). ## Installation @@ -35,10 +40,13 @@ also have to enable the ipyevents jupyter extension: jupyter nbextension enable --py --sys-prefix ipyevents ``` -If you also want to run the examples, you need three additional packages: `requests`, `bs4` and `wordcloud`. You can install them via pip by running: +If you also want to run the examples, you need three additional packages: +`requests`, `bs4` and `wordcloud`. You can install them via pip by running: ``` pip install superintendent[examples] ``` -If you want to contribute to `superintendent`, you will need to install the test dependencies as well. You can do so with `pip install superintendent[tests,examples]` +If you want to contribute to `superintendent`, you will need to install the test +dependencies as well. You can do so with +`pip install superintendent[tests,examples]` diff --git a/docs/examples/labelling-images.ipynb b/docs/examples/labelling-images.ipynb index f153e069..39175d32 100644 --- a/docs/examples/labelling-images.ipynb +++ b/docs/examples/labelling-images.ipynb @@ -69,7 +69,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.1" + "version": "3.7.0" }, "widgets": { "application/vnd.jupyter.widget-state+json": { @@ -1618,5 +1618,5 @@ } }, "nbformat": 4, - "nbformat_minor": 2 + "nbformat_minor": 4 } diff --git a/docs/examples/labelling-text.ipynb b/docs/examples/labelling-text.ipynb index abc44d0d..9bc0a85a 100644 --- a/docs/examples/labelling-text.ipynb +++ b/docs/examples/labelling-text.ipynb @@ -84,7 +84,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.1" + "version": "3.7.3" }, "widgets": { "application/vnd.jupyter.widget-state+json": { diff --git a/examples.ipynb b/examples.ipynb index 337669cc..27460064 100644 --- a/examples.ipynb +++ b/examples.ipynb @@ -36,7 +36,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.1" + "version": "3.7.3" } }, "nbformat": 4, diff --git a/poetry.lock b/poetry.lock deleted file mode 100644 index b0900337..00000000 --- a/poetry.lock +++ /dev/null @@ -1,1275 +0,0 @@ -[[package]] -category = "dev" -description = "A configurable sidebar-enabled Sphinx theme" -name = "alabaster" -optional = false -python-versions = "*" -version = "0.7.12" - -[[package]] -category = "main" -description = "Disable App Nap on OS X 10.9" -marker = "python_version >= \"3.3\" and sys_platform == \"darwin\" or sys_platform == \"darwin\"" -name = "appnope" -optional = false -python-versions = "*" -version = "0.1.0" - -[[package]] -category = "dev" -description = "Atomic file writes." -name = "atomicwrites" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "1.3.0" - -[[package]] -category = "main" -description = "Classes Without Boilerplate" -name = "attrs" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "19.1.0" - -[[package]] -category = "dev" -description = "Internationalization utilities" -name = "babel" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "2.6.0" - -[package.dependencies] -pytz = ">=0a" - -[[package]] -category = "main" -description = "Specifications for callback functions passed in to an API" -name = "backcall" -optional = false -python-versions = "*" -version = "0.1.0" - -[[package]] -category = "dev" -description = "Screen-scraping library" -name = "beautifulsoup4" -optional = false -python-versions = "*" -version = "4.7.1" - -[package.dependencies] -soupsieve = ">=1.2" - -[[package]] -category = "main" -description = "An easy safelist-based HTML-sanitizing tool." -name = "bleach" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "3.1.0" - -[package.dependencies] -six = ">=1.9.0" -webencodings = "*" - -[[package]] -category = "dev" -description = "Dummy package for Beautiful Soup" -name = "bs4" -optional = false -python-versions = "*" -version = "0.0.1" - -[package.dependencies] -beautifulsoup4 = "*" - -[[package]] -category = "main" -description = "Extensible memoizing collections and decorators" -name = "cachetools" -optional = false -python-versions = "*" -version = "3.1.0" - -[[package]] -category = "dev" -description = "Python package for providing Mozilla's CA Bundle." -name = "certifi" -optional = false -python-versions = "*" -version = "2019.3.9" - -[[package]] -category = "dev" -description = "Universal encoding detector for Python 2 and 3" -name = "chardet" -optional = false -python-versions = "*" -version = "3.0.4" - -[[package]] -category = "main" -description = "Composable command line interface toolkit" -name = "click" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "7.0" - -[[package]] -category = "main" -description = "Cross-platform colored terminal text." -marker = "python_version >= \"3.3\" and sys_platform == \"win32\" or sys_platform == \"win32\"" -name = "colorama" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "0.4.1" - -[[package]] -category = "dev" -description = "Code coverage measurement for Python" -name = "coverage" -optional = false -python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, <4" -version = "4.5.3" - -[[package]] -category = "dev" -description = "Show coverage stats online via coveralls.io" -name = "coveralls" -optional = false -python-versions = "*" -version = "1.7.0" - -[package.dependencies] -coverage = ">=3.6" -docopt = ">=0.6.1" -requests = ">=1.0.0" - -[[package]] -category = "main" -description = "Composable style cycles" -name = "cycler" -optional = false -python-versions = "*" -version = "0.10.0" - -[package.dependencies] -six = "*" - -[[package]] -category = "main" -description = "Better living through Python with decorators" -name = "decorator" -optional = false -python-versions = ">=2.6, !=3.0.*, !=3.1.*" -version = "4.4.0" - -[[package]] -category = "main" -description = "XML bomb protection for Python stdlib modules" -name = "defusedxml" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "0.6.0" - -[[package]] -category = "dev" -description = "Pythonic argument parser, that will make you smile" -name = "docopt" -optional = false -python-versions = "*" -version = "0.6.2" - -[[package]] -category = "dev" -description = "Docutils -- Python Documentation Utilities" -name = "docutils" -optional = false -python-versions = "*" -version = "0.14" - -[[package]] -category = "main" -description = "Discover and load entry points from installed packages." -name = "entrypoints" -optional = false -python-versions = ">=2.7" -version = "0.3" - -[[package]] -category = "main" -description = "A simple framework for building complex web applications." -name = "flask" -optional = false -python-versions = "*" -version = "1.0.2" - -[package.dependencies] -Jinja2 = ">=2.10" -Werkzeug = ">=0.14" -click = ">=5.1" -itsdangerous = ">=0.24" - -[[package]] -category = "dev" -description = "HTML parser based on the WHATWG HTML specification" -name = "html5lib" -optional = false -python-versions = "*" -version = "1.0.1" - -[package.dependencies] -six = ">=1.9" -webencodings = "*" - -[[package]] -category = "dev" -description = "A library for property based testing" -name = "hypothesis" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "4.17.2" - -[package.dependencies] -attrs = ">=16.0.0" - -[[package]] -category = "dev" -description = "Internationalized Domain Names in Applications (IDNA)" -name = "idna" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "2.8" - -[[package]] -category = "dev" -description = "Getting image size from png/jpeg/jpeg2000/gif file" -name = "imagesize" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "1.1.0" - -[[package]] -category = "main" -description = "A custom widget for returning mouse and keyboard events to Python" -name = "ipyevents" -optional = false -python-versions = "*" -version = "0.4.1" - -[package.dependencies] -ipywidgets = ">=7.0.0" - -[[package]] -category = "main" -description = "IPython Kernel for Jupyter" -name = "ipykernel" -optional = false -python-versions = ">=3.4" -version = "5.1.0" - -[package.dependencies] -ipython = ">=5.0.0" -jupyter-client = "*" -tornado = ">=4.2" -traitlets = ">=4.1.0" - -[[package]] -category = "main" -description = "IPython: Productive Interactive Computing" -name = "ipython" -optional = false -python-versions = ">=3.5" -version = "7.4.0" - -[package.dependencies] -appnope = "*" -backcall = "*" -colorama = "*" -decorator = "*" -jedi = ">=0.10" -pexpect = "*" -pickleshare = "*" -prompt-toolkit = ">=2.0.0,<2.1.0" -pygments = "*" -setuptools = ">=18.5" -traitlets = ">=4.2" - -[package.dependencies.win-unicode-console] -python = "<3.6" -version = ">=0.5" - -[[package]] -category = "main" -description = "Vestigial utilities from IPython" -name = "ipython-genutils" -optional = false -python-versions = "*" -version = "0.2.0" - -[[package]] -category = "main" -description = "IPython HTML widgets for Jupyter" -name = "ipywidgets" -optional = false -python-versions = "*" -version = "7.4.2" - -[package.dependencies] -ipykernel = ">=4.5.1" -nbformat = ">=4.2.0" -traitlets = ">=4.3.1" -widgetsnbextension = ">=3.4.0,<3.5.0" - -[package.dependencies.ipython] -python = ">=3.3" -version = ">=4.0.0" - -[[package]] -category = "main" -description = "Various helpers to pass data to untrusted environments and back." -name = "itsdangerous" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "1.1.0" - -[[package]] -category = "main" -description = "An autocompletion tool for Python that can be used for text editors." -name = "jedi" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "0.13.3" - -[package.dependencies] -parso = ">=0.3.0" - -[[package]] -category = "main" -description = "A small but fast and easy to use stand-alone template engine written in pure python." -name = "jinja2" -optional = false -python-versions = "*" -version = "2.10.1" - -[package.dependencies] -MarkupSafe = ">=0.23" - -[[package]] -category = "main" -description = "An implementation of JSON Schema validation for Python" -name = "jsonschema" -optional = false -python-versions = "*" -version = "3.0.1" - -[package.dependencies] -attrs = ">=17.4.0" -pyrsistent = ">=0.14.0" -setuptools = "*" -six = ">=1.11.0" - -[[package]] -category = "dev" -description = "Jupyter metapackage. Install all the Jupyter components in one go." -name = "jupyter" -optional = false -python-versions = "*" -version = "1.0.0" - -[package.dependencies] -ipykernel = "*" -ipywidgets = "*" -jupyter-console = "*" -nbconvert = "*" -notebook = "*" -qtconsole = "*" - -[[package]] -category = "main" -description = "Jupyter protocol implementation and client libraries" -name = "jupyter-client" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" -version = "5.2.4" - -[package.dependencies] -jupyter-core = "*" -python-dateutil = ">=2.1" -pyzmq = ">=13" -tornado = ">=4.1" -traitlets = "*" - -[[package]] -category = "dev" -description = "Jupyter terminal console" -name = "jupyter-console" -optional = false -python-versions = ">=3.5" -version = "6.0.0" - -[package.dependencies] -ipykernel = "*" -ipython = "*" -jupyter-client = "*" -prompt-toolkit = ">=2.0.0,<2.1.0" -pygments = "*" - -[[package]] -category = "main" -description = "Jupyter core package. A base package on which Jupyter projects rely." -name = "jupyter-core" -optional = false -python-versions = "*" -version = "4.4.0" - -[package.dependencies] -traitlets = "*" - -[[package]] -category = "dev" -description = "Jupyter Sphinx Extensions" -name = "jupyter-sphinx" -optional = false -python-versions = "*" -version = "0.1.4" - -[package.dependencies] -Sphinx = ">=0.6" -ipywidgets = ">=6.0.0" - -[[package]] -category = "dev" -description = "The JupyterLab notebook server extension." -name = "jupyterlab" -optional = false -python-versions = ">=3.5" -version = "0.35.4" - -[package.dependencies] -jupyterlab-server = ">=0.2.0,<0.3.0" -notebook = ">=4.3.1" - -[[package]] -category = "dev" -description = "JupyterLab Server" -name = "jupyterlab-server" -optional = false -python-versions = ">=3.5" -version = "0.2.0" - -[package.dependencies] -jsonschema = ">=2.6.0" -notebook = ">=4.2.0" - -[[package]] -category = "main" -description = "A fast implementation of the Cassowary constraint solver" -name = "kiwisolver" -optional = false -python-versions = "*" -version = "1.0.1" - -[package.dependencies] -setuptools = "*" - -[[package]] -category = "dev" -description = "Markdown and reStructuredText in a single file." -name = "m2r" -optional = false -python-versions = "*" -version = "0.2.1" - -[package.dependencies] -docutils = "*" -mistune = "*" - -[[package]] -category = "main" -description = "Safely add untrusted strings to HTML/XML markup." -name = "markupsafe" -optional = false -python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" -version = "1.1.1" - -[[package]] -category = "main" -description = "Python plotting package" -name = "matplotlib" -optional = false -python-versions = ">=3.5" -version = "3.0.3" - -[package.dependencies] -cycler = ">=0.10" -kiwisolver = ">=1.0.1" -numpy = ">=1.10.0" -pyparsing = ">=2.0.1,<2.0.4 || >2.0.4,<2.1.2 || >2.1.2,<2.1.6 || >2.1.6" -python-dateutil = ">=2.1" - -[[package]] -category = "main" -description = "The fastest markdown parser in pure Python" -name = "mistune" -optional = false -python-versions = "*" -version = "0.8.4" - -[[package]] -category = "dev" -description = "More routines for operating on iterables, beyond itertools" -marker = "python_version > \"2.7\"" -name = "more-itertools" -optional = false -python-versions = ">=3.4" -version = "7.0.0" - -[[package]] -category = "main" -description = "Converting Jupyter Notebooks" -name = "nbconvert" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "5.4.1" - -[package.dependencies] -bleach = "*" -defusedxml = "*" -entrypoints = ">=0.2.2" -jinja2 = "*" -jupyter-core = "*" -mistune = ">=0.8.1" -nbformat = ">=4.4" -pandocfilters = ">=1.4.1" -pygments = "*" -testpath = "*" -traitlets = ">=4.2" - -[[package]] -category = "main" -description = "The Jupyter Notebook format" -name = "nbformat" -optional = false -python-versions = "*" -version = "4.4.0" - -[package.dependencies] -ipython-genutils = "*" -jsonschema = ">=2.4,<2.5.0 || >2.5.0" -jupyter-core = "*" -traitlets = ">=4.1" - -[[package]] -category = "dev" -description = "Jupyter Notebook Tools for Sphinx" -name = "nbsphinx" -optional = false -python-versions = "*" -version = "0.4.2" - -[package.dependencies] -docutils = "*" -jinja2 = "*" -nbconvert = "!=5.4" -nbformat = "*" -sphinx = ">=1.6" -traitlets = "*" - -[[package]] -category = "main" -description = "A web-based notebook environment for interactive computing" -name = "notebook" -optional = false -python-versions = "*" -version = "5.7.8" - -[package.dependencies] -Send2Trash = "*" -ipykernel = "*" -ipython-genutils = "*" -jinja2 = "*" -jupyter-client = ">=5.2.0" -jupyter-core = ">=4.4.0" -nbconvert = "*" -nbformat = "*" -prometheus-client = "*" -pyzmq = ">=17" -terminado = ">=0.8.1" -tornado = ">=4.1,<7" -traitlets = ">=4.2.1" - -[[package]] -category = "main" -description = "NumPy is the fundamental package for array computing with Python." -name = "numpy" -optional = false -python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" -version = "1.16.3" - -[[package]] -category = "dev" -description = "Core utilities for Python packages" -name = "packaging" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "19.0" - -[package.dependencies] -pyparsing = ">=2.0.2" -six = "*" - -[[package]] -category = "main" -description = "Powerful data structures for data analysis, time series, and statistics" -name = "pandas" -optional = false -python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*" -version = "0.24.2" - -[package.dependencies] -numpy = ">=1.12.0" -python-dateutil = ">=2.5.0" -pytz = ">=2011k" - -[[package]] -category = "main" -description = "Utilities for writing pandoc filters in python" -name = "pandocfilters" -optional = false -python-versions = "*" -version = "1.4.2" - -[[package]] -category = "main" -description = "A Python Parser" -name = "parso" -optional = false -python-versions = "*" -version = "0.4.0" - -[[package]] -category = "dev" -description = "Object-oriented filesystem paths" -marker = "python_version < \"3.6\"" -name = "pathlib2" -optional = false -python-versions = "*" -version = "2.3.3" - -[package.dependencies] -six = "*" - -[[package]] -category = "main" -description = "Pexpect allows easy control of interactive console applications." -marker = "python_version >= \"3.3\" and sys_platform != \"win32\" or sys_platform != \"win32\"" -name = "pexpect" -optional = false -python-versions = "*" -version = "4.7.0" - -[package.dependencies] -ptyprocess = ">=0.5" - -[[package]] -category = "main" -description = "Tiny 'shelve'-like database with concurrency support" -name = "pickleshare" -optional = false -python-versions = "*" -version = "0.7.5" - -[[package]] -category = "dev" -description = "Python Imaging Library (Fork)" -name = "pillow" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "6.0.0" - -[[package]] -category = "dev" -description = "plugin and hook calling mechanisms for python" -name = "pluggy" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "0.9.0" - -[[package]] -category = "main" -description = "Python client for the Prometheus monitoring system." -name = "prometheus-client" -optional = false -python-versions = "*" -version = "0.6.0" - -[[package]] -category = "main" -description = "Library for building powerful interactive command lines in Python" -name = "prompt-toolkit" -optional = false -python-versions = "*" -version = "2.0.9" - -[package.dependencies] -six = ">=1.9.0" -wcwidth = "*" - -[[package]] -category = "main" -description = "psycopg2 - Python-PostgreSQL Database Adapter" -name = "psycopg2-binary" -optional = false -python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" -version = "2.8.2" - -[[package]] -category = "main" -description = "Run a subprocess in a pseudo terminal" -marker = "sys_platform != \"win32\" or os_name != \"nt\" or python_version >= \"3.3\" and sys_platform != \"win32\"" -name = "ptyprocess" -optional = false -python-versions = "*" -version = "0.6.0" - -[[package]] -category = "dev" -description = "library with cross-python path, ini-parsing, io, code, log facilities" -name = "py" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "1.8.0" - -[[package]] -category = "main" -description = "Pygments is a syntax highlighting package written in Python." -name = "pygments" -optional = false -python-versions = "*" -version = "2.3.1" - -[[package]] -category = "main" -description = "Python parsing module" -name = "pyparsing" -optional = false -python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" -version = "2.4.0" - -[[package]] -category = "main" -description = "Persistent/Functional/Immutable data structures" -name = "pyrsistent" -optional = false -python-versions = "*" -version = "0.14.11" - -[package.dependencies] -six = "*" - -[[package]] -category = "dev" -description = "pytest: simple powerful testing with Python" -name = "pytest" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "4.4.1" - -[package.dependencies] -atomicwrites = ">=1.0" -attrs = ">=17.4.0" -colorama = "*" -pluggy = ">=0.9" -py = ">=1.5.0" -setuptools = "*" -six = ">=1.10.0" - -[package.dependencies.more-itertools] -python = ">2.7" -version = ">=4.0.0" - -[package.dependencies.pathlib2] -python = "<3.6" -version = ">=2.2.0" - -[[package]] -category = "dev" -description = "Pytest plugin for measuring coverage." -name = "pytest-cov" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "2.6.1" - -[package.dependencies] -coverage = ">=4.4" -pytest = ">=3.6" - -[[package]] -category = "dev" -description = "PyTest Helpers Namespace" -name = "pytest-helpers-namespace" -optional = false -python-versions = "*" -version = "2019.1.8" - -[package.dependencies] -pytest = ">=2.9.1" - -[[package]] -category = "dev" -description = "Thin-wrapper around the mock package for easier use with py.test" -name = "pytest-mock" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "1.10.4" - -[package.dependencies] -pytest = ">=2.7" - -[[package]] -category = "main" -description = "Extensions to the standard Python datetime module" -name = "python-dateutil" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" -version = "2.8.0" - -[package.dependencies] -six = ">=1.5" - -[[package]] -category = "main" -description = "World timezone definitions, modern and historical" -name = "pytz" -optional = false -python-versions = "*" -version = "2019.1" - -[[package]] -category = "main" -description = "Python bindings for the winpty library" -marker = "os_name == \"nt\"" -name = "pywinpty" -optional = false -python-versions = "*" -version = "0.5.5" - -[[package]] -category = "main" -description = "Python bindings for 0MQ" -name = "pyzmq" -optional = false -python-versions = ">=2.7,!=3.0*,!=3.1*,!=3.2*" -version = "18.0.1" - -[[package]] -category = "dev" -description = "Jupyter Qt console" -name = "qtconsole" -optional = false -python-versions = "*" -version = "4.4.3" - -[package.dependencies] -ipykernel = ">=4.1" -ipython-genutils = "*" -jupyter-client = ">=4.1" -jupyter-core = "*" -pygments = "*" -traitlets = "*" - -[[package]] -category = "dev" -description = "Python HTTP for Humans." -name = "requests" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "2.21.0" - -[package.dependencies] -certifi = ">=2017.4.17" -chardet = ">=3.0.2,<3.1.0" -idna = ">=2.5,<2.9" -urllib3 = ">=1.21.1,<1.25" - -[[package]] -category = "main" -description = "Job scheduling for humans." -name = "schedule" -optional = false -python-versions = "*" -version = "0.6.0" - -[[package]] -category = "main" -description = "A set of python modules for machine learning and data mining" -name = "scikit-learn" -optional = false -python-versions = "*" -version = "0.20.3" - -[package.dependencies] -numpy = ">=1.8.2" -scipy = ">=0.13.3" - -[[package]] -category = "main" -description = "SciPy: Scientific Library for Python" -name = "scipy" -optional = false -python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" -version = "1.2.1" - -[package.dependencies] -numpy = ">=1.8.2" - -[[package]] -category = "main" -description = "Send file to trash natively under Mac OS X, Windows and Linux." -name = "send2trash" -optional = false -python-versions = "*" -version = "1.5.0" - -[[package]] -category = "main" -description = "Python 2 and 3 compatibility utilities" -name = "six" -optional = false -python-versions = ">=2.6, !=3.0.*, !=3.1.*" -version = "1.12.0" - -[[package]] -category = "dev" -description = "This package provides 16 stemmer algorithms (15 + Poerter English stemmer) generated from Snowball algorithms." -name = "snowballstemmer" -optional = false -python-versions = "*" -version = "1.2.1" - -[[package]] -category = "dev" -description = "A modern CSS selector implementation for Beautiful Soup." -name = "soupsieve" -optional = false -python-versions = "*" -version = "1.9.1" - -[[package]] -category = "dev" -description = "Python documentation generator" -name = "sphinx" -optional = false -python-versions = ">=3.5" -version = "2.0.1" - -[package.dependencies] -Jinja2 = ">=2.3" -Pygments = ">=2.0" -alabaster = ">=0.7,<0.8" -babel = ">=1.3,<2.0 || >2.0" -colorama = ">=0.3.5" -docutils = ">=0.12" -imagesize = "*" -packaging = "*" -requests = ">=2.5.0" -setuptools = "*" -snowballstemmer = ">=1.1" -sphinxcontrib-applehelp = "*" -sphinxcontrib-devhelp = "*" -sphinxcontrib-htmlhelp = "*" -sphinxcontrib-jsmath = "*" -sphinxcontrib-qthelp = "*" -sphinxcontrib-serializinghtml = "*" - -[[package]] -category = "dev" -description = "Read the Docs theme for Sphinx" -name = "sphinx-rtd-theme" -optional = false -python-versions = "*" -version = "0.4.3" - -[package.dependencies] -sphinx = "*" - -[[package]] -category = "dev" -description = "" -name = "sphinxcontrib-applehelp" -optional = false -python-versions = "*" -version = "1.0.1" - -[[package]] -category = "dev" -description = "" -name = "sphinxcontrib-devhelp" -optional = false -python-versions = "*" -version = "1.0.1" - -[[package]] -category = "dev" -description = "" -name = "sphinxcontrib-htmlhelp" -optional = false -python-versions = "*" -version = "1.0.2" - -[[package]] -category = "dev" -description = "A sphinx extension which renders display math in HTML via JavaScript" -name = "sphinxcontrib-jsmath" -optional = false -python-versions = ">=3.5" -version = "1.0.1" - -[[package]] -category = "dev" -description = "" -name = "sphinxcontrib-qthelp" -optional = false -python-versions = "*" -version = "1.0.2" - -[[package]] -category = "dev" -description = "" -name = "sphinxcontrib-serializinghtml" -optional = false -python-versions = "*" -version = "1.1.3" - -[[package]] -category = "main" -description = "Database Abstraction Library" -name = "sqlalchemy" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "1.3.3" - -[[package]] -category = "main" -description = "Terminals served to xterm.js using Tornado websockets" -name = "terminado" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "0.8.2" - -[package.dependencies] -ptyprocess = "*" -pywinpty = ">=0.5" -tornado = ">=4" - -[[package]] -category = "main" -description = "Test utilities for code working with files and commands" -name = "testpath" -optional = false -python-versions = "*" -version = "0.4.2" - -[[package]] -category = "main" -description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed." -name = "tornado" -optional = false -python-versions = ">= 3.5" -version = "6.0.2" - -[[package]] -category = "main" -description = "Traitlets Python config system" -name = "traitlets" -optional = false -python-versions = "*" -version = "4.3.2" - -[package.dependencies] -decorator = "*" -ipython-genutils = "*" -six = "*" - -[[package]] -category = "dev" -description = "HTTP library with thread-safe connection pooling, file post, and more." -name = "urllib3" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, <4" -version = "1.24.2" - -[[package]] -category = "main" -description = "Measures number of Terminal column cells of wide-character codes" -name = "wcwidth" -optional = false -python-versions = "*" -version = "0.1.7" - -[[package]] -category = "main" -description = "Character encoding aliases for legacy web content" -name = "webencodings" -optional = false -python-versions = "*" -version = "0.5.1" - -[[package]] -category = "main" -description = "The comprehensive WSGI web application library." -name = "werkzeug" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "0.15.2" - -[[package]] -category = "main" -description = "IPython HTML widgets for Jupyter" -name = "widgetsnbextension" -optional = false -python-versions = "*" -version = "3.4.2" - -[package.dependencies] -notebook = ">=4.4.1" - -[[package]] -category = "main" -description = "Enable Unicode input and display when running Python from Windows console." -marker = "sys_platform == \"win32\" and python_version < \"3.6\" or sys_platform == \"win32\" and python_version < \"3.6\" and python_version >= \"3.3\"" -name = "win-unicode-console" -optional = false -python-versions = "*" -version = "0.5" - -[[package]] -category = "dev" -description = "A little word cloud generator" -name = "wordcloud" -optional = false -python-versions = "*" -version = "1.5.0" - -[package.dependencies] -numpy = ">=1.6.1" -pillow = "*" - -[extras] -tests = [] - -[metadata] -content-hash = "b1703869e928b141da2b719199bc927ac7ce4f04fe548888664ecd125f7c1171" -python-versions = "^3.5" - -[metadata.hashes] -alabaster = ["446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359", "a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02"] -appnope = ["5b26757dc6f79a3b7dc9fab95359328d5747fcb2409d331ea66d0272b90ab2a0", "8b995ffe925347a2138d7ac0fe77155e4311a0ea6d6da4f5128fe4b3cbe5ed71"] -atomicwrites = ["03472c30eb2c5d1ba9227e4c2ca66ab8287fbfbbda3888aa93dc2e28fc6811b4", "75a9445bac02d8d058d5e1fe689654ba5a6556a1dfd8ce6ec55a0ed79866cfa6"] -attrs = ["69c0dbf2ed392de1cb5ec704444b08a5ef81680a61cb899dc08127123af36a79", "f0b870f674851ecbfbbbd364d6b5cbdff9dcedbc7f3f5e18a6891057f21fe399"] -babel = ["6778d85147d5d85345c14a26aada5e478ab04e39b078b0745ee6870c2b5cf669", "8cba50f48c529ca3fa18cf81fa9403be176d374ac4d60738b839122dfaaa3d23"] -backcall = ["38ecd85be2c1e78f77fd91700c76e14667dc21e2713b63876c0eb901196e01e4", "bbbf4b1e5cd2bdb08f915895b51081c041bac22394fdfcfdfbe9f14b77c08bf2"] -beautifulsoup4 = ["034740f6cb549b4e932ae1ab975581e6103ac8f942200a0e9759065984391858", "945065979fb8529dd2f37dbb58f00b661bdbcbebf954f93b32fdf5263ef35348", "ba6d5c59906a85ac23dadfe5c88deaf3e179ef565f4898671253e50a78680718"] -bleach = ["213336e49e102af26d9cde77dd2d0397afabc5a6bf2fed985dc35b5d1e285a16", "3fdf7f77adcf649c9911387df51254b813185e32b2c6619f690b593a617e19fa"] -bs4 = ["36ecea1fd7cc5c0c6e4a1ff075df26d50da647b75376626cc186e2212886dd3a"] -cachetools = ["219b7dc6024195b6f2bc3d3f884d1fef458745cd323b04165378622dcc823852", "9efcc9fab3b49ab833475702b55edd5ae07af1af7a4c627678980b45e459c460"] -certifi = ["59b7658e26ca9c7339e00f8f4636cdfe59d34fa37b9b04f6f9e9926b3cece1a5", "b26104d6835d1f5e49452a26eb2ff87fe7090b89dfcaee5ea2212697e1e1d7ae"] -chardet = ["84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", "fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"] -click = ["2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13", "5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7"] -colorama = ["05eed71e2e327246ad6b38c540c4a3117230b19679b875190486ddd2d721422d", "f8ac84de7840f5b9c4e3347b3c1eaa50f7e49c2b07596221daec5edaabbd7c48"] -coverage = ["0c5fe441b9cfdab64719f24e9684502a59432df7570521563d7b1aff27ac755f", "2b412abc4c7d6e019ce7c27cbc229783035eef6d5401695dccba80f481be4eb3", "3684fabf6b87a369017756b551cef29e505cb155ddb892a7a29277b978da88b9", "39e088da9b284f1bd17c750ac672103779f7954ce6125fd4382134ac8d152d74", "3c205bc11cc4fcc57b761c2da73b9b72a59f8d5ca89979afb0c1c6f9e53c7390", "42692db854d13c6c5e9541b6ffe0fe921fe16c9c446358d642ccae1462582d3b", "465ce53a8c0f3a7950dfb836438442f833cf6663d407f37d8c52fe7b6e56d7e8", "48020e343fc40f72a442c8a1334284620f81295256a6b6ca6d8aa1350c763bbe", "4ec30ade438d1711562f3786bea33a9da6107414aed60a5daa974d50a8c2c351", "5296fc86ab612ec12394565c500b412a43b328b3907c0d14358950d06fd83baf", "5f61bed2f7d9b6a9ab935150a6b23d7f84b8055524e7be7715b6513f3328138e", "6899797ac384b239ce1926f3cb86ffc19996f6fa3a1efbb23cb49e0c12d8c18c", "68a43a9f9f83693ce0414d17e019daee7ab3f7113a70c79a3dd4c2f704e4d741", "6b8033d47fe22506856fe450470ccb1d8ba1ffb8463494a15cfc96392a288c09", "7ad7536066b28863e5835e8cfeaa794b7fe352d99a8cded9f43d1161be8e9fbd", "7bacb89ccf4bedb30b277e96e4cc68cd1369ca6841bde7b005191b54d3dd1034", "839dc7c36501254e14331bcb98b27002aa415e4af7ea039d9009409b9d2d5420", "8e679d1bde5e2de4a909efb071f14b472a678b788904440779d2c449c0355b27", "8f9a95b66969cdea53ec992ecea5406c5bd99c9221f539bca1e8406b200ae98c", "932c03d2d565f75961ba1d3cec41ddde00e162c5b46d03f7423edcb807734eab", "93f965415cc51604f571e491f280cff0f5be35895b4eb5e55b47ae90c02a497b", "988529edadc49039d205e0aa6ce049c5ccda4acb2d6c3c5c550c17e8c02c05ba", "998d7e73548fe395eeb294495a04d38942edb66d1fa61eb70418871bc621227e", "9de60893fb447d1e797f6bf08fdf0dbcda0c1e34c1b06c92bd3a363c0ea8c609", "9e80d45d0c7fcee54e22771db7f1b0b126fb4a6c0a2e5afa72f66827207ff2f2", "a545a3dfe5082dc8e8c3eb7f8a2cf4f2870902ff1860bd99b6198cfd1f9d1f49", "a5d8f29e5ec661143621a8f4de51adfb300d7a476224156a39a392254f70687b", "a9abc8c480e103dc05d9b332c6cc9fb1586330356fc14f1aa9c0ca5745097d19", "aca06bfba4759bbdb09bf52ebb15ae20268ee1f6747417837926fae990ebc41d", "bb23b7a6fd666e551a3094ab896a57809e010059540ad20acbeec03a154224ce", "bfd1d0ae7e292105f29d7deaa9d8f2916ed8553ab9d5f39ec65bcf5deadff3f9", "c22ab9f96cbaff05c6a84e20ec856383d27eae09e511d3e6ac4479489195861d", "c62ca0a38958f541a73cf86acdab020c2091631c137bd359c4f5bddde7b75fd4", "c709d8bda72cf4cd348ccec2a4881f2c5848fd72903c185f363d361b2737f773", "c968a6aa7e0b56ecbd28531ddf439c2ec103610d3e2bf3b75b813304f8cb7723", "ca58eba39c68010d7e87a823f22a081b5290e3e3c64714aac3c91481d8b34d22", "df785d8cb80539d0b55fd47183264b7002077859028dfe3070cf6359bf8b2d9c", "f406628ca51e0ae90ae76ea8398677a921b36f0bd71aab2099dfed08abd0322f", "f46087bbd95ebae244a0eda01a618aff11ec7a069b15a3ef8f6b520db523dcf1", "f8019c5279eb32360ca03e9fac40a12667715546eed5c5eb59eb381f2f501260", "fc5f4d209733750afd2714e9109816a29500718b32dd9a5db01c0cb3a019b96a"] -coveralls = ["baa26648430d5c2225ab12d7e2067f75597a4b967034bba7e3d5ab7501d207a1", "ff9b7823b15070f26f654837bb02a201d006baaf2083e0514ffd3b34a3ffed81"] -cycler = ["1d8a5ae1ff6c5cf9b93e8811e581232ad8920aeec647c37316ceac982b08cb2d", "cd7b2d1018258d7247a71425e9f26463dfb444d411c39569972f4ce586b0c9d8"] -decorator = ["86156361c50488b84a3f148056ea716ca587df2f0de1d34750d35c21312725de", "f069f3a01830ca754ba5258fde2278454a0b5b79e0d7f5c13b3b97e57d4acff6"] -defusedxml = ["6687150770438374ab581bb7a1b327a847dd9c5749e396102de3fad4e8a3ef93", "f684034d135af4c6cbb949b8a4d2ed61634515257a67299e5f940fbaa34377f5"] -docopt = ["49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491"] -docutils = ["02aec4bd92ab067f6ff27a38a38a41173bf01bed8f89157768c1573f53e474a6", "51e64ef2ebfb29cae1faa133b3710143496eca21c530f3f71424d77687764274", "7a4bd47eaf6596e1295ecb11361139febe29b084a87bf005bf899f9a42edc3c6"] -entrypoints = ["589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19", "c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451"] -flask = ["2271c0070dbcb5275fad4a82e29f23ab92682dc45f9dfbc22c02ba9b9322ce48", "a080b744b7e345ccfcbc77954861cb05b3c63786e93f2b3875e0913d44b43f05"] -html5lib = ["20b159aa3badc9d5ee8f5c647e5efd02ed2a66ab8d354930bd9ff139fc1dc0a3", "66cb0dcfdbbc4f9c3ba1a63fdb511ffdbd4f513b2b6d81b80cd26ce6b3fb3736"] -hypothesis = ["4a0ef713f71c49379f1bfb92784063b5cd32899924506b70a86a95625a7e3891", "c691d1479e2b45b028696b63cebde22dd8607dca53b948407e345391782e32a5", "f3ca26da5535fc4467793080e35f5be670d28cb618a55a419a6bee3ff856134e"] -idna = ["c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407", "ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c"] -imagesize = ["3f349de3eb99145973fefb7dbe38554414e5c30abd0c8e4b970a7c9d09f3a1d8", "f3832918bc3c66617f92e35f5d70729187676313caa60c187eb0f28b8fe5e3b5"] -ipyevents = ["62360311fb7dbd2995031b2e8da46ad49e8a265f8f8eaf62e9fe051c903c8779", "8f00a4183f0b2bd43de9cc48ae32c84674ee43629ff1afec6b3869ecf5698740"] -ipykernel = ["0aeb7ec277ac42cc2b59ae3d08b10909b2ec161dc6908096210527162b53675d", "0fc0bf97920d454102168ec2008620066878848fcfca06c22b669696212e292f"] -ipython = ["b038baa489c38f6d853a3cfc4c635b0cda66f2864d136fe8f40c1a6e334e2a6b", "f5102c1cd67e399ec8ea66bcebe6e3968ea25a8977e53f012963e5affeb1fe38"] -ipython-genutils = ["72dd37233799e619666c9f639a9da83c34013a73e8bbc79a7a6348d93c61fab8", "eb2e116e75ecef9d4d228fdc66af54269afa26ab4463042e33785b887c628ba8"] -ipywidgets = ["0f2b5cde9f272cb49d52f3f0889fdd1a7ae1e74f37b48dac35a83152780d2b7b", "a3e224f430163f767047ab9a042fc55adbcab0c24bbe6cf9f306c4f89fdf0ba3"] -itsdangerous = ["321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19", "b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749"] -jedi = ["2bb0603e3506f708e792c7f4ad8fc2a7a9d9c2d292a358fbbd58da531695595b", "2c6bcd9545c7d6440951b12b44d373479bf18123a401a52025cf98563fbd826c"] -jinja2 = ["065c4f02ebe7f7cf559e49ee5a95fb800a9e4528727aec6f24402a5374c65013", "14dd6caf1527abb21f08f86c784eac40853ba93edb79552aa1e4b8aef1b61c7b"] -jsonschema = ["0c0a81564f181de3212efa2d17de1910f8732fa1b71c42266d983cd74304e20d", "a5f6559964a3851f59040d3b961de5e68e70971afb88ba519d27e6a039efff1a"] -jupyter = ["3e1f86076bbb7c8c207829390305a2b1fe836d471ed54be66a3b8c41e7f46cc7", "5b290f93b98ffbc21c0c7e749f054b3267782166d72fa5e3ed1ed4eaf34a2b78", "d9dc4b3318f310e34c82951ea5d6683f67bed7def4b259fafbfe4f1beb1d8e5f"] -jupyter-client = ["b5f9cb06105c1d2d30719db5ffb3ea67da60919fb68deaefa583deccd8813551", "c44411eb1463ed77548bc2d5ec0d744c9b81c4a542d9637c7a52824e2121b987"] -jupyter-console = ["308ce876354924fb6c540b41d5d6d08acfc946984bf0c97777c1ddcb42e0b2f5", "cc80a97a5c389cbd30252ffb5ce7cefd4b66bde98219edd16bf5cb6f84bb3568"] -jupyter-core = ["927d713ffa616ea11972534411544589976b2493fc7e09ad946e010aa7eb9970", "ba70754aa680300306c699790128f6fbd8c306ee5927976cbe48adacf240c0b7"] -jupyter-sphinx = ["03f22230f71de202c1a5fe45ab973877a42260e4a2cd901529dae0bdef9dc908", "8a83dcd06fde45ea715e5361c661ca0569d51a49b45ec0d6740efcab003e6059"] -jupyterlab = ["c48f092526f6d5f12b039118bd92401ab605f49d17050ac71c0d809e86b15036", "deba0b2803640fcad72c61366bff11d5945173015961586d5e3b2f629ffeb455"] -jupyterlab-server = ["65eaf85b27a37380329fbdd8ebd095a0bd65fe9261d73ef6a1abee1dbaeaac1f", "72d916a73957a880cdb885def6d8664a6d1b2760ef5dca5ad665aa1e8d1bb783"] -kiwisolver = ["0ee4ed8b3ae8f5f712b0aa9ebd2858b5b232f1b9a96b0943dceb34df2a223bc3", "0f7f532f3c94e99545a29f4c3f05637f4d2713e7fd91b4dd8abfc18340b86cd5", "1a078f5dd7e99317098f0e0d490257fd0349d79363e8c923d5bb76428f318421", "1aa0b55a0eb1bd3fa82e704f44fb8f16e26702af1a073cc5030eea399e617b56", "2874060b91e131ceeff00574b7c2140749c9355817a4ed498e82a4ffa308ecbc", "379d97783ba8d2934d52221c833407f20ca287b36d949b4bba6c75274bcf6363", "3b791ddf2aefc56382aadc26ea5b352e86a2921e4e85c31c1f770f527eb06ce4", "4329008a167fac233e398e8a600d1b91539dc33c5a3eadee84c0d4b04d4494fa", "45813e0873bbb679334a161b28cb9606d9665e70561fd6caa8863e279b5e464b", "53a5b27e6b5717bdc0125338a822605084054c80f382051fb945d2c0e6899a20", "574f24b9805cb1c72d02b9f7749aa0cc0b81aa82571be5201aa1453190390ae5", "66f82819ff47fa67a11540da96966fb9245504b7f496034f534b81cacf333861", "79e5fe3ccd5144ae80777e12973027bd2f4f5e3ae8eb286cabe787bed9780138", "83410258eb886f3456714eea4d4304db3a1fc8624623fc3f38a487ab36c0f653", "8b6a7b596ce1d2a6d93c3562f1178ebd3b7bb445b3b0dd33b09f9255e312a965", "9576cb63897fbfa69df60f994082c3f4b8e6adb49cccb60efb2a80a208e6f996", "95a25d9f3449046ecbe9065be8f8380c03c56081bc5d41fe0fb964aaa30b2195", "a424f048bebc4476620e77f3e4d1f282920cef9bc376ba16d0b8fe97eec87cde", "aaec1cfd94f4f3e9a25e144d5b0ed1eb8a9596ec36d7318a504d813412563a85", "acb673eecbae089ea3be3dcf75bfe45fc8d4dcdc951e27d8691887963cf421c7", "b15bc8d2c2848a4a7c04f76c9b3dc3561e95d4dabc6b4f24bfabe5fd81a0b14f", "b1c240d565e977d80c0083404c01e4d59c5772c977fae2c483f100567f50847b", "c595693de998461bcd49b8d20568c8870b3209b8ea323b2a7b0ea86d85864694", "ce3be5d520b4d2c3e5eeb4cd2ef62b9b9ab8ac6b6fedbaa0e39cdb6f50644278", "e0f910f84b35c36a3513b96d816e6442ae138862257ae18a0019d2fc67b041dc", "ea36e19ac0a483eea239320aef0bd40702404ff8c7e42179a2d9d36c5afcb55c", "efabbcd4f406b532206b8801058c8bab9e79645b9880329253ae3322b7b02cd5", "f923406e6b32c86309261b8195e24e18b6a8801df0cfc7814ac44017bfcb3939"] -m2r = ["bf90bad66cda1164b17e5ba4a037806d2443f2a4d5ddc9f6a5554a0322aaed99"] -markupsafe = ["00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473", "09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161", "09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235", "1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5", "24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff", "29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b", "43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1", "46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e", "500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183", "535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66", "62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1", "6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1", "717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e", "79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b", "7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905", "88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735", "8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d", "98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e", "9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d", "9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c", "ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21", "b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2", "b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5", "b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b", "ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6", "c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f", "cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f", "e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7"] -matplotlib = ["1ae6549976b6ceb6ee426272a28c0fc9715b3e3669694d560c8f661c5b39e2c5", "4d4250bf508dd07cca3b43888097f873cadb66eec6ac63dbbfb798798ec07af2", "53af2e01d7f1700ed2b64a9091bc865360c9c4032f625451c4589a826854c787", "63e498067d32d627111cd1162cae1621f1221f9d4c6a9745dd7233f29de581b6", "7169a34971e398dd58e87e173f97366fd88a3fa80852704530433eb224a8ca57", "91c54d6bb9eeaaff965656c5ea6cbdcbf780bad8462ac99b30b451548194746f", "aeef177647bb3fccfe09065481989d7dfc5ac59e9367d6a00a3481062cf651e4", "cf8ae10559a78aee0409ede1e9d4fda03895433eeafe609dd9ed67e45f552db0", "d51d0889d1c4d51c51a9822265c0494ea3e70a52bdd88358e0863daca46fa23a", "de5ccd3500247f85fe4f9fad90f80a8bd397e4f110a4c33fabf95f07403e8372", "e1d33589e32f482d0a7d1957bf473d43341115d40d33f578dad44432e47df7b7", "e8d1939262aa6b36d0c51f50a50a43a04b9618d20db31e6c0192b1463067aeef", "e918d51b1fda82a65fdf52d2f3914b2246481cc2a9cd10e223e6be6078916ff3"] -mistune = ["59a3429db53c50b5c6bcc8a07f8848cb00d7dc8bdb431a4ab41920d201d4756e", "88a1051873018da288eee8538d476dffe1262495144b33ecb586c4ab266bb8d4"] -more-itertools = ["2112d2ca570bb7c3e53ea1a35cd5df42bb0fd10c45f0fb97178679c3c03d64c7", "c3e4748ba1aad8dba30a4886b0b1a2004f9a863837b8654e7059eebf727afa5a"] -nbconvert = ["302554a2e219bc0fc84f3edd3e79953f3767b46ab67626fdec16e38ba3f7efe4", "5de8fb2284422272a1d45abc77c07b888127550a6d602ce619592a2b08a474ff"] -nbformat = ["b9a0dbdbd45bb034f4f8893cafd6f652ea08c8c1674ba83f2dc55d3955743b0b", "f7494ef0df60766b7cabe0a3651556345a963b74dbc16bc7c18479041170d402"] -nbsphinx = ["b794219e465b3aab500b800884ff40fd152bb19d8b6f87580de1f3a07170aef8", "c39176496b17e34c7a53b13350468ea7d5e076997efbeedd52352a340ade4d3b"] -notebook = ["573e0ae650c5d76b18b6e564ba6d21bf321d00847de1d215b418acb64f056eb8", "f64fa6624d2323fbef6210a621817d6505a45d0d4a9367f1843b20a38a4666ee"] -numpy = ["0e2eed77804b2a6a88741f8fcac02c5499bba3953ec9c71e8b217fad4912c56c", "1c666f04553ef70fda54adf097dbae7080645435fc273e2397f26bbf1d127bbb", "1f46532afa7b2903bfb1b79becca2954c0a04389d19e03dc73f06b039048ac40", "315fa1b1dfc16ae0f03f8fd1c55f23fd15368710f641d570236f3d78af55e340", "3d5fcea4f5ed40c3280791d54da3ad2ecf896f4c87c877b113576b8280c59441", "48241759b99d60aba63b0e590332c600fc4b46ad597c9b0a53f350b871ef0634", "4b4f2924b36d857cf302aec369caac61e43500c17eeef0d7baacad1084c0ee84", "54fe3b7ed9e7eb928bbc4318f954d133851865f062fa4bbb02ef8940bc67b5d2", "5a8f021c70e6206c317974c93eaaf9bc2b56295b6b1cacccf88846e44a1f33fc", "754a6be26d938e6ca91942804eb209307b73f806a1721176278a6038869a1686", "771147e654e8b95eea1293174a94f34e2e77d5729ad44aefb62fbf8a79747a15", "78a6f89da87eeb48014ec652a65c4ffde370c036d780a995edaeb121d3625621", "7fde5c2a3a682a9e101e61d97696687ebdba47637611378b4127fe7e47fdf2bf", "80d99399c97f646e873dd8ce87c38cfdbb668956bbc39bc1e6cac4b515bba2a0", "88a72c1e45a0ae24d1f249a529d9f71fe82e6fa6a3fd61414b829396ec585900", "a4f4460877a16ac73302a9c077ca545498d9fe64e6a81398d8e1a67e4695e3df", "a61255a765b3ac73ee4b110b28fccfbf758c985677f526c2b4b39c48cc4b509d", "ab4896a8c910b9a04c0142871d8800c76c8a2e5ff44763513e1dd9d9631ce897", "abbd6b1c2ef6199f4b7ca9f818eb6b31f17b73a6110aadc4e4298c3f00fab24e", "b16d88da290334e33ea992c56492326ea3b06233a00a1855414360b77ca72f26", "b78a1defedb0e8f6ae1eb55fa6ac74ab42acc4569c3a2eacc2a407ee5d42ebcb", "cfef82c43b8b29ca436560d51b2251d5117818a8d1fb74a8384a83c096745dad", "d160e57731fcdec2beda807ebcabf39823c47e9409485b5a3a1db3a8c6ce763e"] -packaging = ["0c98a5d0be38ed775798ece1b9727178c4469d9c3b4ada66e8e6b7849f8732af", "9e1cbf8c12b1f1ce0bb5344b8d7ecf66a6f8a6e91bcb0c84593ed6d3ab5c4ab3"] -pandas = ["071e42b89b57baa17031af8c6b6bbd2e9a5c68c595bc6bf9adabd7a9ed125d3b", "17450e25ae69e2e6b303817bdf26b2cd57f69595d8550a77c308be0cd0fd58fa", "17916d818592c9ec891cbef2e90f98cc85e0f1e89ed0924c9b5220dc3209c846", "2538f099ab0e9f9c9d09bbcd94b47fd889bad06dc7ae96b1ed583f1dc1a7a822", "366f30710172cb45a6b4f43b66c220653b1ea50303fbbd94e50571637ffb9167", "42e5ad741a0d09232efbc7fc648226ed93306551772fc8aecc6dce9f0e676794", "4e718e7f395ba5bfe8b6f6aaf2ff1c65a09bb77a36af6394621434e7cc813204", "4f919f409c433577a501e023943e582c57355d50a724c589e78bc1d551a535a2", "4fe0d7e6438212e839fc5010c78b822664f1a824c0d263fd858f44131d9166e2", "5149a6db3e74f23dc3f5a216c2c9ae2e12920aa2d4a5b77e44e5b804a5f93248", "627594338d6dd995cfc0bacd8e654cd9e1252d2a7c959449228df6740d737eb8", "83c702615052f2a0a7fb1dd289726e29ec87a27272d775cb77affe749cca28f8", "8c872f7fdf3018b7891e1e3e86c55b190e6c5cee70cab771e8f246c855001296", "90f116086063934afd51e61a802a943826d2aac572b2f7d55caaac51c13db5b5", "a3352bacac12e1fc646213b998bce586f965c9d431773d9e91db27c7c48a1f7d", "bcdd06007cca02d51350f96debe51331dec429ac8f93930a43eb8fb5639e3eb5", "c1bd07ebc15285535f61ddd8c0c75d0d6293e80e1ee6d9a8d73f3f36954342d0", "c9a4b7c55115eb278c19aa14b34fcf5920c8fe7797a09b7b053ddd6195ea89b3", "cc8fc0c7a8d5951dc738f1c1447f71c43734244453616f32b8aa0ef6013a5dfb", "d7b460bc316064540ce0c41c1438c416a40746fd8a4fb2999668bf18f3c4acf1"] -pandocfilters = ["b3dd70e169bb5449e6bc6ff96aea89c5eea8c5f6ab5e207fc2f521a2cf4a0da9"] -parso = ["17cc2d7a945eb42c3569d4564cdf49bde221bc2b552af3eca9c1aad517dcdd33", "2e9574cb12e7112a87253e14e2c380ce312060269d04bd018478a3c92ea9a376"] -pathlib2 = ["25199318e8cc3c25dcb45cbe084cc061051336d5a9ea2a12448d3d8cb748f742", "5887121d7f7df3603bca2f710e7219f3eca0eb69e0b7cc6e0a022e155ac931a7"] -pexpect = ["2094eefdfcf37a1fdbfb9aa090862c1a4878e5c7e0e7e7088bdb511c558e5cd1", "9e2c1fd0e6ee3a49b28f95d4b33bc389c89b20af6a1255906e90ff1262ce62eb"] -pickleshare = ["87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca", "9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56"] -pillow = ["0683e80d81e840d401b687ebc00a02bbb23d0793c34d0852a5af64cfa1589540", "09c4e81c3277199898e8dc2d85d94febad87c41251ecbd447ba7d64d94765bd8", "0ee74a23022af9baf997e3016b4e090e4ff08688d37a6f49010338ab46cfe101", "10860baedfe5da7c43cd17835b091494dcc59dda5ad176a011713fe398ea6ac2", "15c056bfa284c30a7f265a41ac4cbbc93bdbfc0dfe0613b9cb8a8581b51a9e55", "1a4e06ba4f74494ea0c58c24de2bb752818e9d504474ec95b0aa94f6b0a7e479", "1c3c707c76be43c9e99cb7e3d5f1bee1c8e5be8b8a2a5eeee665efbf8ddde91a", "1fd0b290203e3b0882d9605d807b03c0f47e3440f97824586c173eca0aadd99d", "24114e4a6e1870c5a24b1da8f60d0ba77a0b4027907860188ea82bd3508c80eb", "258d886a49b6b058cd7abb0ab4b2b85ce78669a857398e83e8b8e28b317b5abb", "2734c55f7d054b0ad889c971136cbb0a5b35a921e27beaa44fdc2436af529c6e", "2ac36ec56727a95bd5a04dfca6abce1db8042c31ee73b65796a42f31fd52d009", "2bc1002b573d107c0b172a5da0f34b4900b2ddc6c3296b82d601e966d5ac1959", "33c79b6dd6bc7f65079ab9ca5bebffb5f5d1141c689c9c6a7855776d1b09b7e8", "367385fc797b2c31564c427430c7a8630db1a00bd040555dfc1d5c52e39fcd72", "3c1884ff078fb8bf5f63d7d86921838b82ed4a7d0c027add773c2f38b3168754", "44e5240e8f4f8861d748f2a58b3f04daadab5e22bfec896bf5434745f788f33f", "46aa988e15f3ea72dddd81afe3839437b755fffddb5e173886f11460be909dce", "492e1e4df823b57f9334f591c78a1e0e65a361e92594534e0568eeeeea56bbba", "50fb9e25d25cfcb50b2e6842c4e104e4f0b424be4624e1724532bf005c67589a", "5ceadd60dbd1e56ab7faffbfee1df5ecb83c3f0420e47f652cd5306d70eb0296", "74d90d499c9c736d52dd6d9b7221af5665b9c04f1767e35f5dd8694324bd4601", "7eeac51fc37e6b19631a4b8e38b8261a074efcf7cc27fc16a6bee4697af7aaa5", "809c0a2ce9032cbcd7b5313f71af4bdc5c8c771cb86eb7559afd954cab82ebb5", "85d1ef2cdafd5507c4221d201aaf62fc9276f8b0f71bd3933363e62a33abc734", "8c3889c7681af77ecfa4431cd42a2885d093ecb811e81fbe5e203abc07e0995b", "9218d81b9fca98d2c47d35d688a0cea0c42fd473159dfd5612dcb0483c63e40b", "9319215530e236822169cbe92426cdc18d16b88c943fdf365a6309a89876e335", "96ec275c83bf839972d6a7dd7d685fdfb6a3233c3c382ecff839d04e7d53955d", "9aa4f3827992288edd37c9df345783a69ef58bd20cc02e64b36e44bcd157bbf1", "9d80f44137a70b6f84c750d11019a3419f409c944526a95219bea0ac31f4dd91", "b7ebd36128a2fe93991293f997e44be9286503c7530ace6a55b938b20be288d8", "c30857e1fbf7d4a4b79d7d376eefaf293ea4307b8293d00a62e6f517f51bfe9b", "c4c78e2c71c257c136cdd43869fd3d5e34fc2162dc22e4a5406b0ebe86958239", "c5472ea3945e8f9eb0659f37fc1f592fd06f4f725f0f03774a8999ad8c130334", "c6a842537f887be1fe115d8abb5daa9bc8cc124e455ff995830cc785624a97af", "cf0a2e040fdf5a6d95f4c286c6ef1df6b36c218b528c8a9158ec2452a804b9b8", "cfd28aad6fc61f7a5d4ee556a997dc6e5555d9381d1390c00ecaf984d57e4232", "d0fd1ec2e7c3e0aeaae999efe83f5d0f42c1160a1f8be5120d40857d20baa452", "dca5660e25932771460d4688ccbb515677caaf8595f3f3240ec16c117deff89a", "de7aedc85918c2f887886442e50f52c1b93545606317956d65f342bd81cb4fc3", "e6c0bbf8e277b74196e3140c35f9a1ae3eafd818f7f2d3a15819c49135d6c062"] -pluggy = ["19ecf9ce9db2fce065a7a0586e07cfb4ac8614fe96edf628a264b1c70116cf8f", "84d306a647cc805219916e62aab89caa97a33a1dd8c342e87a37f91073cd4746"] -prometheus-client = ["1b38b958750f66f208bcd9ab92a633c0c994d8859c831f7abc1f46724fcee490"] -prompt-toolkit = ["11adf3389a996a6d45cc277580d0d53e8a5afd281d0c9ec71b28e6f121463780", "2519ad1d8038fd5fc8e770362237ad0364d16a7650fb5724af6997ed5515e3c1", "977c6583ae813a37dc1c2e1b715892461fcbdaa57f6fc62f33a528c4886c8f55"] -psycopg2-binary = ["007ca0df127b1862fc010125bc4100b7a630efc6841047bd11afceadb4754611", "03c49e02adf0b4d68f422fdbd98f7a7c547beb27e99a75ed02298f85cb48406a", "0a1232cdd314e08848825edda06600455ad2a7adaa463ebfb12ece2d09f3370e", "131c80d0958c89273d9720b9adf9df1d7600bb3120e16019a7389ab15b079af5", "2de34cc3b775724623f86617d2601308083176a495f5b2efc2bbb0da154f483a", "2eddc31500f73544a2a54123d4c4b249c3c711d31e64deddb0890982ea37397a", "484f6c62bdc166ee0e5be3aa831120423bf399786d1f3b0304526c86180fbc0b", "4c2d9369ed40b4a44a8ccd6bc3a7db6272b8314812d2d1091f95c4c836d92e06", "70f570b5fa44413b9f30dbc053d17ef3ce6a4100147a10822f8662e58d473656", "7a2b5b095f3bd733aab101c89c0e1a3f0dfb4ebdc26f6374805c086ffe29d5b2", "804914a669186e2843c1f7fbe12b55aad1b36d40a28274abe6027deffad9433d", "8520c03172da18345d012949a53617a963e0191ccb3c666f23276d5326af27b5", "90da901fc33ea393fc644607e4a3916b509387e9339ec6ebc7bfded45b7a0ae9", "a582416ad123291a82c300d1d872bdc4136d69ad0b41d57dc5ca3df7ef8e3088", "ac8c5e20309f4989c296d62cac20ee456b69c41fd1bc03829e27de23b6fa9dd0", "b2cf82f55a619879f8557fdaae5cec7a294fac815e0087c4f67026fdf5259844", "b59d6f8cfca2983d8fdbe457bf95d2192f7b7efdb2b483bf5fa4e8981b04e8b2", "be08168197021d669b9964bd87628fa88f910b1be31e7010901070f2540c05fd", "be0f952f1c365061041bad16e27e224e29615d4eb1fb5b7e7760a1d3d12b90b6", "c1c9a33e46d7c12b9c96cf2d4349d783e3127163fd96254dcd44663cf0a1d438", "d18c89957ac57dd2a2724ecfe9a759912d776f96ecabba23acb9ecbf5c731035", "d7e7b0ff21f39433c50397e60bf0995d078802c591ca3b8d99857ea18a7496ee", "da0929b2bf0d1f365345e5eb940d8713c1d516312e010135b14402e2a3d2404d", "de24a4962e361c512d3e528ded6c7480eab24c655b8ca1f0b761d3b3650d2f07", "e45f93ff3f7dae2202248cf413a87aeb330821bf76998b3cf374eda2fc893dd7", "f046aeae1f7a845041b8661bb7a52449202b6c5d3fb59eb4724e7ca088811904", "f1dc2b7b2748084b890f5d05b65a47cd03188824890e9a60818721fd492249fb", "fcbe7cf3a786572b73d2cd5f34ed452a5f5fac47c9c9d1e0642c457a148f9f88"] -ptyprocess = ["923f299cc5ad920c68f2bc0bc98b75b9f838b93b599941a6b63ddbc2476394c0", "d7cc528d76e76342423ca640335bd3633420dc1366f258cb31d05e865ef5ca1f"] -py = ["64f65755aee5b381cea27766a3a147c3f15b9b6b9ac88676de66ba2ae36793fa", "dc639b046a6e2cff5bbe40194ad65936d6ba360b52b3c3fe1d08a82dd50b5e53"] -pygments = ["5ffada19f6203563680669ee7f53b64dabbeb100eb51b61996085e99c03b284a", "e8218dd399a61674745138520d0d4cf2621d7e032439341bc3f647bff125818d"] -pyparsing = ["1873c03321fc118f4e9746baf201ff990ceb915f433f23b395f5580d1840cb2a", "9b6323ef4ab914af344ba97510e966d64ba91055d6b9afa6b30799340e89cc03"] -pyrsistent = ["3ca82748918eb65e2d89f222b702277099aca77e34843c5eb9d52451173970e2"] -pytest = ["3773f4c235918987d51daf1db66d51c99fac654c81d6f2f709a046ab446d5e5d", "b7802283b70ca24d7119b32915efa7c409982f59913c1a6c0640aacf118b95f5"] -pytest-cov = ["0ab664b25c6aa9716cbf203b17ddb301932383046082c081b9848a0edf5add33", "230ef817450ab0699c6cc3c9c8f7a829c34674456f2ed8df1fe1d39780f7c87f"] -pytest-helpers-namespace = ["4eff23a19f92410c0166f6dffbfa8901d3e14a80e97d70cd08428b6d597771ce", "e2c5475bc6d50e81a30f5644b1612ada643c81bfc8ca51efc1d08ebac299fb31"] -pytest-mock = ["43ce4e9dd5074993e7c021bb1c22cbb5363e612a2b5a76bc6d956775b10758b7", "5bf5771b1db93beac965a7347dc81c675ec4090cb841e49d9d34637a25c30568"] -python-dateutil = ["7e6584c74aeed623791615e26efd690f29817a27c73085b78e4bad02493df2fb", "c89805f6f4d64db21ed966fda138f8a5ed7a4fdbc1a8ee329ce1b74e3c74da9e"] -pytz = ["303879e36b721603cc54604edcac9d20401bdbe31e1e4fdee5b9f98d5d31dfda", "d747dd3d23d77ef44c6a3526e274af6efeb0a6f1afd5a69ba4d5be4098c8e141"] -pywinpty = ["0e01321e53a230233358a6d608a1a8bc86c3882cf82769ba3c62ca387dc9cc51", "333e0bc5fca8ad9e9a1516ebedb2a65da38dc1f399f8b2ea57d6cccec1ff2cc8", "3ca3123aa6340ab31bbf9bd012b92e72f9ec905e4c9ee152cc997403e1778cd3", "44a6dddcf2abf402e22f87e2c9a341f7d0b296afbec3d28184c8de4d7f514ee4", "53d94d574c3d4da2df5b1c3ae728b8d90e4d33502b0388576bbd4ddeb4de0f77", "c3955f162c53dde968f3fc11361658f1d83b683bfe601d4b6f94bb01ea4300bc", "cec9894ecb34de3d7b1ca121dd98433035b9f8949b5095e84b103b349231509c", "dcd45912e2fe2e6f72cee997a4da6ed1ad2056165a277ce5ec7f7ac98dcdf667", "f2bcdd9a2ffd8b223752a971b3d377fb7bfed85f140ec9710f1218d760f2ccb7"] -pyzmq = ["1651e52ed91f0736afd6d94ef9f3259b5534ce8beddb054f3d5ca989c4ef7c4f", "5ccb9b3d4cd20c000a9b75689d5add8cd3bce67fcbd0f8ae1b59345247d803af", "5e120c4cd3872e332fb35d255ad5998ebcee32ace4387b1b337416b6b90436c7", "5e2a3707c69a7281a9957f83718815fd74698cba31f6d69f9ed359921f662221", "63d51add9af8d0442dc90f916baf98fdc04e3b0a32afec4bfc83f8d85e72959f", "65c5a0bdc49e20f7d6b03a661f71e2fda7a99c51270cafe71598146d09810d0d", "66828fabe911aa545d919028441a585edb7c9c77969a5fea6722ef6e6ece38ab", "7d79427e82d9dad6e9b47c0b3e7ae5f9d489b1601e3a36ea629bb49501a4daf3", "824ee5d3078c4eae737ffc500fbf32f2b14e6ec89b26b435b7834febd70120cf", "89dc0a83cccec19ff3c62c091e43e66e0183d1e6b4658c16ee4e659518131494", "8b319805f6f7c907b101c864c3ca6cefc9db8ce0791356f180b1b644c7347e4c", "90facfb379ab47f94b19519c1ecc8ec8d10813b69d9c163117944948bdec5d15", "a0a178c7420021fc0730180a914a4b4b3092ce9696ceb8e72d0f60f8ce1655dd", "a7a89591ae315baccb8072f216614b3e59aed7385aef4393a6c741783d6ee9cf", "ba2578f0ae582452c02ed9fac2dc477b08e80ce05d2c0885becf5fff6651ccb0", "c69b0055c55702f5b0b6b354133e8325b9a56dbc80e1be2d240bead253fb9825", "ca434e1858fe222380221ddeb81e86f45522773344c9da63c311d17161df5e06", "d4b8ecfc3d92f114f04d5c40f60a65e5196198b827503341521dda12d8b14939", "d706025c47b09a54f005953ebe206f6d07a22516776faa4f509aaff681cc5468", "d8f27e958f8a2c0c8ffd4d8855c3ce8ac3fa1e105f0491ce31729aa2b3229740", "dbd264298f76b9060ce537008eb989317ca787c857e23cbd1b3ddf89f190a9b1", "e926d66f0df8fdbf03ba20583af0f215e475c667fb033d45fd031c66c63e34c9", "efc3bd48237f973a749f7312f68062f1b4ca5c2032a0673ca3ea8e46aa77187b", "f59bc782228777cbfe04555707a9c56d269c787ed25d6d28ed9d0fbb41cb1ad2", "f8da5322f4ff5f667a0d5a27e871b560c6637153c81e318b35cb012b2a98835c"] -qtconsole = ["1ac4a65e81a27b0838330a6d351c2f8435d4013d98a95373e8a41119b2968390", "bc1ba15f50c29ed50f1268ad823bb6543be263c18dd093b80495e9df63b003ac"] -requests = ["502a824f31acdacb3a35b6690b5fbf0bc41d63a24a45c4004352b0242707598e", "7bf2a778576d825600030a110f3c0e3e8edc51dfaafe1c146e39a2027784957b"] -schedule = ["3f895a1036799a25ab9c335de917073e63cf8256920917e932777382f101f08f", "f9fb5181283de4db6e701d476dd01b6a3dd81c38462a54991ddbb9d26db857c9"] -scikit-learn = ["018f470a7e685767d84ce6fac87af59e064e87ec3cea71eaf12646f9538e293d", "0ae00d570331b8a5c552f721167818b4739a5c855fbc76b11231ccdea2dd26ab", "13079520dd8211967d1871e439b59818d335439672818e9683847091d0e07778", "1c133749a526b33af2b6695d94d2cc43ba212c5aa7bd3a45619335556ced7637", "382e7053567b7b11e862782e3de2940e2141be24e6262aa0b4a9cb7fdd61f85a", "384df81fdba12d21063072f2cf472a7a8425a3d4fa3915faef0a88e94e07b332", "4705073de7bbcc6b9cd2f24dc9189aa8d3935e8621d3e65546c4b7fee9a042bf", "4f829d6c09b997e1d0a998f970cf3ff82cd6796d56148c63c29174367878d490", "51a933224b1b11986d4c7c123e5b28eb69602899d0179e6888b7abf2ffc85265", "63ad98c6512b52aebde9bd806ec1127e13e2a8d42a00ebdf805153819f7c2cad", "67e15514c9df4c5354b3ecc89451f5baa0f1b62c7ed68f4d20febf9c9d9e17a6", "75f0e0e93851b30639baabfc1a4433aabc57eef269d55ee4c6f649fb60686218", "89609708e819342dd5c94617fd53a36187d7d6a80435ddb282f6a60b058dbe77", "8ca274d4e91685e4547af718b6f1e9a9d4912c7a6dcb0c68925de84f81a09d2a", "9987f3d31efc427ebf9926f703e5171552cfb3b6935f880e4f0d3a17b7f91540", "9f3e08dbd3f2f574913faba9b48d3c24a43fcc0eb14a0e962431005434b9cfe6", "a7a403bcea250cac37971058fca0c30b0144737a375f99d3855e5e7a34c43348", "ad7e4e823db1271d344e0c3ce0988b2e0fecc49079eec9c818d866c38b2824bd", "b1e9037a582e650d866324a50d2741724ea5f6c175200bef0b549d014898035a", "b82fbd8843ead2640158b2c0946d354b66f3d49472e6790d70c4ceec35663b3f", "b91c82bfd25145d428de99429de97d7a1c2c2658c212689fe2839b29a5251159", "ba57b73ec7074f60bb85f953296df437784d560553d0cc04b253c43f1846ccad", "c503802a81de18b8b4d40d069f5e363795ee44b1605f38bc104160ca3bfe2c41", "d30e8e0dffbc299533f47044fec26c5087473cb29cf51f1995986ac8354c7b4c", "d89b810bfb0e16a0de7f18773849bdf83dd7fd0614ae5225e5a9214cdb9be245", "e22e1d47def2944ad7a12c09452de085587ec5baad2174683e56a42b6918a76f", "f650ddc023c95681fccd5e297820f35de039e008265040c08188be95b3275a0f", "f7d4b3885ad1a7a6f07719ab6b1790d9892d6d41d973e8d4543a93bb15226fb4"] -scipy = ["014cb900c003b5ac81a53f2403294e8ecf37aedc315b59a6b9370dce0aa7627a", "281a34da34a5e0de42d26aed692ab710141cad9d5d218b20643a9cb538ace976", "588f9cc4bfab04c45fbd19c1354b5ade377a8124d6151d511c83730a9b6b2338", "5a10661accd36b6e2e8855addcf3d675d6222006a15795420a39c040362def66", "628f60be272512ca1123524969649a8cb5ae8b31cca349f7c6f8903daf9034d7", "6dcc43a88e25b815c2dea1c6fac7339779fc988f5df8396e1de01610604a7c38", "70e37cec0ac0fe95c85b74ca4e0620169590fd5d3f44765f3c3a532cedb0e5fd", "7274735fb6fb5d67d3789ddec2cd53ed6362539b41aa6cc0d33a06c003aaa390", "78e12972e144da47326958ac40c2bd1c1cca908edc8b01c26a36f9ffd3dce466", "790cbd3c8d09f3a6d9c47c4558841e25bac34eb7a0864a9def8f26be0b8706af", "79792c8fe8e9d06ebc50fe23266522c8c89f20aa94ac8e80472917ecdce1e5ba", "865afedf35aaef6df6344bee0de391ee5e99d6e802950a237f9fb9b13e441f91", "870fd401ec7b64a895cff8e206ee16569158db00254b2f7157b4c9a5db72c722", "963815c226b29b0176d5e3d37fc9de46e2778ce4636a5a7af11a48122ef2577c", "9726791484f08e394af0b59eb80489ad94d0a53bbb58ab1837dcad4d58489863", "9de84a71bb7979aa8c089c4fb0ea0e2ed3917df3fb2a287a41aaea54bbad7f5d", "b2c324ddc5d6dbd3f13680ad16a29425841876a84a1de23a984236d1afff4fa6", "b86ae13c597fca087cb8c193870507c8916cefb21e52e1897da320b5a35075e5", "ba0488d4dbba2af5bf9596b849873102d612e49a118c512d9d302ceafa36e01a", "d78702af4102a3a4e23bb7372cec283e78f32f5573d92091aa6aaba870370fe1", "def0e5d681dd3eb562b059d355ae8bebe27f5cc455ab7c2b6655586b63d3a8ea", "e085d1babcb419bbe58e2e805ac61924dac4ca45a07c9fa081144739e500aa3c", "e2cfcbab37c082a5087aba5ff00209999053260441caadd4f0e8f4c2d6b72088", "e742f1f5dcaf222e8471c37ee3d1fd561568a16bb52e031c25674ff1cf9702d5", "f06819b028b8ef9010281e74c59cb35483933583043091ed6b261bb1540f11cc", "f15f2d60a11c306de7700ee9f65df7e9e463848dbea9c8051e293b704038da60", "f31338ee269d201abe76083a990905473987371ff6f3fdb76a3f9073a361cf37", "f6b88c8d302c3dac8dff7766955e38d670c82e0d79edfc7eae47d6bb2c186594"] -send2trash = ["60001cc07d707fe247c94f74ca6ac0d3255aabcb930529690897ca2a39db28b2", "f1691922577b6fa12821234aeb57599d887c4900b9ca537948d2dac34aea888b"] -six = ["3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", "d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73"] -snowballstemmer = ["919f26a68b2c17a7634da993d91339e288964f93c274f1343e3bbbe2096e1128", "9f3bcd3c401c3e862ec0ebe6d2c069ebc012ce142cce209c098ccb5b09136e89"] -soupsieve = ["6898e82ecb03772a0d82bd0d0a10c0d6dcc342f77e0701d0ec4a8271be465ece", "b20eff5e564529711544066d7dc0f7661df41232ae263619dede5059799cdfca"] -sphinx = ["423280646fb37944dd3c85c58fb92a20d745793a9f6c511f59da82fa97cd404b", "de930f42600a4fef993587633984cc5027dedba2464bcf00ddace26b40f8d9ce"] -sphinx-rtd-theme = ["00cf895504a7895ee433807c62094cf1e95f065843bf3acd17037c3e9a2becd4", "728607e34d60456d736cc7991fd236afb828b21b82f956c5ea75f94c8414040a"] -sphinxcontrib-applehelp = ["edaa0ab2b2bc74403149cb0209d6775c96de797dfd5b5e2a71981309efab3897", "fb8dee85af95e5c30c91f10e7eb3c8967308518e0f7488a2828ef7bc191d0d5d"] -sphinxcontrib-devhelp = ["6c64b077937330a9128a4da74586e8c2130262f014689b4b89e2d08ee7294a34", "9512ecb00a2b0821a146736b39f7aeb90759834b07e81e8cc23a9c70bacb9981"] -sphinxcontrib-htmlhelp = ["4670f99f8951bd78cd4ad2ab962f798f5618b17675c35c5ac3b2132a14ea8422", "d4fd39a65a625c9df86d7fa8a2d9f3cd8299a3a4b15db63b50aac9e161d8eff7"] -sphinxcontrib-jsmath = ["2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178", "a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"] -sphinxcontrib-qthelp = ["513049b93031beb1f57d4daea74068a4feb77aa5630f856fcff2e50de14e9a20", "79465ce11ae5694ff165becda529a600c754f4bc459778778c7017374d4d406f"] -sphinxcontrib-serializinghtml = ["c0efb33f8052c04fd7a26c0a07f1678e8512e0faec19f4aa8f2473a8b81d5227", "db6615af393650bf1151a6cd39120c29abaf93cc60db8c48eb2dddbfdc3a9768"] -sqlalchemy = ["91c54ca8345008fceaec987e10924bf07dcab36c442925357e5a467b36a38319"] -terminado = ["d9d012de63acb8223ac969c17c3043337c2fcfd28f3aea1ee429b345d01ef460", "de08e141f83c3a0798b050ecb097ab6259c3f0331b2f7b7750c9075ced2c20c2"] -testpath = ["46c89ebb683f473ffe2aab0ed9f12581d4d078308a3cb3765d79c6b2317b0109", "b694b3d9288dbd81685c5d2e7140b81365d46c29f5db4bc659de5aa6b98780f8"] -tornado = ["1174dcb84d08887b55defb2cda1986faeeea715fff189ef3dc44cce99f5fca6b", "2613fab506bd2aedb3722c8c64c17f8f74f4070afed6eea17f20b2115e445aec", "44b82bc1146a24e5b9853d04c142576b4e8fa7a92f2e30bc364a85d1f75c4de2", "457fcbee4df737d2defc181b9073758d73f54a6cfc1f280533ff48831b39f4a8", "49603e1a6e24104961497ad0c07c799aec1caac7400a6762b687e74c8206677d", "8c2f40b99a8153893793559919a355d7b74649a11e59f411b0b0a1793e160bc0", "e1d897889c3b5a829426b7d52828fb37b28bc181cd598624e65c8be40ee3f7fa"] -traitlets = ["9c4bd2d267b7153df9152698efb1050a5d84982d3384a37b2c1f7723ba3e7835", "c6cb5e6f57c5a9bdaa40fa71ce7b4af30298fbab9ece9815b5d995ab6217c7d9"] -urllib3 = ["4c291ca23bbb55c76518905869ef34bdd5f0e46af7afe6861e8375643ffee1a0", "9a247273df709c4fedb38c711e44292304f73f39ab01beda9f6b9fc375669ac3"] -wcwidth = ["3df37372226d6e63e1b1e1eda15c594bca98a22d33a23832a90998faa96bc65e", "f4ebe71925af7b40a864553f761ed559b43544f8f71746c2d756c7fe788ade7c"] -webencodings = ["a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", "b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"] -werkzeug = ["0a73e8bb2ff2feecfc5d56e6f458f5b99290ef34f565ffb2665801ff7de6af7a", "7fad9770a8778f9576693f0cc29c7dcc36964df916b83734f4431c0e612a7fbc"] -widgetsnbextension = ["14b2c65f9940c9a7d3b70adbe713dbd38b5ec69724eebaba034d1036cf3d4740", "fa618be8435447a017fd1bf2c7ae922d0428056cfc7449f7a8641edf76b48265"] -win-unicode-console = ["d4142d4d56d46f449d6f00536a73625a871cba040f0bc1a2e305a04578f07d1e"] -wordcloud = ["1ba7de6e3179f77f390fa70a363fcd8a3708dd79df7994738f0ba20e6b4eec4a", "2804995d361438fde75114543d5e48cf4b9f6bc74327c7ed6973ccba0e11221d", "2c67ae08992ced6ee465b31e307e2d686c593fd5d25459b7bf79effd08e5b797", "5259f04f0e06a58c313e4c9c145a11ca8c4443bb5d9195414160c0f359d047d8", "5425b176d9d8a634130db398400a830aa1f43a2bd1d60e16801764ae2b44ed4a", "578996a2ac83d2199f96661e66af587f010ffb472744fd834186cdfd060d5e38", "5a90670745e346e468ec0e203e329e8c44392a4e9aae38dcceb4d313ac0dc939", "6ceed30c943b49e8e8b222a4d5a6725bbeca180fada7a04c4121ed238d6896e6", "78a856ca60be4c912cd27c3050dd4ad79e34ca021cd83fd61b77bbb10a84a089", "80b6646a821537faa88b4bba78e35c20f9056bd7227b76fcf065b6627709c089", "9b87d3ccb7829f8e5fbe1847126f9d232bd7d8d299475e5fc8e5331c5cd52fa6", "a0e70a23de1e978059a35a1fda976d921b802f0ef7cd145283be7a0772f46b11", "a8b7b896e7c767afc4d195d0c1657320d6e3db1e02a919eeb2d895b0c277afd9", "c567d8d5e6743932f1748ac0db6235dc8948fdf34c4819dffebc4914b9e37d3c", "c7c0de04c68bef168d51ece614e979b19a22287101efbf86ad0b23e91a9f8405", "d13cce1ad31d5dc6d9d276a5745fe1067d40b680901fad45527bad660f28232e", "f2df3140b4355b589316f4bc80e08f4385cd74a57d6de6e97d2f85847e2161c5"] diff --git a/pyproject.toml b/pyproject.toml index 86427020..3d039b48 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,60 +1,73 @@ [tool.black] line-length = 79 -[tool.poetry] -name = "superintendent" -version = "0.4.2" -description = "Interactive machine learning supervision." -authors = ["Jan Freyberg "] -readme = "README.md" -license = "MIT" -homepage = "https://www.janfreyberg.com/superintendent" -repository = "https://github.com/janfreyberg/superintendent" -keywords = ["widgets", "labelling", "annotation"] +[build-system] +requires = ["flit"] +build-backend = "flit.buildapi" + +[tool.flit.metadata] +module = "superintendent" +author = "Jan Freyberg" +author-email = "jan.freyberg@gmail.com" +home-page = "https://github.com/janfreyberg/superintendent" +description-file = "README.md" classifiers = [ - "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "License :: OSI Approved :: MIT License", "Intended Audience :: Science/Research", "Framework :: Jupyter", ] +license = "MIT" +keywords = "widgets labelling annotation" +requires-python = ">=3.6" +requires = [ + "ipywidgets>=7.4", + "numpy>=1.15", + "pandas>=0.24.0", + "matplotlib>=3.0", + "scikit-learn>=0.20.3", + "scipy>=1.2", + "schedule>=0.6.0", + "sqlalchemy>=1.3", + "cachetools>=3.1", + "psycopg2-binary>=2.8", + "flask>=1.0", + "ipyevents>=0.6.0", +] -[tool.poetry.dependencies] -python = "^3.5" -ipywidgets = "^7.4" -ipyevents = "^0.4.1" -numpy = "^1.16" -pandas = "^0.24.2" -matplotlib = "^3.0" -scikit-learn = "^0.20.3" -scipy = "^1.2" -schedule = "^0.6.0" -sqlalchemy = "^1.3" -cachetools = "^3.1" -psycopg2-binary = "^2.8" -flask = "^1.0" - -[tool.poetry.dev-dependencies] -jupyterlab = "^0.35.4" -pytest = "^4.4" -hypothesis = "^4.17" -pytest-helpers-namespace = "^2019.1" -pytest-mock = "^1.10" -nbconvert = "^5.4" -jupyter = "^1.0" -pytest-cov = "^2.6" -coveralls = "^1.7" -requests = "^2.21" -html5lib = "^1.0" -bs4 = "^0.0.1" -wordcloud = "^1.5" -m2r = "^0.2.1" -sphinx_rtd_theme = "^0.4.3" -jupyter_sphinx = "^0.1.4" -sphinx = "^2.0" -nbsphinx = "^0.4.2" - -[build-system] -requires = ["poetry>=0.12"] -build-backend = "poetry.masonry.api" +[tool.flit.metadata.requires-extra] +dev = [ + "jupyterlab>=1.1", + "rope", + "docargs", + "black>=19.3b0", + "flake8>=3.7", +] +test = [ + "isort>=4.3.21", + "pytest>=4.1", + "pytest-cov>=2.6", + "hypothesis>=4.17", + "pytest-helpers-namespace>=2019.1", + "pytest-mock>=1.10", + "nbconvert>=5.4", + "coveralls>=1.7", +] +doc = [ + "sphinx>=2.0", + "requests>=2.21", + "html5lib>=1.0", + "bs4>=0.0.1", + "wordcloud>=1.5", + "m2r>=0.2.1", + "sphinx_rtd_theme>=0.4.3", + "jupyter_sphinx>=0.1.4", + "nbsphinx>=0.4.2", +] +examples = [ + "requests>=2.21", + "html5lib>=1.0", + "bs4>=0.0.1", + "wordcloud>=1.5", +] diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 214d7fd1..00000000 --- a/setup.cfg +++ /dev/null @@ -1,4 +0,0 @@ -[metadata] -description-file = README.md -[aliases] -test="pytest" diff --git a/src/superintendent/version.py b/src/superintendent/version.py deleted file mode 100644 index 8785d00b..00000000 --- a/src/superintendent/version.py +++ /dev/null @@ -1,4 +0,0 @@ -import pkg_resources - -__version__ = pkg_resources.get_distribution("superintendent").version -version = __version__ diff --git a/src/superintendent/__init__.py b/superintendent/__init__.py similarity index 66% rename from src/superintendent/__init__.py rename to superintendent/__init__.py index 2d8b476c..479b8e0b 100644 --- a/src/superintendent/__init__.py +++ b/superintendent/__init__.py @@ -1,4 +1,6 @@ +"""Interactive machine learning supervision.""" from .clustersupervisor import ClusterSupervisor # noqa -from .semisupervisor import SemiSupervisor # noqa from .multioutput import MultiLabeller # noqa -from .version import __version__ # noqa +from .semisupervisor import SemiSupervisor # noqa + +__version__ = "0.4.3" # noqa diff --git a/superintendent/_compatibility.py b/superintendent/_compatibility.py new file mode 100644 index 00000000..9cca13b0 --- /dev/null +++ b/superintendent/_compatibility.py @@ -0,0 +1,13 @@ +import contextlib +import warnings + + +@contextlib.contextmanager +def ignore_widget_on_submit_warning(): + with warnings.catch_warnings(): + warnings.filterwarnings( + "ignore", + message=r".*on_submit is deprecated.*", + category=DeprecationWarning, + ) + yield diff --git a/src/superintendent/base.py b/superintendent/base.py similarity index 95% rename from src/superintendent/base.py rename to superintendent/base.py index 9351387a..70bf1422 100644 --- a/src/superintendent/base.py +++ b/superintendent/base.py @@ -58,7 +58,7 @@ def __init__( self, features: Optional[Any] = None, labels: Optional[Any] = None, - options: Tuple[str] = (), + options: Tuple[str, ...] = (), other_option: bool = True, max_buttons: int = 12, display_func: Callable = None, @@ -222,9 +222,11 @@ def _render_processing(self, message="Rendering..."): IPython.display.clear_output(wait=True) IPython.display.display( widgets.HTML( - "

{}".format(message) - + '' + value=( + "

{}".format(message) + + '' + ) ) ) @@ -234,7 +236,9 @@ def _render_finished(self): with self.feature_output: IPython.display.clear_output(wait=True) - IPython.display.display(widgets.HTML(u"

Finished labelling 🎉!")) + IPython.display.display( + widgets.HTML(value=u"

Finished labelling 🎉!") + ) self.layout.children = [self.progressbar, self.feature_display] return self diff --git a/src/superintendent/clustersupervisor.py b/superintendent/clustersupervisor.py similarity index 100% rename from src/superintendent/clustersupervisor.py rename to superintendent/clustersupervisor.py diff --git a/src/superintendent/controls/__init__.py b/superintendent/controls/__init__.py similarity index 100% rename from src/superintendent/controls/__init__.py rename to superintendent/controls/__init__.py index 937c490f..e9caa549 100644 --- a/src/superintendent/controls/__init__.py +++ b/superintendent/controls/__init__.py @@ -1,3 +1,3 @@ -from .submitter import Submitter # noqa from .multiclasssubmitter import MulticlassSubmitter # noqa +from .submitter import Submitter # noqa from .timer import Timer # noqa diff --git a/src/superintendent/controls/buttongroup.py b/superintendent/controls/buttongroup.py similarity index 91% rename from src/superintendent/controls/buttongroup.py rename to superintendent/controls/buttongroup.py index 49856cd0..a4350f30 100644 --- a/src/superintendent/controls/buttongroup.py +++ b/superintendent/controls/buttongroup.py @@ -19,9 +19,9 @@ class ButtonGroup(widgets.HBox): """ options = traitlets.List( - trait=traitlets.Unicode(), default=list(), allow_none=True + default_value=[], trait=traitlets.Unicode(), allow_none=True ) - submission_functions = traitlets.List(list(), allow_none=True) + submission_functions = traitlets.List(default_value=[], allow_none=True) button_width = traitlets.Union( [traitlets.Float(), traitlets.Integer(), traitlets.Unicode()], allow_none=True, @@ -86,10 +86,10 @@ def _handle_click(self, owner: widgets.Button) -> None: func(owner) @traitlets.validate("button_width") - def _valid_value(self, proposal: Dict): - if isinstance(proposal["value"], Number) and proposal["value"] <= 1: + def _valid_value(self, proposal: Dict[str, Union[float, int, Text]]): + if isinstance(proposal["value"], float) and proposal["value"] <= 1: return "{}%".format(int(100 * proposal["value"])) - elif isinstance(proposal["value"], Number): + elif isinstance(proposal["value"], (int, float)): return "{}px".format(int(proposal["value"])) elif isinstance(proposal["value"], str): return proposal["value"] diff --git a/src/superintendent/controls/dropdownbutton.py b/superintendent/controls/dropdownbutton.py similarity index 87% rename from src/superintendent/controls/dropdownbutton.py rename to superintendent/controls/dropdownbutton.py index 138193bf..a93209be 100644 --- a/src/superintendent/controls/dropdownbutton.py +++ b/superintendent/controls/dropdownbutton.py @@ -1,5 +1,5 @@ from collections import defaultdict -from typing import Callable, Sequence +from typing import Callable, DefaultDict, Sequence import ipywidgets as widgets import traitlets @@ -8,9 +8,11 @@ class DropdownButton(widgets.VBox): options = traitlets.List( - trait=traitlets.Unicode(), default=list(), allow_none=True + trait=traitlets.Unicode(), default_value=list(), allow_none=True + ) + submission_functions = traitlets.List( + default_value=list(), allow_none=True ) - submission_functions = traitlets.List(list(), allow_none=True) def __init__(self, options: Sequence[str], *args, **kwargs): """Create a dropdown button. @@ -39,7 +41,9 @@ def __init__(self, options: Sequence[str], *args, **kwargs): ) self.button.on_click(self._handle_click) - self.hints = defaultdict(widgets.Output) + self.hints: DefaultDict[str, widgets.Output] = defaultdict( + widgets.Output + ) self.children = [ widgets.HBox([self.dropdown, self.button]), diff --git a/src/superintendent/controls/hintedmultiselect.py b/superintendent/controls/hintedmultiselect.py similarity index 100% rename from src/superintendent/controls/hintedmultiselect.py rename to superintendent/controls/hintedmultiselect.py diff --git a/src/superintendent/controls/keycapture.py b/superintendent/controls/keycapture.py similarity index 100% rename from src/superintendent/controls/keycapture.py rename to superintendent/controls/keycapture.py diff --git a/src/superintendent/controls/multiclasssubmitter.py b/superintendent/controls/multiclasssubmitter.py similarity index 94% rename from src/superintendent/controls/multiclasssubmitter.py rename to superintendent/controls/multiclasssubmitter.py index d359d00d..76c18f5b 100644 --- a/src/superintendent/controls/multiclasssubmitter.py +++ b/superintendent/controls/multiclasssubmitter.py @@ -1,6 +1,7 @@ import ipywidgets as widgets import traitlets +from .._compatibility import ignore_widget_on_submit_warning from .hintedmultiselect import HintedMultiselect from .keycapture import DEFAULT_SHORTCUTS from .submitter import Submitter @@ -75,7 +76,8 @@ def _compose(self, change=None): description="Other:", placeholder="Hit enter to submit.", ) - self.other_widget.on_submit(self._when_submitted) + with ignore_widget_on_submit_warning(): + self.other_widget.on_submit(self._when_submitted) else: self.other_widget = widgets.HBox([]) diff --git a/src/superintendent/controls/submitter.py b/superintendent/controls/submitter.py similarity index 94% rename from src/superintendent/controls/submitter.py rename to superintendent/controls/submitter.py index 9f82e0ca..7c3cdead 100644 --- a/src/superintendent/controls/submitter.py +++ b/superintendent/controls/submitter.py @@ -1,10 +1,11 @@ """Input and timing control widgets.""" -from typing import Any, Callable, Dict, List, Optional, Tuple, Union +from typing import Any, Callable, Dict, Optional, Sequence import ipywidgets as widgets import traitlets +from .._compatibility import ignore_widget_on_submit_warning from .buttongroup import ButtonGroup, ButtonWithHint from .dropdownbutton import DropdownButton from .keycapture import DEFAULT_SHORTCUTS @@ -47,7 +48,7 @@ class Submitter(widgets.VBox): def __init__( self, - options: Optional[Union[List[str], Tuple[str]]] = (), + options: Sequence[str] = (), max_buttons: int = 12, other_option: bool = True, hint_function: Optional[Callable] = None, @@ -63,12 +64,12 @@ def __init__( """ super().__init__([]) - self.submission_functions = [] + self.submission_functions: Sequence[Callable] = [] self.hint_function = hint_function # self.shortcuts = shortcuts self.hints = dict() if hints is None else hints - if hint_function is not None: + if self.hint_function is not None: for option, feature in self.hints.items(): self.hints[option] = widgets.Output() with self.hints[option]: @@ -203,7 +204,8 @@ def _compose(self, change=None): description="Other:", placeholder="Hit enter to submit.", ) - self.other_widget.on_submit(self._when_submitted) + with ignore_widget_on_submit_warning(): + self.other_widget.on_submit(self._when_submitted) else: self.other_widget = widgets.HBox([]) diff --git a/src/superintendent/controls/timer.py b/superintendent/controls/timer.py similarity index 100% rename from src/superintendent/controls/timer.py rename to superintendent/controls/timer.py diff --git a/src/superintendent/controls/togglebuttongroup.py b/superintendent/controls/togglebuttongroup.py similarity index 90% rename from src/superintendent/controls/togglebuttongroup.py rename to superintendent/controls/togglebuttongroup.py index 566d3cf2..80394580 100644 --- a/src/superintendent/controls/togglebuttongroup.py +++ b/superintendent/controls/togglebuttongroup.py @@ -19,9 +19,11 @@ class ToggleButtonGroup(widgets.HBox): """ options = traitlets.List( - trait=traitlets.Unicode(), default=list(), allow_none=True + trait=traitlets.Unicode(), default_value=list(), allow_none=True + ) + submission_functions = traitlets.List( + default_value=list(), allow_none=True ) - submission_functions = traitlets.List(list(), allow_none=True) button_width = traitlets.Union( [traitlets.Float(), traitlets.Integer(), traitlets.Unicode()], allow_none=True, @@ -75,10 +77,10 @@ def value(self): ] @traitlets.validate("button_width") - def _valid_value(self, proposal: Dict): - if isinstance(proposal["value"], Number) and proposal["value"] <= 1: + def _valid_value(self, proposal: Dict[str, Union[float, int, Text]]): + if isinstance(proposal["value"], float) and proposal["value"] <= 1: return "{}%".format(int(100 * proposal["value"])) - elif isinstance(proposal["value"], Number): + elif isinstance(proposal["value"], (int, float)): return "{}px".format(int(proposal["value"])) elif isinstance(proposal["value"], str): return proposal["value"] diff --git a/src/superintendent/display.py b/superintendent/display.py similarity index 94% rename from src/superintendent/display.py rename to superintendent/display.py index be2ab0ce..86f1a730 100644 --- a/src/superintendent/display.py +++ b/superintendent/display.py @@ -1,4 +1,5 @@ """Helper functions for displaying types of data.""" +from typing import Callable, Dict import IPython.display import numpy as np @@ -49,7 +50,7 @@ def image_display_func(image, imsize=None): plt.show() -functions = { +functions: Dict[str, Callable] = { "default": default_display_func, "image": image_display_func, "img": image_display_func, diff --git a/src/superintendent/distributed/__init__.py b/superintendent/distributed/__init__.py similarity index 100% rename from src/superintendent/distributed/__init__.py rename to superintendent/distributed/__init__.py index c70d886b..dcdc913d 100644 --- a/src/superintendent/distributed/__init__.py +++ b/superintendent/distributed/__init__.py @@ -1,2 +1,2 @@ -from .semisupervisor import SemiSupervisor # noqa from .multioutput import MultiLabeller # noqa +from .semisupervisor import SemiSupervisor # noqa diff --git a/src/superintendent/distributed/dbqueue.py b/superintendent/distributed/dbqueue.py similarity index 99% rename from src/superintendent/distributed/dbqueue.py rename to superintendent/distributed/dbqueue.py index f80d2d88..630256be 100644 --- a/src/superintendent/distributed/dbqueue.py +++ b/superintendent/distributed/dbqueue.py @@ -8,13 +8,12 @@ from functools import reduce from typing import Any, Dict, Sequence, Set, Tuple -import sqlalchemy as sa -import sqlalchemy.ext.declarative -from sqlalchemy.exc import OperationalError, ProgrammingError - import cachetools import numpy as np import pandas as pd +import sqlalchemy as sa +import sqlalchemy.ext.declarative +from sqlalchemy.exc import OperationalError, ProgrammingError from ..queueing import BaseLabellingQueue, _features_to_array from .serialization import data_dumps, data_loads @@ -418,7 +417,7 @@ def drop_table(self, sure=False): # noqa: D001 else: warnings.warn("To actually drop the table, pass sure=True") - def _unlabelled_count(self): + def _unlabelled_count(self) -> int: with self.session() as session: return ( session.query(self.data) @@ -429,7 +428,7 @@ def _unlabelled_count(self): .count() ) - def _labelled_count(self): + def _labelled_count(self) -> int: with self.session() as session: return ( session.query(self.data) diff --git a/src/superintendent/distributed/multioutput.py b/superintendent/distributed/multioutput.py similarity index 100% rename from src/superintendent/distributed/multioutput.py rename to superintendent/distributed/multioutput.py diff --git a/src/superintendent/distributed/semisupervisor.py b/superintendent/distributed/semisupervisor.py similarity index 85% rename from src/superintendent/distributed/semisupervisor.py rename to superintendent/distributed/semisupervisor.py index e5ad84f9..44cde824 100644 --- a/src/superintendent/distributed/semisupervisor.py +++ b/superintendent/distributed/semisupervisor.py @@ -1,7 +1,8 @@ """Tools to supervise classification.""" import time -from typing import Optional +from math import inf +from typing import Optional, Union import ipywidgets as widgets import traitlets @@ -12,6 +13,7 @@ # # from . import base from .. import semisupervisor +from .._compatibility import ignore_widget_on_submit_warning from .dbqueue import DatabaseQueue @@ -108,7 +110,7 @@ def _get_worker_id(self): placeholder="Please enter your name or ID." ) self.layout.children = [ - widgets.HTML("

Please enter your name:

"), + widgets.HTML(value="

Please enter your name:

"), widgets.Box( children=[worker_id_field], layout=widgets.Layout( @@ -120,7 +122,8 @@ def _get_worker_id(self): ), ), ] - worker_id_field.on_submit(self._set_worker_id) + with ignore_widget_on_submit_warning(): + worker_id_field.on_submit(self._set_worker_id) def _set_worker_id(self, worker_id_field): if len(worker_id_field.value) > 0: @@ -129,27 +132,33 @@ def _set_worker_id(self, worker_id_field): def _run_orchestration( self, - interval_seconds: int = 30, - interval_n_labels: Optional[int] = 0, + interval_seconds: float = 60, + interval_n_labels: int = 0, shuffle_prop: float = 0.1, - ): + ) -> bool: + + first_orchestration = not hasattr(self, "_last_n_labelled") + + if first_orchestration: + self._last_n_labelled = 0 - if ( - not hasattr(self, "_last_n_labelled") - or interval_n_labels - >= self.queue._labelled_count() - self._last_n_labelled - ): - self._last_n_labelled = self.queue._labelled_count + n_new_labels = self.queue._labelled_count() - self._last_n_labelled + if first_orchestration or n_new_labels >= interval_n_labels: + self._last_n_labelled += n_new_labels self.shuffle_prop = shuffle_prop self.retrain() print(self.model_performance.value) time.sleep(interval_seconds) + return True + else: + return False def orchestrate( self, - interval_seconds: Optional[int] = 60, - interval_n_labels: Optional[int] = 0, + interval_seconds: Optional[float] = None, + interval_n_labels: int = 0, shuffle_prop: float = 0.1, + max_runs: Union[int, float] = inf, ): """Orchestrate the active learning process. @@ -170,11 +179,12 @@ def orchestrate( shuffle_prop : float What proportion of the data should be randomly sampled on each re- training run. + max_runs : int + How many orchestration runs to do at most. Returns ------- None - """ if interval_seconds is None: self._run_orchestration( @@ -183,8 +193,9 @@ def orchestrate( shuffle_prop=shuffle_prop, ) else: - while True: # pragma: no cover - self._run_orchestration( + runs = 0 + while runs < max_runs: + runs += self._run_orchestration( interval_seconds=interval_seconds, interval_n_labels=interval_n_labels, shuffle_prop=shuffle_prop, diff --git a/src/superintendent/distributed/serialization.py b/superintendent/distributed/serialization.py similarity index 100% rename from src/superintendent/distributed/serialization.py rename to superintendent/distributed/serialization.py diff --git a/src/superintendent/multioutput/__init__.py b/superintendent/multioutput/__init__.py similarity index 100% rename from src/superintendent/multioutput/__init__.py rename to superintendent/multioutput/__init__.py diff --git a/src/superintendent/multioutput/multilabeller.py b/superintendent/multioutput/multilabeller.py similarity index 100% rename from src/superintendent/multioutput/multilabeller.py rename to superintendent/multioutput/multilabeller.py index dade8e3d..5d906600 100644 --- a/src/superintendent/multioutput/multilabeller.py +++ b/superintendent/multioutput/multilabeller.py @@ -4,8 +4,8 @@ from sklearn.multioutput import MultiOutputClassifier from sklearn.preprocessing import MultiLabelBinarizer -from . import prioritisation from .. import controls, semisupervisor +from . import prioritisation class MultiLabeller(semisupervisor.SemiSupervisor): diff --git a/src/superintendent/multioutput/prioritisation.py b/superintendent/multioutput/prioritisation.py similarity index 100% rename from src/superintendent/multioutput/prioritisation.py rename to superintendent/multioutput/prioritisation.py diff --git a/src/superintendent/prioritisation.py b/superintendent/prioritisation.py similarity index 100% rename from src/superintendent/prioritisation.py rename to superintendent/prioritisation.py diff --git a/src/superintendent/queueing.py b/superintendent/queueing.py similarity index 83% rename from src/superintendent/queueing.py rename to superintendent/queueing.py index 5f8c877e..32d75a18 100644 --- a/src/superintendent/queueing.py +++ b/superintendent/queueing.py @@ -4,7 +4,7 @@ from collections import defaultdict, deque, namedtuple from functools import reduce from random import shuffle -from typing import Any, Dict, Set +from typing import Any, DefaultDict, Deque, Dict, List, Optional, Set, Tuple import numpy as np import pandas as pd @@ -12,35 +12,122 @@ class BaseLabellingQueue(abc.ABC): # pragma: no cover @abc.abstractmethod - def enqueue(self): + def enqueue(self, feature: Any, label: Optional[Any] = None) -> None: + """Add a data point to the queue. + + Parameters + ---------- + feature : Any + A data point to be added to the queue + label : str, list, optional + The label, if you already have one (the default is None) + + Returns + ------- + None + """ pass @abc.abstractmethod - def pop(self): + def pop(self) -> Tuple[int, Any]: + """Pop an item off the queue. + + Returns + ------- + int + The ID of the item just popped + Any + The item itself. + """ pass @abc.abstractmethod - def submit(self): + def submit(self, id_: int, label: str) -> None: + """Label a data point. + + Parameters + ---------- + id_ : int + The ID of the datapoint to submit a label for + label : str + The label to apply for the data point + + Raises + ------ + ValueError + If you attempt to label an item that hasn't been popped in this + queue. + + Returns + ------- + None + """ pass @abc.abstractmethod - def reorder(self): + def reorder(self, new_order: Dict[int, int]) -> None: + """Reorder the data still in the queue + + Parameters + ---------- + new_order : Dict[int, int] + A mapping from ID of an item to the order of the item. For example, + a dictionary {1: 2, 2: 1, 3: 3} would place the item with ID 2 + first, then the item with id 1, then the item with ID 3. + + Returns + ------- + None + """ pass @abc.abstractmethod - def undo(self): + def undo(self) -> None: + """Un-pop the latest item. + + Returns + ------- + None + """ pass @abc.abstractmethod def list_completed(self): + """List all items with a label. + + Returns + ------- + ids : List[int] + The IDs of the returned items. + x : Any + The data points that have labels. + y : Any + The labels. + """ pass @abc.abstractmethod def list_uncompleted(self): + """List all items without a label. + + Returns + ------- + ids : List[int] + The IDs of the returned items. + x : Any + The data points that don't have labels. + """ pass @abc.abstractmethod def list_labels(self): + """List all the labels. + + Returns + ------- + Set[str] + All the labels. + """ pass @abc.abstractmethod @@ -70,16 +157,16 @@ def __init__(self, features: Any = None, labels: Any = None): (the default is None). """ - self.data = dict() - self.labels = dict() + self.data: Dict[int, Any] = dict() + self.labels: Dict[int, Any] = dict() - self.order = deque([]) - self._popped = deque([]) + self.order: Deque[int] = deque([]) + self._popped: Deque[int] = deque([]) if features is not None: self.enqueue_many(features, labels) - def enqueue(self, feature, label=None) -> None: + def enqueue(self, feature: Any, label: Optional[Any] = None) -> None: """Add a data point to the queue. Parameters @@ -131,7 +218,7 @@ def enqueue_many(self, features: Any, labels=None) -> None: for feature, label in zip(features, labels): self.enqueue(feature, label) - def pop(self) -> (int, Any): + def pop(self) -> Tuple[int, Any]: """Pop an item off the queue. Returns @@ -201,8 +288,9 @@ def shuffle(self) -> None: ------- None """ - - shuffle(self.order) + _order = list(self.order) + shuffle(_order) + self.order = deque(_order) def undo(self) -> None: """Un-pop the latest item. @@ -340,12 +428,14 @@ def __init__( membership, or a similar metric. """ - self.data = defaultdict(list) - self.representativeness = defaultdict(list) - self.cluster_labels = dict() + self.data: DefaultDict[Any, List[Any]] = defaultdict(list) + self.representativeness: DefaultDict[Any, List[Any]] = defaultdict( + list + ) + self.cluster_labels: Dict[Any, str] = dict() - self.order = deque([]) - self._popped = deque([]) + self.order: Deque[int] = deque([]) + self._popped: Deque[int] = deque([]) if features is not None: self.enqueue_many(features, cluster_indices, representativeness) @@ -452,9 +542,11 @@ def reorder(self): def shuffle(self) -> None: """Shuffle the queue.""" - shuffle(self.order) + _order = list(self.order) + shuffle(_order) + self.order = deque(_order) - def undo(self): + def undo(self) -> None: """Unpop the most recently popped item.""" if len(self._popped) > 0: cluster_index = self._popped.pop() diff --git a/src/superintendent/semisupervisor.py b/superintendent/semisupervisor.py similarity index 99% rename from src/superintendent/semisupervisor.py rename to superintendent/semisupervisor.py index b1081ccc..debf78da 100644 --- a/src/superintendent/semisupervisor.py +++ b/superintendent/semisupervisor.py @@ -111,7 +111,7 @@ def __init__( icon="refresh", ) self.retrain_button.on_click(self.retrain) - self.model_performance = widgets.HTML("") + self.model_performance = widgets.HTML(value="") self.top_bar.children = ( widgets.HBox( [*self.top_bar.children], diff --git a/src/superintendent/validation.py b/superintendent/validation.py similarity index 100% rename from src/superintendent/validation.py rename to superintendent/validation.py diff --git a/tests/conftest.py b/tests/conftest.py index 602f8173..29df745f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -4,9 +4,9 @@ import sys if sys.platform == "darwin": # noqa - import matplotlib # noqa + import matplotlib # isort:skip - matplotlib.use("PS") # noqa + matplotlib.use("PS") # isort:skip import warnings import collections @@ -48,10 +48,17 @@ def exact_element_match(a, b): elif isinstance(a, pd.DataFrame) and isinstance(b, pd.DataFrame): a = a.reset_index(drop=True) b = b.reset_index(drop=True) - return ((a == b) | (a.isnull() & b.isnull())).all().all() or a.empty or b.empty + return ( + ((a == b) | (a.isnull() & b.isnull())).all().all() + or a.empty + or b.empty + ) else: return all( - [a_ == b_ or (np.isnan(a_) and np.isnan(b_)) for a_, b_ in zip(a, b)] + [ + a_ == b_ or (np.isnan(a_) and np.isnan(b_)) + for a_, b_ in zip(a, b) + ] ) @@ -60,7 +67,9 @@ def recursively_list_widget_children(parent): childless = [ widget for widget in parent.children if not hasattr(widget, "children") ] - parents = [widget for widget in parent.children if hasattr(widget, "children")] + parents = [ + widget for widget in parent.children if hasattr(widget, "children") + ] for widget in parents: childless += recursively_list_widget_children(widget) diff --git a/tests/test_distributed_semisupervisor.py b/tests/test_distributed_semisupervisor.py index 9bc23fb6..b11c7e45 100644 --- a/tests/test_distributed_semisupervisor.py +++ b/tests/test_distributed_semisupervisor.py @@ -1,13 +1,11 @@ from collections import namedtuple +from time import time +import ipywidgets import numpy as np import pandas as pd -import ipywidgets -from sklearn.model_selection import cross_validate -from sklearn.linear_model import LogisticRegression - import pytest - +import superintendent.prioritisation from hypothesis import given, settings from hypothesis.extra.numpy import ( array_shapes, @@ -28,8 +26,8 @@ recursive, text, ) - -import superintendent.prioritisation +from sklearn.linear_model import LogisticRegression +from sklearn.model_selection import cross_validate from superintendent.distributed import SemiSupervisor primitive_strategy = text() | integers() | floats(allow_nan=False) | booleans() @@ -401,4 +399,50 @@ def test_that_run_orchestration_calls_retrain_and_prints(mocker): mock_retrain.assert_called_once_with() mock_print.assert_called_once_with("test model performance") - mock_sleep.assert_called_once_with(30) + mock_sleep.assert_called_once_with(60) + + +def test_that_run_orchestration_with_none_runs_orchestrator_once(mocker): + + widget = SemiSupervisor() + mocker.patch.object(widget, "_run_orchestration", return_value=1) + + dummy_html_widget = namedtuple("dummy_html_widget", ["value"]) + widget.model_performance = dummy_html_widget( + value="test model performance" + ) + # t0 = time() + widget.orchestrate(interval_seconds=0.1, max_runs=2) + assert widget._run_orchestration.call_count == 2 + + +def test_that_run_orchestration_doesnt_rerun_if_not_enough_new_labels(mocker): + widget = SemiSupervisor() + # patch the nr of provided labels: + mocker.patch.object(widget, "queue") + widget.queue.configure_mock(**{"_labelled_count.side_effect": [0, 5, 10]}) + # patch methods not to be used: + mocker.patch.object(widget, "retrain") + widget.model_performance = mocker.MagicMock( + **{"model_performance.value": "nice"} + ) + # print([widget.queue._labelled_count() for i in range(3)]) + # raise ValueError + widget.orchestrate(max_runs=2, interval_seconds=0, interval_n_labels=10) + + assert widget.queue._labelled_count.call_count == 3 + assert widget.retrain.call_count == 2 + + +def test_that_orchestration_sleeps_enough(mocker): + widget = SemiSupervisor() + # patch methods not to be used: + mocker.patch.object(widget, "retrain") + widget.model_performance = mocker.MagicMock( + **{"model_performance.value": "nice"} + ) + t0 = time() + widget.orchestrate(max_runs=2, interval_seconds=0.01, interval_n_labels=0) + t1 = time() + + assert t1 - t0 > 0.02