├── .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 | --------------------------------------------------------------------------------