├── .editorconfig
├── .github
├── ISSUE_TEMPLATE.md
└── workflows
│ └── python-package.yml
├── .gitignore
├── CONTRIBUTING.rst
├── HISTORY.rst
├── LICENSE
├── MANIFEST.in
├── Makefile
├── README.rst
├── docs
├── Makefile
├── conf.py
├── contributing.rst
├── history.rst
├── index.rst
├── installation.rst
├── make.bat
├── modules.rst
├── stac_nb.rst
└── usage.rst
├── requirements.txt
├── requirements_dev.txt
├── setup.cfg
├── setup.py
├── stac_nb
├── __init__.py
└── stac_nb.py
├── tests
├── __init__.py
├── conftest.py
└── test_stac_nb.py
└── tox.ini
/.editorconfig:
--------------------------------------------------------------------------------
1 | # http://editorconfig.org
2 |
3 | root = true
4 |
5 | [*]
6 | indent_style = space
7 | indent_size = 4
8 | trim_trailing_whitespace = true
9 | insert_final_newline = true
10 | charset = utf-8
11 | end_of_line = lf
12 |
13 | [*.bat]
14 | indent_style = tab
15 | end_of_line = crlf
16 |
17 | [LICENSE]
18 | insert_final_newline = false
19 |
20 | [Makefile]
21 | indent_style = tab
22 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | * stac-nb version:
2 | * Python version:
3 | * Operating System:
4 |
5 | ### Description
6 |
7 | Describe what you were trying to get done.
8 | Tell us what happened, what went wrong, and what you expected to happen.
9 |
10 | ### What I Did
11 |
12 | ```
13 | Paste the command(s) you ran and the output.
14 | If there was a crash, please include the traceback here.
15 | ```
16 |
--------------------------------------------------------------------------------
/.github/workflows/python-package.yml:
--------------------------------------------------------------------------------
1 | # This workflow will install Python dependencies, run tests and lint with a variety of Python versions
2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
3 |
4 | name: builds
5 |
6 | on:
7 | push:
8 | branches: [main]
9 | pull_request:
10 | types: [opened]
11 | branches: [main]
12 |
13 | jobs:
14 | build:
15 | runs-on: ubuntu-latest
16 | strategy:
17 | fail-fast: false
18 | matrix:
19 | python-version: [3.7, 3.8, 3.9]
20 |
21 | steps:
22 | - uses: actions/checkout@v2
23 | - name: Set up Python ${{ matrix.python-version }}
24 | uses: actions/setup-python@v2
25 | with:
26 | python-version: ${{ matrix.python-version }}
27 | - name: Install dependencies
28 | run: |
29 | python -m pip install --upgrade pip
30 | python -m pip install flake8 pytest requests-mock coverage
31 | if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
32 | - name: Lint with flake8
33 | run: |
34 | # stop the build if there are Python syntax errors or undefined names
35 | flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
36 | # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
37 | flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
38 | - name: Test with pytest
39 | run: |
40 | pytest
41 | - name: Run coverage
42 | run: |
43 | coverage run --source stac_nb -m pytest
44 | - name: Coveralls
45 | uses: AndreMiras/coveralls-python-action@develop
46 | with:
47 | parallel: true
48 | flag-name: Unit Test
49 |
50 | coveralls_finish:
51 | needs: build
52 | runs-on: ubuntu-latest
53 | steps:
54 | - name: Coveralls Finished
55 | uses: AndreMiras/coveralls-python-action@develop
56 | with:
57 | parallel-finished: true
58 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | env/
12 | build/
13 | develop-eggs/
14 | dist/
15 | downloads/
16 | eggs/
17 | .eggs/
18 | lib/
19 | lib64/
20 | parts/
21 | sdist/
22 | var/
23 | wheels/
24 | *.egg-info/
25 | .installed.cfg
26 | *.egg
27 |
28 | # PyInstaller
29 | # Usually these files are written by a python script from a template
30 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
31 | *.manifest
32 | *.spec
33 |
34 | # Installer logs
35 | pip-log.txt
36 | pip-delete-this-directory.txt
37 |
38 | # Unit test / coverage reports
39 | htmlcov/
40 | .tox/
41 | .coverage
42 | .coverage.*
43 | .cache
44 | nosetests.xml
45 | coverage.xml
46 | *.cover
47 | .hypothesis/
48 | .pytest_cache/
49 |
50 | # Translations
51 | *.mo
52 | *.pot
53 |
54 | # Django stuff:
55 | *.log
56 | local_settings.py
57 |
58 | # Flask stuff:
59 | instance/
60 | .webassets-cache
61 |
62 | # Scrapy stuff:
63 | .scrapy
64 |
65 | # Sphinx documentation
66 | docs/_build/
67 |
68 | # PyBuilder
69 | target/
70 |
71 | # Jupyter Notebook
72 | .ipynb_checkpoints
73 |
74 | # pyenv
75 | .python-version
76 |
77 | # celery beat schedule file
78 | celerybeat-schedule
79 |
80 | # SageMath parsed files
81 | *.sage.py
82 |
83 | # dotenv
84 | .env
85 |
86 | # virtualenv
87 | .venv
88 | venv/
89 | ENV/
90 |
91 | # Spyder project settings
92 | .spyderproject
93 | .spyproject
94 |
95 | # Rope project settings
96 | .ropeproject
97 |
98 | # mkdocs documentation
99 | /site
100 |
101 | # mypy
102 | .mypy_cache/
103 |
104 | # IDE settings
105 | .vscode/
106 | .idea/
107 |
--------------------------------------------------------------------------------
/CONTRIBUTING.rst:
--------------------------------------------------------------------------------
1 | .. highlight:: shell
2 |
3 | ============
4 | Contributing
5 | ============
6 |
7 | Contributions are welcome, and they are greatly appreciated! Every little bit
8 | helps, and credit will always be given.
9 |
10 | You can contribute in many ways:
11 |
12 | Types of Contributions
13 | ----------------------
14 |
15 | Report Bugs
16 | ~~~~~~~~~~~
17 |
18 | Report bugs at https://github.com/darrenwiens/stac-nb/issues.
19 |
20 | If you are reporting a bug, please include:
21 |
22 | * Your operating system name and version.
23 | * Any details about your local setup that might be helpful in troubleshooting.
24 | * Detailed steps to reproduce the bug.
25 |
26 | Fix Bugs
27 | ~~~~~~~~
28 |
29 | Look through the GitHub issues for bugs. Anything tagged with "bug" and "help
30 | wanted" is open to whoever wants to implement it.
31 |
32 | Implement Features
33 | ~~~~~~~~~~~~~~~~~~
34 |
35 | Look through the GitHub issues for features. Anything tagged with "enhancement"
36 | and "help wanted" is open to whoever wants to implement it.
37 |
38 | Write Documentation
39 | ~~~~~~~~~~~~~~~~~~~
40 |
41 | stac-nb could always use more documentation, whether as part of the
42 | official stac-nb docs, in docstrings, or even on the web in blog posts,
43 | articles, and such.
44 |
45 | Submit Feedback
46 | ~~~~~~~~~~~~~~~
47 |
48 | The best way to send feedback is to file an issue at https://github.com/darrenwiens/stac-nb/issues.
49 |
50 | If you are proposing a feature:
51 |
52 | * Explain in detail how it would work.
53 | * Keep the scope as narrow as possible, to make it easier to implement.
54 | * Remember that this is a volunteer-driven project, and that contributions
55 | are welcome :)
56 |
57 | Get Started!
58 | ------------
59 |
60 | Ready to contribute? Here's how to set up `stac_nb` for local development.
61 |
62 | 1. Fork the `stac_nb` repo on GitHub.
63 | 2. Clone your fork locally::
64 |
65 | $ git clone git@github.com:your_name_here/stac_nb.git
66 |
67 | 3. Install your local copy into a virtualenv. Assuming you have virtualenvwrapper installed, this is how you set up your fork for local development::
68 |
69 | $ mkvirtualenv stac_nb
70 | $ cd stac_nb/
71 | $ python setup.py develop
72 |
73 | 4. Create a branch for local development::
74 |
75 | $ git checkout -b name-of-your-bugfix-or-feature
76 |
77 | Now you can make your changes locally.
78 |
79 | 5. When you're done making changes, check that your changes pass flake8 and the
80 | tests, including testing other Python versions with tox::
81 |
82 | $ flake8 stac_nb tests
83 | $ python setup.py test or pytest
84 | $ tox
85 |
86 | To get flake8 and tox, just pip install them into your virtualenv.
87 |
88 | 6. Commit your changes and push your branch to GitHub::
89 |
90 | $ git add .
91 | $ git commit -m "Your detailed description of your changes."
92 | $ git push origin name-of-your-bugfix-or-feature
93 |
94 | 7. Submit a pull request through the GitHub website.
95 |
96 | Pull Request Guidelines
97 | -----------------------
98 |
99 | Before you submit a pull request, check that it meets these guidelines:
100 |
101 | 1. The pull request should include tests.
102 | 2. If the pull request adds functionality, the docs should be updated. Put
103 | your new functionality into a function with a docstring, and add the
104 | feature to the list in README.rst.
105 |
106 | Tips
107 | ----
108 |
109 | To run a subset of tests::
110 |
111 | $ pytest tests.test_stac_nb
112 |
113 |
114 | Deploying
115 | ---------
116 |
117 | A reminder for the maintainers on how to deploy.
118 | Make sure all your changes are committed (including an entry in HISTORY.rst).
119 | Then run::
120 |
121 | $ bump2version patch # possible: major / minor / patch
122 | $ git push
123 | $ git push --tags
124 |
--------------------------------------------------------------------------------
/HISTORY.rst:
--------------------------------------------------------------------------------
1 | History
2 | =======
3 |
4 | 0.1.0 (2021-10-02)
5 | ------------------
6 |
7 | * First release on PyPI.
8 |
9 | 0.2.0 (2021-10-04)
10 | ------------------
11 |
12 | * Added: optional filter by ids
13 | * Added: optional print STAC query
14 | * Updated: docs
15 |
16 | 0.3.0 (2021-10-06)
17 | ------------------
18 |
19 | * Breaking Change: ``ui.query_results`` is now a list of ``pystac.item.Item``
20 | * Added: automate builds and tests
21 |
22 | 0.4.0 (2021-10-08)
23 | ------------------
24 |
25 | * Breaking Change: ``ui.query_results`` is now a ``VisualList``
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021, Darren Wiens
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include CONTRIBUTING.rst
2 | include HISTORY.rst
3 | include LICENSE
4 | include README.rst
5 |
6 | recursive-include tests *
7 | recursive-exclude * __pycache__
8 | recursive-exclude * *.py[co]
9 |
10 | recursive-include docs *.rst conf.py Makefile make.bat *.jpg *.png *.gif
11 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: clean clean-test clean-pyc clean-build docs help
2 | .DEFAULT_GOAL := help
3 |
4 | define BROWSER_PYSCRIPT
5 | import os, webbrowser, sys
6 |
7 | from urllib.request import pathname2url
8 |
9 | webbrowser.open("file://" + pathname2url(os.path.abspath(sys.argv[1])))
10 | endef
11 | export BROWSER_PYSCRIPT
12 |
13 | define PRINT_HELP_PYSCRIPT
14 | import re, sys
15 |
16 | for line in sys.stdin:
17 | match = re.match(r'^([a-zA-Z_-]+):.*?## (.*)$$', line)
18 | if match:
19 | target, help = match.groups()
20 | print("%-20s %s" % (target, help))
21 | endef
22 | export PRINT_HELP_PYSCRIPT
23 |
24 | BROWSER := python -c "$$BROWSER_PYSCRIPT"
25 |
26 | help:
27 | @python -c "$$PRINT_HELP_PYSCRIPT" < $(MAKEFILE_LIST)
28 |
29 | clean: clean-build clean-pyc clean-test ## remove all build, test, coverage and Python artifacts
30 |
31 | clean-build: ## remove build artifacts
32 | rm -fr build/
33 | rm -fr dist/
34 | rm -fr .eggs/
35 | find . -name '*.egg-info' -exec rm -fr {} +
36 |
37 |
38 | clean-pyc: ## remove Python file artifacts
39 | find . -name '*.pyc' -exec rm -f {} +
40 | find . -name '*.pyo' -exec rm -f {} +
41 | find . -name '*~' -exec rm -f {} +
42 | find . -name '__pycache__' -exec rm -fr {} +
43 |
44 | clean-test: ## remove test and coverage artifacts
45 | rm -fr .tox/
46 | rm -f .coverage
47 | rm -fr htmlcov/
48 | rm -fr .pytest_cache
49 |
50 | lint/flake8: ## check style with flake8
51 | flake8 stac_nb tests
52 | lint/black: ## check style with black
53 | black --check stac_nb tests
54 |
55 | lint: lint/flake8 lint/black ## check style
56 |
57 | test: ## run tests quickly with the default Python
58 | pytest
59 |
60 | test-all: ## run tests on every Python version with tox
61 | tox
62 |
63 | coverage: ## check code coverage quickly with the default Python
64 | coverage run --source stac_nb -m pytest
65 | coverage report -m
66 | coverage html
67 | $(BROWSER) htmlcov/index.html
68 |
69 | docs: ## generate Sphinx HTML documentation, including API docs
70 | rm -f docs/stac_nb.rst
71 | rm -f docs/modules.rst
72 | sphinx-apidoc -o docs/ stac_nb
73 | $(MAKE) -C docs clean
74 | $(MAKE) -C docs html
75 | $(BROWSER) docs/_build/html/index.html
76 |
77 | servedocs: docs ## compile the docs watching for changes
78 | watchmedo shell-command -p '*.rst' -c '$(MAKE) -C docs html' -R -D .
79 |
80 | release: dist ## package and upload a release
81 | twine upload dist/*
82 |
83 | test-release: dist ## package and upload a release to TestPypi
84 | twine upload --repository testpypi dist/*
85 |
86 | dist: clean ## builds source and wheel package
87 | python setup.py sdist
88 | python setup.py bdist_wheel
89 | ls -l dist
90 |
91 | install: clean ## install the package to the active Python's site-packages
92 | python setup.py install
93 |
--------------------------------------------------------------------------------
/README.rst:
--------------------------------------------------------------------------------
1 | stac-nb
2 | =================
3 |
4 | STAC in Jupyter Notebooks
5 | -------------------------
6 |
7 | .. image:: https://readthedocs.org/projects/stac-nb/badge/?version=latest&style=flat
8 | :target: https://stac-nb.readthedocs.io/en/latest/?badge=latest
9 | :alt: Documentation Status
10 | .. image:: https://badge.fury.io/py/stac-nb.svg
11 | :target: https://badge.fury.io/py/stac-nb
12 | :alt: PyPI Status
13 | .. image:: https://coveralls.io/repos/github/darrenwiens/stac-nb/badge.svg?branch=main
14 | :target: https://coveralls.io/github/darrenwiens/stac-nb?branch=main
15 | .. image:: https://github.com/darrenwiens/stac-nb/actions/workflows/python-package.yml/badge.svg
16 | :alt: Build Status
17 |
18 | Install
19 | -------------------------
20 | ::
21 |
22 | pip install stac-nb
23 |
24 | Usage
25 | -------------------------
26 |
27 | .. usage_label
28 |
29 | To use stac-nb in a project, start Jupyter Lab (``jupyter lab``), create a new notebook, then::
30 |
31 | from stac_nb import STAC_Query_UI
32 |
33 | Display the UI for a STAC API::
34 |
35 | ui = STAC_Query_UI("https://earth-search.aws.element84.com/v0")
36 | ui.display()
37 |
38 | After you have run the query, retrieve the results from ``ui.query_results``::
39 |
40 | ui.query_results
41 |
42 | The statement above will render a visual list component, including an interactive map and a
43 | multitude of other richly stylized elements.
44 |
45 | The list of pystac.Items returned from the query may be used further in Python, like::
46 |
47 | list(ui.query_results)
48 |
--------------------------------------------------------------------------------
/docs/Makefile:
--------------------------------------------------------------------------------
1 | # Minimal makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line.
5 | SPHINXOPTS =
6 | SPHINXBUILD = python -msphinx
7 | SPHINXPROJ = stac_nb
8 | SOURCEDIR = .
9 | BUILDDIR = _build
10 |
11 | # Put it first so that "make" without argument is like "make help".
12 | help:
13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
14 |
15 | .PHONY: help Makefile
16 |
17 | # Catch-all target: route all unknown targets to Sphinx using the new
18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
19 | %: Makefile
20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
21 |
--------------------------------------------------------------------------------
/docs/conf.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # stac_nb documentation build configuration file, created by
4 | # sphinx-quickstart on Fri Jun 9 13:47:02 2017.
5 | #
6 | # This file is execfile()d with the current directory set to its
7 | # containing dir.
8 | #
9 | # Note that not all possible configuration values are present in this
10 | # autogenerated file.
11 | #
12 | # All configuration values have a default; values that are commented out
13 | # serve to show the default.
14 |
15 | # If extensions (or modules to document with autodoc) are in another
16 | # directory, add these directories to sys.path here. If the directory is
17 | # relative to the documentation root, use os.path.abspath to make it
18 | # absolute, like shown here.
19 | #
20 | import os
21 | import sys
22 | sys.path.insert(0, os.path.abspath('..'))
23 |
24 | import stac_nb
25 |
26 | # -- General configuration ---------------------------------------------
27 |
28 | # If your documentation needs a minimal Sphinx version, state it here.
29 | #
30 | # needs_sphinx = '1.0'
31 |
32 | # Add any Sphinx extension module names here, as strings. They can be
33 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
34 | extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode']
35 |
36 | # Add any paths that contain templates here, relative to this directory.
37 | templates_path = ['_templates']
38 |
39 | # The suffix(es) of source filenames.
40 | # You can specify multiple suffix as a list of string:
41 | #
42 | # source_suffix = ['.rst', '.md']
43 | source_suffix = '.rst'
44 |
45 | # The master toctree document.
46 | master_doc = 'index'
47 |
48 | # General information about the project.
49 | project = 'stac-nb'
50 | copyright = "2021, Darren Wiens"
51 | author = "Darren Wiens"
52 |
53 | # The version info for the project you're documenting, acts as replacement
54 | # for |version| and |release|, also used in various other places throughout
55 | # the built documents.
56 | #
57 | # The short X.Y version.
58 | version = stac_nb.__version__
59 | # The full version, including alpha/beta/rc tags.
60 | release = stac_nb.__version__
61 |
62 | # The language for content autogenerated by Sphinx. Refer to documentation
63 | # for a list of supported languages.
64 | #
65 | # This is also used if you do content translation via gettext catalogs.
66 | # Usually you set "language" from the command line for these cases.
67 | language = None
68 |
69 | # List of patterns, relative to source directory, that match files and
70 | # directories to ignore when looking for source files.
71 | # This patterns also effect to html_static_path and html_extra_path
72 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
73 |
74 | # The name of the Pygments (syntax highlighting) style to use.
75 | pygments_style = 'sphinx'
76 |
77 | # If true, `todo` and `todoList` produce output, else they produce nothing.
78 | todo_include_todos = False
79 |
80 |
81 | # -- Options for HTML output -------------------------------------------
82 |
83 | # The theme to use for HTML and HTML Help pages. See the documentation for
84 | # a list of builtin themes.
85 | #
86 | html_theme = 'alabaster'
87 |
88 | # Theme options are theme-specific and customize the look and feel of a
89 | # theme further. For a list of options available for each theme, see the
90 | # documentation.
91 | #
92 | # html_theme_options = {}
93 |
94 | # Add any paths that contain custom static files (such as style sheets) here,
95 | # relative to this directory. They are copied after the builtin static files,
96 | # so a file named "default.css" will overwrite the builtin "default.css".
97 | html_static_path = ['_static']
98 |
99 |
100 | # -- Options for HTMLHelp output ---------------------------------------
101 |
102 | # Output file base name for HTML help builder.
103 | htmlhelp_basename = 'stac_nbdoc'
104 |
105 |
106 | # -- Options for LaTeX output ------------------------------------------
107 |
108 | latex_elements = {
109 | # The paper size ('letterpaper' or 'a4paper').
110 | #
111 | # 'papersize': 'letterpaper',
112 |
113 | # The font size ('10pt', '11pt' or '12pt').
114 | #
115 | # 'pointsize': '10pt',
116 |
117 | # Additional stuff for the LaTeX preamble.
118 | #
119 | # 'preamble': '',
120 |
121 | # Latex figure (float) alignment
122 | #
123 | # 'figure_align': 'htbp',
124 | }
125 |
126 | # Grouping the document tree into LaTeX files. List of tuples
127 | # (source start file, target name, title, author, documentclass
128 | # [howto, manual, or own class]).
129 | latex_documents = [
130 | (master_doc, 'stac_nb.tex',
131 | 'stac-nb Documentation',
132 | 'Darren Wiens', 'manual'),
133 | ]
134 |
135 |
136 | # -- Options for manual page output ------------------------------------
137 |
138 | # One entry per manual page. List of tuples
139 | # (source start file, name, description, authors, manual section).
140 | man_pages = [
141 | (master_doc, 'stac_nb',
142 | 'stac-nb Documentation',
143 | [author], 1)
144 | ]
145 |
146 |
147 | # -- Options for Texinfo output ----------------------------------------
148 |
149 | # Grouping the document tree into Texinfo files. List of tuples
150 | # (source start file, target name, title, author,
151 | # dir menu entry, description, category)
152 | texinfo_documents = [
153 | (master_doc, 'stac_nb',
154 | 'stac-nb Documentation',
155 | author,
156 | 'stac_nb',
157 | 'One line description of project.',
158 | 'Miscellaneous'),
159 | ]
160 |
161 |
162 |
163 |
--------------------------------------------------------------------------------
/docs/contributing.rst:
--------------------------------------------------------------------------------
1 | .. include:: ../CONTRIBUTING.rst
2 |
--------------------------------------------------------------------------------
/docs/history.rst:
--------------------------------------------------------------------------------
1 | .. include:: ../HISTORY.rst
2 |
--------------------------------------------------------------------------------
/docs/index.rst:
--------------------------------------------------------------------------------
1 | Welcome to stac-nb's documentation!
2 | ======================================
3 |
4 | .. toctree::
5 | :maxdepth: 2
6 | :caption: Contents:
7 |
8 | readme
9 | installation
10 | usage
11 | modules
12 | contributing
13 | history
14 |
15 | Indices and tables
16 | ==================
17 | * :ref:`genindex`
18 | * :ref:`modindex`
19 | * :ref:`search`
20 |
--------------------------------------------------------------------------------
/docs/installation.rst:
--------------------------------------------------------------------------------
1 | .. highlight:: shell
2 |
3 | ============
4 | Installation
5 | ============
6 |
7 |
8 | Stable release
9 | --------------
10 |
11 | To install stac-nb, run this command in your terminal:
12 |
13 | .. code-block:: console
14 |
15 | $ pip install stac-nb
16 |
17 | This is the preferred method to install stac-nb, as it will always install the most recent stable release.
18 |
19 | If you don't have `pip`_ installed, this `Python installation guide`_ can guide
20 | you through the process.
21 |
22 | .. _pip: https://pip.pypa.io
23 | .. _Python installation guide: http://docs.python-guide.org/en/latest/starting/installation/
24 |
25 |
26 | From sources
27 | ------------
28 |
29 | The sources for stac-nb can be downloaded from the `Github repo`_.
30 |
31 | You can either clone the public repository:
32 |
33 | .. code-block:: console
34 |
35 | $ git clone git://github.com/darrenwiens/stac-nb
36 |
37 | Or download the `tarball`_:
38 |
39 | .. code-block:: console
40 |
41 | $ curl -OJL https://github.com/darrenwiens/stac-nb/tarball/master
42 |
43 | Once you have a copy of the source, you can install it with:
44 |
45 | .. code-block:: console
46 |
47 | $ python setup.py install
48 |
49 |
50 | .. _Github repo: https://github.com/darrenwiens/stac-nb
51 | .. _tarball: https://github.com/darrenwiens/stac-nb/tarball/master
52 |
--------------------------------------------------------------------------------
/docs/make.bat:
--------------------------------------------------------------------------------
1 | @ECHO OFF
2 |
3 | pushd %~dp0
4 |
5 | REM Command file for Sphinx documentation
6 |
7 | if "%SPHINXBUILD%" == "" (
8 | set SPHINXBUILD=python -msphinx
9 | )
10 | set SOURCEDIR=.
11 | set BUILDDIR=_build
12 | set SPHINXPROJ=stac_nb
13 |
14 | if "%1" == "" goto help
15 |
16 | %SPHINXBUILD% >NUL 2>NUL
17 | if errorlevel 9009 (
18 | echo.
19 | echo.The Sphinx module was not found. Make sure you have Sphinx installed,
20 | echo.then set the SPHINXBUILD environment variable to point to the full
21 | echo.path of the 'sphinx-build' executable. Alternatively you may add the
22 | echo.Sphinx directory to PATH.
23 | echo.
24 | echo.If you don't have Sphinx installed, grab it from
25 | echo.http://sphinx-doc.org/
26 | exit /b 1
27 | )
28 |
29 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
30 | goto end
31 |
32 | :help
33 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
34 |
35 | :end
36 | popd
37 |
--------------------------------------------------------------------------------
/docs/modules.rst:
--------------------------------------------------------------------------------
1 | stac_nb
2 | =======
3 |
4 | .. toctree::
5 | :maxdepth: 4
6 |
7 | stac_nb
8 |
--------------------------------------------------------------------------------
/docs/stac_nb.rst:
--------------------------------------------------------------------------------
1 | stac\_nb package
2 | ================
3 |
4 | Submodules
5 | ----------
6 |
7 | stac\_nb.stac\_nb module
8 | ------------------------
9 |
10 | .. automodule:: stac_nb.stac_nb
11 | :members:
12 | :undoc-members:
13 | :show-inheritance:
14 |
15 |
16 | Module contents
17 | ---------------
18 |
19 | .. automodule:: stac_nb
20 | :members:
21 | :undoc-members:
22 | :show-inheritance:
23 |
--------------------------------------------------------------------------------
/docs/usage.rst:
--------------------------------------------------------------------------------
1 | Usage
2 | =====
3 |
4 | .. include:: ../README.rst
5 | :start-after: .. usage_label
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | ipywidgets>=7.6.5
2 | pystac-client>=0.3.0
3 |
--------------------------------------------------------------------------------
/requirements_dev.txt:
--------------------------------------------------------------------------------
1 | pip==19.2.3
2 | bump2version==0.5.11
3 | wheel==0.33.6
4 | watchdog==0.9.0
5 | flake8==3.7.8
6 | tox==3.14.0
7 | coverage==5.2.1
8 | requests-mock==1.9.3
9 | Sphinx==1.8.5
10 | twine==1.14.0
11 |
12 | pytest==6.2.4
13 | black==21.7b0
14 |
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | [bumpversion]
2 | current_version = 0.4.0
3 | commit = True
4 | tag = True
5 |
6 | [bumpversion:file:setup.py]
7 | search = version="{current_version}"
8 | replace = version="{new_version}"
9 |
10 | [bumpversion:file:stac_nb/__init__.py]
11 | search = __version__ = "{current_version}"
12 | replace = __version__ = "{new_version}"
13 |
14 | [bdist_wheel]
15 | universal = 1
16 |
17 | [coverage:run]
18 | relative_files = True
19 |
20 | [flake8]
21 | exclude = docs, tests/conftest.py
22 | max-line-length = 100
23 |
24 | [tool:pytest]
25 | collect_ignore = ['setup.py']
26 |
27 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | """The setup script."""
4 |
5 | import io
6 | import os
7 | from setuptools import setup, find_packages
8 |
9 | with open("README.rst") as readme_file:
10 | readme = readme_file.read()
11 |
12 | with open("HISTORY.rst") as history_file:
13 | history = history_file.read()
14 |
15 | cwd = os.path.abspath(os.path.dirname(__file__))
16 | with io.open(os.path.join(cwd, "requirements.txt"), encoding="utf-8") as f:
17 | all_reqs = f.read().split("\n")
18 |
19 | install_requires = [x.strip() for x in all_reqs]
20 |
21 | test_requirements = [
22 | "pytest>=3",
23 | ]
24 |
25 | setup(
26 | author="Darren Wiens",
27 | author_email="dkwiens@gmail.com",
28 | python_requires=">=3.6",
29 | classifiers=[
30 | "Development Status :: 2 - Pre-Alpha",
31 | "Intended Audience :: Developers",
32 | "License :: OSI Approved :: MIT License",
33 | "Natural Language :: English",
34 | "Programming Language :: Python :: 3",
35 | "Programming Language :: Python :: 3.6",
36 | "Programming Language :: Python :: 3.7",
37 | "Programming Language :: Python :: 3.8",
38 | ],
39 | description="stac-nb exposes STAC in Jupyter Notebooks",
40 | install_requires=install_requires,
41 | license="MIT license",
42 | long_description=readme + "\n\n" + history,
43 | include_package_data=True,
44 | keywords="stac_nb",
45 | name="stac_nb",
46 | packages=find_packages(include=["stac_nb", "stac_nb.*"]),
47 | test_suite="tests",
48 | tests_require=test_requirements,
49 | url="https://github.com/darrenwiens/stac-nb",
50 | project_urls={
51 | "Documentation": "https://stac-nb.readthedocs.io",
52 | "Source": "https://github.com/darrenwiens/stac-nb",
53 | "Tracker": "https://github.com/darrenwiens/stac-nb/issues",
54 | },
55 | version="0.4.0",
56 | zip_safe=False,
57 | )
58 |
--------------------------------------------------------------------------------
/stac_nb/__init__.py:
--------------------------------------------------------------------------------
1 | """Top-level package for stac-nb."""
2 |
3 | __author__ = """Darren Wiens"""
4 | __email__ = "dkwiens@gmail.com"
5 | __version__ = "0.4.0"
6 |
7 | from .stac_nb import STAC_Query_UI, VisualList # noqa: F401
8 |
--------------------------------------------------------------------------------
/stac_nb/stac_nb.py:
--------------------------------------------------------------------------------
1 | from IPython.display import display as iDisplay
2 | import ipywidgets as widgets
3 | from pystac_client import Client
4 | import json
5 |
6 | # This class is a proxy to visualize STAC responses nicely in Jupyter
7 | # To show the actual list or dict in Jupyter, use repr() or print()
8 |
9 |
10 | class VisualList(list):
11 |
12 | def __init__(self, data: list):
13 | list.__init__(self, data)
14 |
15 | def _repr_html_(self):
16 | # Construct HTML, but load Vue Components source files only if the
17 | # openEO HTML tag is not yet defined
18 | return """
19 |
26 |
27 |
28 |
29 | """.format(
30 | props=json.dumps({'items': [i.to_dict() for i in self], 'show-map': True})
31 | )
32 |
33 |
34 | class STAC_Query_UI(widgets.VBox):
35 | def __init__(self, stac_api: str, headers: dict = None, **kwargs):
36 | super().__init__(**kwargs)
37 | self.client = Client.open(stac_api, headers=headers)
38 | self.query_results = None
39 |
40 | collection_ids = [c.id for c in self.client.get_all_collections()]
41 |
42 | self.collections_w = widgets.SelectMultiple(
43 | options=collection_ids,
44 | description="Collection(s):",
45 | disabled=False,
46 | layout={
47 | "width": "95%",
48 | },
49 | )
50 |
51 | self.limit_w = widgets.BoundedIntText(
52 | value=10,
53 | min=0,
54 | max=1000,
55 | step=1,
56 | description="Limit:",
57 | disabled=False,
58 | layout={
59 | "width": "95%",
60 | },
61 | )
62 |
63 | self.ids_w = widgets.Textarea(
64 | placeholder="Comma delimited list of IDs",
65 | description="ID(s):",
66 | disabled=False,
67 | layout={
68 | "width": "95%",
69 | },
70 | )
71 |
72 | self.bbox_w = widgets.Text(
73 | placeholder="Comma delimited list of bounds (order: W, S, E, N)",
74 | description="BBox:",
75 | disabled=False,
76 | layout={
77 | "width": "95%",
78 | },
79 | )
80 |
81 | self.start_date_w = widgets.DatePicker(description="Start Date", disabled=False)
82 |
83 | self.end_date_w = widgets.DatePicker(description="End Date", disabled=False)
84 |
85 | self.show_query_w = widgets.Checkbox(
86 | value=False,
87 | description="Print query",
88 | disabled=False,
89 | indent=False,
90 | )
91 |
92 | self.query_btn_w = widgets.Button(
93 | description="Run Query",
94 | disabled=False,
95 | button_style="",
96 | tooltip="Run Query",
97 | icon="check",
98 | )
99 |
100 | self.response_text = widgets.Output()
101 |
102 | self.query_btn_w.on_click(self.click_button)
103 |
104 | common_widgets = widgets.VBox([self.collections_w, self.limit_w, self.ids_w])
105 | spatial_widgets = widgets.VBox([self.bbox_w])
106 | temporal_widgets = widgets.VBox([self.start_date_w, self.end_date_w])
107 |
108 | children = [common_widgets, spatial_widgets, temporal_widgets]
109 | tab = widgets.Tab()
110 | tab.children = children
111 | titles = ["Common", "Spatial", "Temporal"]
112 | for i in range(len(titles)):
113 | tab.set_title(i, str(titles[i]))
114 |
115 | self.children = [tab, self.show_query_w, self.query_btn_w, self.response_text]
116 |
117 | def display(self):
118 | iDisplay(self)
119 |
120 | def click_button(self, b):
121 | start_datetime = self.start_date_w.value or "1900-01-01T00:00:00Z"
122 | end_datetime = self.end_date_w.value or "2900-01-01T00:00:00Z"
123 |
124 | payload_dict = dict(
125 | collections=self.collections_w.value,
126 | datetime=f"{start_datetime}/{end_datetime}",
127 | max_items=self.limit_w.value,
128 | )
129 |
130 | try:
131 | bbox = [float(i) for i in self.bbox_w.value.split(",")]
132 | except ValueError:
133 | bbox = []
134 |
135 | if len(bbox) != 4:
136 | payload_dict["bbox"] = [-180, -90, 180, 90]
137 | else:
138 | payload_dict["bbox"] = bbox
139 |
140 | ids = self.ids_w.value
141 | if ids is not None and len(ids) > 0:
142 | payload_dict["ids"] = [x.strip(" ") for x in ids.split(",")]
143 |
144 | query_response = self.client.search(**payload_dict)
145 |
146 | self.query_results = VisualList(query_response.get_items())
147 |
148 | with self.response_text:
149 | if self.show_query_w.value:
150 | print(f"QUERY: {vars(query_response)}")
151 | print(f"MATCHES: {len(self.query_results)}")
152 |
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
1 | """Unit test package for stac_nb."""
2 |
--------------------------------------------------------------------------------
/tests/conftest.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | from pystac_client.item_search import ItemSearch
3 |
4 |
5 | STAC_API = "https://api/endpoint"
6 |
7 |
8 | @pytest.fixture(autouse=True)
9 | def mock_responses(
10 | requests_mock,
11 | landing_page_response,
12 | collections_response,
13 | collection_response,
14 | search_response,
15 | ):
16 |
17 | requests_mock.get(f"{STAC_API}", json=landing_page_response)
18 | requests_mock.get(f"{STAC_API}/collections", json=collections_response)
19 | requests_mock.get(
20 | f"{STAC_API}/collections/simple-collection", json=collection_response
21 | )
22 | requests_mock.post(f"{STAC_API}/search", json=search_response)
23 |
24 |
25 | @pytest.fixture(scope="module")
26 | def landing_page_response():
27 | return {
28 | "stac_version": "1.0.0",
29 | "stac_api_version": "0.9.0",
30 | "type": "Catalog",
31 | "id": "stac-server",
32 | "title": "STAC API",
33 | "description": "Test STAC API",
34 | "links": [
35 | {
36 | "rel": "child",
37 | "href": "https://api/endpoint/collections/simple-collection",
38 | },
39 | {
40 | "rel": "service-desc",
41 | "type": "application/vnd.oai.openapi+json;version=3.0",
42 | "href": "https://api/endpoint/api",
43 | },
44 | {
45 | "rel": "conformance",
46 | "type": "application/json",
47 | "href": "https://api/endpoint/conformance",
48 | },
49 | {
50 | "rel": "data",
51 | "type": "application/json",
52 | "href": "https://api/endpoint/collections",
53 | },
54 | {
55 | "rel": "self",
56 | "type": "application/json",
57 | "href": "https://api/endpoint/",
58 | },
59 | {
60 | "rel": "search",
61 | "type": "application/geo+json",
62 | "href": "https://api/endpoint/search",
63 | },
64 | {"rel": "docs", "href": "https://stac-utils.github.io/stac-server/"},
65 | ],
66 | "conformsTo": [
67 | "https://api.stacspec.org/v1.0.0-beta.2/core",
68 | "https://api.stacspec.org/v1.0.0-beta.2/item-search",
69 | "https://api.stacspec.org/v1.0.0-beta.2/item-search#fields",
70 | "https://api.stacspec.org/v1.0.0-beta.2/item-search#sort",
71 | "https://api.stacspec.org/v1.0.0-beta.2/item-search#query",
72 | "http://www.opengis.net/spec/ogcapi-features-1/1.0/conf/core",
73 | "http://www.opengis.net/spec/ogcapi-features-1/1.0/conf/oas30",
74 | "http://www.opengis.net/spec/ogcapi-features-1/1.0/conf/geojson",
75 | ],
76 | }
77 |
78 |
79 | @pytest.fixture(scope="module")
80 | def collections_response(collection_response):
81 | return {"collections": [collection_response]}
82 |
83 |
84 | @pytest.fixture(scope="module")
85 | def collection_response():
86 | return {
87 | "id": "simple-collection",
88 | "type": "Collection",
89 | "stac_extensions": [
90 | "https://stac-extensions.github.io/eo/v1.0.0/schema.json",
91 | "https://stac-extensions.github.io/projection/v1.0.0/schema.json",
92 | "https://stac-extensions.github.io/view/v1.0.0/schema.json",
93 | ],
94 | "stac_version": "1.0.0",
95 | "description": "A simple collection demonstrating core catalog fields with links to a couple of items",
96 | "title": "Simple Example Collection",
97 | "providers": [
98 | {
99 | "name": "Remote Data, Inc",
100 | "description": "Producers of awesome spatiotemporal assets",
101 | "roles": ["producer", "processor"],
102 | "url": "http://remotedata.io",
103 | }
104 | ],
105 | "extent": {
106 | "spatial": {
107 | "bbox": [
108 | [
109 | 172.91173669923782,
110 | 1.3438851951615003,
111 | 172.95469614953714,
112 | 1.3690476620161975,
113 | ]
114 | ]
115 | },
116 | "temporal": {
117 | "interval": [["2020-12-11T22:38:32.125Z", "2020-12-14T18:02:31.437Z"]]
118 | },
119 | },
120 | "license": "CC-BY-4.0",
121 | "summaries": {
122 | "platform": ["cool_sat1", "cool_sat2"],
123 | "constellation": ["ion"],
124 | "instruments": ["cool_sensor_v1", "cool_sensor_v2"],
125 | "gsd": {"minimum": 0.512, "maximum": 0.66},
126 | "eo:cloud_cover": {"minimum": 1.2, "maximum": 1.2},
127 | "proj:epsg": {"minimum": 32659, "maximum": 32659},
128 | "view:sun_elevation": {"minimum": 54.9, "maximum": 54.9},
129 | "view:off_nadir": {"minimum": 3.8, "maximum": 3.8},
130 | "view:sun_azimuth": {"minimum": 135.7, "maximum": 135.7},
131 | },
132 | "links": [
133 | {
134 | "rel": "root",
135 | "href": "./collection.json",
136 | "type": "application/json",
137 | "title": "Simple Example Collection",
138 | },
139 | {
140 | "rel": "item",
141 | "href": "./simple-item.json",
142 | "type": "application/geo+json",
143 | "title": "Simple Item",
144 | },
145 | {
146 | "rel": "item",
147 | "href": "./core-item.json",
148 | "type": "application/geo+json",
149 | "title": "Core Item",
150 | },
151 | {
152 | "rel": "item",
153 | "href": "./extended-item.json",
154 | "type": "application/geo+json",
155 | "title": "Extended Item",
156 | },
157 | {
158 | "rel": "self",
159 | "href": "https://raw.githubusercontent.com/radiantearth/stac-spec/v1.0.0/examples/collection.json",
160 | "type": "application/json",
161 | },
162 | ],
163 | }
164 |
165 |
166 | @pytest.fixture(scope="module")
167 | def search_response():
168 | return {
169 | "type": "FeatureCollection",
170 | "stac_version": "1.0.0-beta.2",
171 | "stac_extensions": [],
172 | "context": {"page": 1, "limit": 10, "matched": 3337, "returned": 1},
173 | "numberMatched": 3337,
174 | "numberReturned": 1,
175 | "features": [
176 | {
177 | "stac_version": "1.0.0",
178 | "stac_extensions": [],
179 | "type": "Feature",
180 | "id": "20201211_223832_CS2",
181 | "bbox": [
182 | 172.91173669923782,
183 | 1.3438851951615003,
184 | 172.95469614953714,
185 | 1.3690476620161975,
186 | ],
187 | "geometry": {
188 | "type": "Polygon",
189 | "coordinates": [
190 | [
191 | [172.91173669923782, 1.3438851951615003],
192 | [172.95469614953714, 1.3438851951615003],
193 | [172.95469614953714, 1.3690476620161975],
194 | [172.91173669923782, 1.3690476620161975],
195 | [172.91173669923782, 1.3438851951615003],
196 | ]
197 | ],
198 | },
199 | "properties": {"datetime": "2020-12-11T22:38:32.125000Z"},
200 | "collection": "simple-collection",
201 | "links": [],
202 | "assets": {
203 | "visual": {
204 | "href": "https://storage.googleapis.com/open-cogs/stac-examples/20201211_223832_CS2.tif",
205 | "type": "image/tiff; application=geotiff; profile=cloud-optimized",
206 | "title": "3-Band Visual",
207 | "roles": ["visual"],
208 | },
209 | "thumbnail": {
210 | "href": "https://storage.googleapis.com/open-cogs/stac-examples/20201211_223832_CS2.jpg",
211 | "title": "Thumbnail",
212 | "type": "image/jpeg",
213 | "roles": ["thumbnail"],
214 | },
215 | },
216 | }
217 | ],
218 | }
219 |
--------------------------------------------------------------------------------
/tests/test_stac_nb.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | """Tests for `stac_nb` package."""
4 |
5 | from stac_nb import STAC_Query_UI, VisualList
6 | import pystac
7 |
8 | stac_api = "https://api/endpoint"
9 |
10 |
11 | def test_stac_query_ui(collections_response):
12 | """Test UI initialization."""
13 |
14 | ui = STAC_Query_UI(stac_api)
15 |
16 | assert len(ui.children) == 4
17 | assert ui.query_results is None
18 | assert ui.collections_w.options[0] == collections_response["collections"][0]["id"]
19 |
20 |
21 | def test_display_ui(requests_mock, collection_response):
22 | """Test displaying the UI."""
23 |
24 | ui = STAC_Query_UI(stac_api)
25 | ui.display()
26 |
27 | assert True
28 |
29 |
30 | def test_button_click(search_response):
31 | """Test UI button click."""
32 |
33 | ui = STAC_Query_UI(stac_api)
34 | assert ui.query_results is None
35 |
36 | ui.click_button(ui.query_btn_w)
37 |
38 | assert isinstance(ui.query_results, list)
39 | assert len(ui.query_results) == len(search_response["features"])
40 | assert isinstance(ui.query_results[0], pystac.item.Item)
41 |
42 |
43 | def test_bbox():
44 | """Test sending bbox in query."""
45 |
46 | ui = STAC_Query_UI(stac_api)
47 | assert ui.query_results is None
48 | ui.bbox_w.value = "-123,45,-124,46"
49 |
50 | ui.click_button(ui.query_btn_w)
51 | assert isinstance(ui.query_results, list)
52 |
53 |
54 | def test_ids():
55 | """Test sending ids in query."""
56 |
57 | ui = STAC_Query_UI(stac_api)
58 | assert ui.query_results is None
59 | ui.ids_w.value = "20201211_223832_CS2, another_id"
60 |
61 | ui.click_button(ui.query_btn_w)
62 | assert isinstance(ui.query_results, list)
63 |
64 |
65 | def test_print_query(capfd, search_response):
66 | """Test showing query."""
67 |
68 | ui = STAC_Query_UI(stac_api)
69 | assert ui.query_results is None
70 | ui.show_query_w.value = True
71 |
72 | ui.click_button(ui.query_btn_w)
73 |
74 | out, err = capfd.readouterr()
75 | assert "QUERY" in out
76 | assert f"MATCHES: {len(search_response['features'])}" in out
77 | assert not err
78 |
79 | assert isinstance(ui.query_results, list)
80 |
81 |
82 | def test_visual_list(search_response):
83 | item = pystac.Item.from_dict(search_response["features"][0])
84 |
85 | visual_list = VisualList([item])
86 |
87 | assert len(visual_list) == 1
88 | assert isinstance(visual_list._repr_html_(), str)
89 |
--------------------------------------------------------------------------------
/tox.ini:
--------------------------------------------------------------------------------
1 | [tox]
2 | envlist = py36, py37, py38, flake8
3 |
4 | [testenv:flake8]
5 | basepython = python
6 | deps = flake8
7 | commands = flake8 stac_nb tests
8 |
9 | [testenv]
10 | setenv =
11 | PYTHONPATH = {toxinidir}
12 | deps =
13 | -r{toxinidir}/requirements_dev.txt
14 | ; If you want to make tox run the tests with the same versions, create a
15 | ; requirements.txt with the pinned versions and uncomment the following line:
16 | ; -r{toxinidir}/requirements.txt
17 | commands =
18 | pip install -U pip
19 | pytest --basetemp={envtmpdir}
20 |
21 |
--------------------------------------------------------------------------------