├── .codespellignore ├── .dockerignore ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── PULL_REQUEST_TEMPLATE.MD ├── dependabot.yml ├── setup │ └── action.yml └── workflows │ ├── continuous-integration.yml │ └── release.yml ├── .gitignore ├── .pre-commit-config.yaml ├── .readthedocs.yml ├── CHANGELOG.md ├── LICENSE ├── MANIFEST.in ├── README.md ├── RELEASING.md ├── docker ├── Dockerfile ├── build ├── console ├── debug ├── docs-server ├── env ├── format ├── notebook ├── pull ├── stac └── test ├── docs ├── Makefile ├── _static │ ├── landsat-8-example-polygon.png │ ├── landsat-8-example.png │ ├── modis.png │ ├── sentinel-2-partial-data-only.png │ ├── sentinel-2-partial.png │ └── stactools.png ├── api.rst ├── cli.rst ├── conf.py ├── footprint.rst ├── index.rst └── make.bat ├── environment.yml ├── pyproject.toml ├── scripts ├── format ├── install-min-requirements ├── lint ├── notebook ├── publish ├── rewrite_test_data.py ├── stac ├── test └── update ├── src └── stactools │ ├── cli │ ├── __init__.py │ ├── __main__.py │ ├── cli.py │ ├── commands │ │ ├── __init__.py │ │ ├── add.py │ │ ├── add_asset.py │ │ ├── add_raster.py │ │ ├── copy.py │ │ ├── create.py │ │ ├── info.py │ │ ├── layout.py │ │ ├── lint.py │ │ ├── merge.py │ │ ├── migrate.py │ │ ├── summary.py │ │ ├── update_extent.py │ │ ├── update_geometry.py │ │ ├── validate.py │ │ └── version.py │ ├── py.typed │ └── registry.py │ ├── core │ ├── __init__.py │ ├── add.py │ ├── add_asset.py │ ├── add_raster.py │ ├── copy.py │ ├── create.py │ ├── geometry.py │ ├── io │ │ ├── __init__.py │ │ └── xml.py │ ├── layout.py │ ├── merge.py │ ├── migrate.py │ ├── projection.py │ ├── py.typed │ └── utils │ │ ├── __init__.py │ │ ├── antimeridian.py │ │ ├── convert.py │ │ ├── raster_footprint.py │ │ ├── round.py │ │ └── subprocess.py │ └── testing │ ├── __init__.py │ ├── cli.py │ ├── cli_test.py │ ├── py.typed │ └── test_data.py └── tests ├── __init__.py ├── cli ├── __init__.py └── commands │ ├── __init__.py │ ├── test_add.py │ ├── test_add_asset.py │ ├── test_add_raster.py │ ├── test_cases.py │ ├── test_copy.py │ ├── test_create.py │ ├── test_info.py │ ├── test_lint.py │ ├── test_merge.py │ ├── test_migrate.py │ ├── test_summary.py │ ├── test_update_extent.py │ ├── test_update_geometry.py │ ├── test_validate.py │ └── test_version.py ├── conftest.py ├── core ├── __init__.py ├── test_add_asset.py ├── test_add_raster.py ├── test_create.py ├── test_io.py ├── test_projection.py └── utils │ ├── __init__.py │ ├── test_antimeridian.py │ ├── test_convert.py │ ├── test_raster_footprint.py │ └── test_round.py ├── data-files ├── basic │ ├── catalog.json │ ├── country-1 │ │ ├── area-1-1 │ │ │ ├── area-1-1-imagery │ │ │ │ ├── area-1-1-imagery-invalid.json │ │ │ │ └── area-1-1-imagery.json │ │ │ ├── area-1-1-labels │ │ │ │ └── area-1-1-labels.json │ │ │ ├── collection-invalid.json │ │ │ └── collection.json │ │ ├── area-1-2 │ │ │ ├── area-1-2-imagery │ │ │ │ └── area-1-2-imagery.json │ │ │ ├── area-1-2-labels │ │ │ │ └── area-1-2-labels.json │ │ │ └── collection.json │ │ └── catalog.json │ └── country-2 │ │ ├── area-2-1 │ │ ├── area-2-1-imagery │ │ │ └── area-2-1-imagery.json │ │ ├── area-2-1-labels │ │ │ └── area-2-1-labels.json │ │ └── collection.json │ │ ├── area-2-2 │ │ ├── area-2-2-imagery │ │ │ └── area-2-2-imagery.json │ │ ├── area-2-2-labels │ │ │ └── area-2-2-labels.json │ │ └── collection.json │ │ └── catalog.json ├── catalogs │ └── collection-assets │ │ ├── catalog.json │ │ └── sentinel-2 │ │ ├── collection.json │ │ └── metadata.xml ├── core │ ├── byte.tif │ └── simple-item.json ├── external-child │ └── catalog.json ├── hdf │ └── AMSR_E_L3_RainGrid_B05_200707.h5 ├── linting │ ├── 20201211_223832_cs2.json │ └── core-item.json ├── planet-disaster-v1.0.0-beta.2 │ ├── collection.json │ └── hurricane-harvey │ │ ├── catalog.json │ │ └── hurricane-harvey-0831 │ │ ├── 20170831_162740_ssc1d1 │ │ └── 20170831_162740_ssc1d1.json │ │ ├── 20170831_172754_101c │ │ └── 20170831_172754_101c.json │ │ ├── 20170831_195425_SS02 │ │ └── 20170831_195425_SS02.json │ │ ├── 2017831_195552_SS02 │ │ └── 2017831_195552_SS02.json │ │ ├── Houston-East-20170831-103f-100d-0f4f-RGB │ │ └── Houston-East-20170831-103f-100d-0f4f-RGB.json │ │ └── catalog.json ├── planet-disaster │ ├── collection.json │ └── hurricane-harvey │ │ ├── catalog.json │ │ └── hurricane-harvey-0831 │ │ ├── 20170831_162740_ssc1d1 │ │ ├── 20170831_162740_ssc1d1.json │ │ ├── SkySat_Freeport_s03_20170831T162740Z.png │ │ └── SkySat_Freeport_s03_20170831T162740Z.tif │ │ ├── 20170831_172754_101c │ │ ├── 20170831_172754_101c.json │ │ ├── 20170831_172754_101c_3B_AnalyticMS.tif │ │ ├── 20170831_172754_101c_3B_AnalyticMS_DN_udm.tif │ │ ├── 20170831_172754_101c_3B_AnalyticMS_metadata.xml │ │ ├── 20170831_172754_101c_3b_Visual.tif │ │ └── 20170831_172754_101c_thumb_large.png │ │ ├── 20170831_195425_SS02 │ │ ├── 20170831_195425_SS02.json │ │ ├── SkySat_PortArthur_s02_20170831T195425Z.png │ │ └── SkySat_PortArthur_s02_20170831T195425Z.tif │ │ ├── 2017831_195552_SS02 │ │ ├── 2017831_195552_SS02.json │ │ ├── SkySat_20170831T195552Z_RGB.png │ │ ├── SkySat_20170831T195552Z_RGB.tif │ │ └── SkySat_20170831T195552Z_RGB_Corrected.jpg │ │ ├── Houston-East-20170831-103f-100d-0f4f-RGB │ │ ├── Houston-East-20170831-103f-100d-0f4f-3-band.png │ │ ├── Houston-East-20170831-103f-100d-0f4f-3-band.tif │ │ └── Houston-East-20170831-103f-100d-0f4f-RGB.json │ │ └── catalog.json ├── raster_footprint │ ├── AST_L1T_00310012006175412_20150516104359-SWIR-cropped.tif │ ├── LC08_L1TP_198029_20220331_20220406_02_T1_B2.TIF │ ├── LC08_L1TP_198029_20220331_20220406_02_T1_B2.json │ ├── LC08_LST_crop.tif │ ├── MCD43A4.A2001055.h25v06.006.2016113010159.json │ ├── MCD43A4.A2001055.h25v06.006.2016113010159_B01.TIF │ ├── S2A_OPER_MSI_L2A_TL_ATOS_20220620T162319_A036527_T32TLS_N04.00.json │ ├── S2A_OPER_MSI_L2A_TL_ATOS_20220620T162319_A036527_T32TLS_N04.00_R60m_B01.jp2 │ ├── S2B_OPER_MSI_L2A_TL_2BPS_20220618T135630_A027590_T32TLS_N04.00.json │ ├── S2B_OPER_MSI_L2A_TL_2BPS_20220618T135630_A027590_T32TLS_N04.00_R60m_B01.jp2 │ └── aster │ │ ├── AST_L1T_00305032000040446_20150409135350.json │ │ ├── AST_L1T_00305032000040446_20150409135350_78838.SWIR.SIMPLIFIED.tif │ │ ├── AST_L1T_00305032000040446_20150409135350_78838.TIR.SIMPLIFIED.tif │ │ └── AST_L1T_00305032000040446_20150409135350_78838.VNIR.SIMPLIFIED.tif └── training │ ├── acc │ ├── 665946 │ │ └── 665946.json │ ├── 665946-labels │ │ └── 665946-labels.json │ ├── a42435-labels │ │ └── a42435-labels.json │ ├── a42435 │ │ └── a42435.json │ ├── ca041a-labels │ │ └── ca041a-labels.json │ ├── ca041a │ │ └── ca041a.json │ ├── collection.json │ ├── d41d81-labels │ │ └── d41d81-labels.json │ └── d41d81 │ │ └── d41d81.json │ ├── catalog.json │ ├── dar │ ├── 353093 │ │ └── 353093.json │ ├── 0a4c40-labels │ │ └── 0a4c40-labels.json │ ├── 0a4c40 │ │ └── 0a4c40.json │ ├── 353093-labels │ │ └── 353093-labels.json │ ├── 42f235-labels │ │ └── 42f235-labels.json │ ├── 42f235 │ │ └── 42f235.json │ ├── a017f9-labels │ │ └── a017f9-labels.json │ ├── a017f9 │ │ └── a017f9.json │ ├── b15fce-labels │ │ └── b15fce-labels.json │ ├── b15fce │ │ └── b15fce.json │ ├── collection.json │ ├── f883a0-labels │ │ └── f883a0-labels.json │ └── f883a0 │ │ └── f883a0.json │ ├── kam │ ├── 4e7c7f-labels │ │ └── 4e7c7f-labels.json │ ├── 4e7c7f │ │ └── 4e7c7f.json │ └── collection.json │ ├── mon │ ├── 401175 │ │ └── 401175.json │ ├── 493701 │ │ └── 493701.json │ ├── 207cc7-labels │ │ └── 207cc7-labels.json │ ├── 207cc7 │ │ └── 207cc7.json │ ├── 401175-labels │ │ └── 401175-labels.json │ ├── 493701-labels │ │ └── 493701-labels.json │ ├── collection.json │ ├── f15272-labels │ │ └── f15272-labels.json │ └── f15272 │ │ └── f15272.json │ ├── nia │ ├── 825a50-labels │ │ └── 825a50-labels.json │ ├── 825a50 │ │ └── 825a50.json │ └── collection.json │ ├── ptn │ ├── abe1a3-labels │ │ └── abe1a3-labels.json │ ├── abe1a3 │ │ └── abe1a3.json │ ├── collection.json │ ├── f49f31-labels │ │ └── f49f31-labels.json │ └── f49f31 │ │ └── f49f31.json │ └── znz │ ├── 425403 │ └── 425403.json │ ├── 06f252-labels │ └── 06f252-labels.json │ ├── 06f252 │ └── 06f252.json │ ├── 076995-labels │ └── 076995-labels.json │ ├── 076995 │ └── 076995.json │ ├── 33cae6-labels │ └── 33cae6-labels.json │ ├── 33cae6 │ └── 33cae6.json │ ├── 3b20d4-labels │ └── 3b20d4-labels.json │ ├── 3b20d4 │ └── 3b20d4.json │ ├── 3f8360-labels │ └── 3f8360-labels.json │ ├── 3f8360 │ └── 3f8360.json │ ├── 425403-labels │ └── 425403-labels.json │ ├── 75cdfa-labels │ └── 75cdfa-labels.json │ ├── 75cdfa │ └── 75cdfa.json │ ├── 9b8638-labels │ └── 9b8638-labels.json │ ├── 9b8638 │ └── 9b8638.json │ ├── aee7fd-labels │ └── aee7fd-labels.json │ ├── aee7fd │ └── aee7fd.json │ ├── bc32f1-labels │ └── bc32f1-labels.json │ ├── bc32f1 │ └── bc32f1.json │ ├── bd5c14-labels │ └── bd5c14-labels.json │ ├── bd5c14 │ └── bd5c14.json │ ├── c7415c-labels │ └── c7415c-labels.json │ ├── c7415c │ └── c7415c.json │ ├── collection.json │ ├── e52478-labels │ └── e52478-labels.json │ └── e52478 │ └── e52478.json ├── expected └── rasterbands.json └── testing ├── __init__.py └── test_test_data.py /.codespellignore: -------------------------------------------------------------------------------- 1 | alos 2 | ned 3 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | .git/ 2 | tests/*/data-files/external/* 3 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To reproduce** 14 | Steps to reproduce the behavior: 15 | 16 | > Ex. 17 | > 18 | > 1. Install stactools 19 | > 2. Run `scripts/test` 20 | > 3. See error 21 | 22 | **Expected behavior** 23 | A clear and concise description of what you expected to happen. 24 | 25 | **Screenshots and shell session dumps** 26 | If applicable, add session dumps and/or screenshots to help explain your problem. 27 | 28 | > ex. `scripts/lint >> lint_errors.txt` 29 | 30 | **Additional context** 31 | Add any other context about the problem here. 32 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. Ex. I would like to use stac to do [...] 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.MD: -------------------------------------------------------------------------------- 1 | Before you submit a pull request, please fill in the following: 2 | 3 | **Related Issue(s):** 4 | Please add links (if any) to related github issues. 5 | 6 | **Description:** 7 | Please explain the changes you made here. 8 | 9 | **PR checklist:** 10 | 11 | - [ ] Code is formatted (run `scripts/format`). 12 | - [ ] Code lints properly (run `scripts/lint`). 13 | - [ ] Tests pass (run `scripts/test`). 14 | - [ ] Documentation has been updated to reflect changes, if applicable. 15 | - [ ] Changes are added to the [CHANGELOG](../CHANGELOG.md). 16 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "docker" 4 | directory: "/docker" 5 | schedule: 6 | interval: "weekly" 7 | 8 | - package-ecosystem: "github-actions" 9 | directory: "/" 10 | schedule: 11 | interval: "weekly" 12 | -------------------------------------------------------------------------------- /.github/setup/action.yml: -------------------------------------------------------------------------------- 1 | name: Setup 2 | description: Set up the stactools testing environment with conda, pip, and associated caches 3 | inputs: 4 | python-version: 5 | description: Python version to set up w/ conda 6 | required: True 7 | runs: 8 | using: composite 9 | steps: 10 | - name: Set up conda cache 11 | uses: actions/cache@v2 12 | with: 13 | path: ~/conda_pkgs_dir 14 | key: ${{ runner.os }}-conda-${{ hashFiles('environment.yml') }} 15 | restore-keys: ${{ runner.os }}-conda- 16 | - name: Set up pip cache 17 | uses: actions/cache@v2 18 | with: 19 | path: ~/.cache/pip 20 | key: ${{ runner.os }}-pip-${{ hashFiles('pyproject.toml') }} 21 | restore-keys: ${{ runner.os }}-pip- 22 | - name: Set up pre-commit cache 23 | uses: actions/cache@v2 24 | with: 25 | path: ~/.cache/pre-commit 26 | key: ${{ runner.os }}-pre-commit-${{ hashFiles('.pre-commit-config.yaml' )}} 27 | restore-keys: ${{ runner.os }}-pre-commit- 28 | - name: Set up Conda with Python ${{ inputs.python-version }} 29 | uses: conda-incubator/setup-miniconda@v2 30 | with: 31 | auto-update-conda: true 32 | channels: conda-forge 33 | python-version: ${{ inputs.python-version }} 34 | - name: Update Conda's environemnt 35 | run: conda env update -f environment.yml -n test 36 | shell: bash -l {0} 37 | - name: Update pip 38 | run: python -m pip install --upgrade pip 39 | shell: bash -l {0} 40 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | tags: 6 | - "*" 7 | 8 | env: 9 | DOCKER_REGISTRY: ghcr.io 10 | DOCKER_IMAGE_NAME: ${{ github.repository }} 11 | 12 | jobs: 13 | release: 14 | name: release 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v4 18 | 19 | - name: Set up Python 3.x 20 | uses: actions/setup-python@v5 21 | with: 22 | python-version: "3.x" 23 | 24 | - name: Install release dependencies 25 | run: | 26 | python -m pip install --upgrade pip 27 | pip install setuptools wheel twine 28 | 29 | - name: Build and publish package 30 | env: 31 | TWINE_USERNAME: ${{ secrets.PYPI_STACUTILS_USERNAME }} 32 | TWINE_PASSWORD: ${{ secrets.PYPI_STACUTILS_PASSWORD }} 33 | run: | 34 | scripts/publish 35 | docker: 36 | name: docker 37 | permissions: 38 | contents: read 39 | packages: write 40 | runs-on: ubuntu-latest 41 | steps: 42 | - name: Checkout 43 | uses: actions/checkout@v4 44 | - name: Login to GitHub Container Registry 45 | uses: docker/login-action@v3 46 | with: 47 | registry: ${{ env.DOCKER_REGISTRY }} 48 | username: ${{ github.actor }} 49 | password: ${{ secrets.GITHUB_TOKEN }} 50 | - name: Docker meta main 51 | id: meta-main 52 | uses: docker/metadata-action@v5 53 | with: 54 | images: ${{ env.DOCKER_REGISTRY }}/${{ env.DOCKER_IMAGE_NAME }} 55 | flavor: | 56 | latest=true 57 | tags: | 58 | type=pep440,pattern={{version}} 59 | - name: Build and push main 60 | uses: docker/build-push-action@v6 61 | with: 62 | context: . 63 | file: docker/Dockerfile 64 | target: main 65 | push: true 66 | tags: ${{ steps.meta-main.outputs.tags }} 67 | labels: ${{ steps.meta-main.outputs.labels }} 68 | - name: Docker meta dev 69 | id: meta-dev 70 | uses: docker/metadata-action@v5 71 | with: 72 | images: ${{ env.DOCKER_REGISTRY }}/${{ env.DOCKER_IMAGE_NAME }} 73 | flavor: | 74 | latest=true 75 | suffix=-dev,onlatest=true 76 | tags: | 77 | type=pep440,pattern={{version}} 78 | - name: Build and push dev 79 | uses: docker/build-push-action@v6 80 | with: 81 | context: . 82 | file: docker/Dockerfile 83 | target: dev 84 | push: true 85 | tags: ${{ steps.meta-dev.outputs.tags }} 86 | labels: ${{ steps.meta-dev.outputs.labels }} 87 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | # Configuration file for pre-commit (https://pre-commit.com/). 2 | # Please run `pre-commit run --all-files` when adding or changing entries. 3 | 4 | repos: 5 | - repo: https://github.com/charliermarsh/ruff-pre-commit 6 | rev: v0.8.4 7 | hooks: 8 | - id: ruff 9 | args: [--fix, --exit-non-zero-on-fix] 10 | - repo: https://github.com/psf/black 11 | rev: 24.10.0 12 | hooks: 13 | - id: black 14 | - repo: https://github.com/codespell-project/codespell 15 | rev: v2.3.0 16 | hooks: 17 | - id: codespell 18 | args: [--ignore-words=.codespellignore] 19 | types_or: [jupyter, markdown, python, shell] 20 | - repo: https://github.com/PyCQA/doc8 21 | rev: v1.1.2 22 | hooks: 23 | - id: doc8 24 | - repo: https://github.com/pre-commit/mirrors-mypy 25 | rev: v1.14.0 26 | hooks: 27 | - id: mypy 28 | # TODO lint test and scripts too 29 | files: "^src/.*\\.py$" 30 | args: 31 | - --ignore-missing-imports 32 | - --explicit-package-bases 33 | additional_dependencies: 34 | - click != 8.1.0 35 | - numpy 36 | - pyproj 37 | - pystac 38 | - types-requests 39 | -------------------------------------------------------------------------------- /.readthedocs.yml: -------------------------------------------------------------------------------- 1 | # .readthedocs.yml 2 | # Read the Docs configuration file 3 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 4 | 5 | # Required 6 | version: 2 7 | 8 | sphinx: 9 | fail_on_warning: false 10 | 11 | # Optionally build your docs in additional formats such as PDF 12 | formats: 13 | - pdf 14 | 15 | build: 16 | os: ubuntu-20.04 17 | tools: 18 | python: "3.10" 19 | 20 | python: 21 | install: 22 | - method: pip 23 | path: . 24 | extra_requirements: 25 | - docs -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This software is licensed under the Apache 2 license, quoted below. 2 | 3 | Copyright 2020 Azavea [http://www.azavea.com] 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); you may not 6 | use this file except in compliance with the License. You may obtain a copy of 7 | the License at 8 | 9 | [http://www.apache.org/licenses/LICENSE-2.0] 10 | 11 | Unless required by applicable law or agreed to in writing, software 12 | distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13 | WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14 | License for the specific language governing permissions and limitations under 15 | the License. 16 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include src/stactools/cli/py.typed 2 | include src/stactools/core/py.typed 3 | include src/stactools/testing/py.typed 4 | -------------------------------------------------------------------------------- /docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM continuumio/miniconda3 AS base 2 | RUN conda update conda && conda install pip && conda clean -af 3 | WORKDIR /opt/stactools 4 | COPY environment.yml ./ 5 | RUN conda env update -f environment.yml -n base && conda clean -af 6 | # For some pip env vars falsey means enable 7 | ENV PIP_NO_BINARY rasterio 8 | ENV PIP_NO_CACHE_DIR 0 9 | ENTRYPOINT [ "python", "-m", "stactools.cli" ] 10 | 11 | 12 | FROM base as dep_builder 13 | # Some deps must be built (e.g. against the conda GDAL) 14 | RUN apt-get update \ 15 | && apt-get install -y gcc build-essential \ 16 | && rm -rf /var/lib/apt/lists/* 17 | COPY pyproject.toml ./ 18 | COPY src/stactools/core/__init__.py src/stactools/core/ 19 | # Install dependencies but remove the actual package 20 | RUN pip install --prefix=/install .[s3] \ 21 | && rm -r /install/lib/*/site-packages/stactools* 22 | 23 | 24 | FROM base AS dev 25 | # Install make for the docs build 26 | RUN apt-get update \ 27 | && apt-get install -y make build-essential \ 28 | && rm -rf /var/lib/apt/lists/* 29 | COPY --from=dep_builder /install /opt/conda 30 | RUN conda install -c conda-forge pandoc && conda clean -af 31 | COPY . ./ 32 | # pre-commit run --all-files fails w/o this line 33 | RUN git init 34 | RUN pip install -e .[dev,s3] 35 | 36 | 37 | FROM base AS main 38 | COPY --from=dep_builder /install /opt/conda 39 | COPY src ./src 40 | COPY pyproject.toml ./ 41 | RUN pip install .[s3] 42 | -------------------------------------------------------------------------------- /docker/build: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | if [[ -n "${STACTOOLS_DEBUG}" ]]; then 6 | set -x 7 | fi 8 | 9 | source $(dirname "$0")/env 10 | 11 | function usage() { 12 | 13 | echo -n \ 14 | "Usage: $(basename "$0") 15 | Build stactools containers. Must be run from the repository root 16 | 17 | Options: 18 | --no-cache Do not use cache when building the images 19 | --pull Attempt to pull upstream images before building 20 | " 21 | } 22 | 23 | while [[ $# -gt 0 ]] 24 | do 25 | key="$1" 26 | case $key in 27 | --help) 28 | usage 29 | exit 0 30 | shift 31 | ;; 32 | 33 | --no-cache) 34 | NO_CACHE="--no-cache" 35 | shift 36 | ;; 37 | 38 | --pull) 39 | PULL="--pull" 40 | shift 41 | ;; 42 | esac 43 | done 44 | 45 | if [ "${BASH_SOURCE[0]}" = "${0}" ]; then 46 | if [ "${1:-}" = "--help" ]; then 47 | usage 48 | else 49 | docker build $PULL $NO_CACHE --target main -t $DOCKER_REGISTRY/$DOCKER_ORG/$DOCKER_REPO:$DOCKER_TAG -f docker/Dockerfile . 50 | docker build $PULL $NO_CACHE --target dev -t $DOCKER_REGISTRY/$DOCKER_ORG/$DOCKER_REPO:$DOCKER_TAG_DEV -f docker/Dockerfile . 51 | fi 52 | 53 | # Wipe out the debug container if it still exists. It is now obsolete. 54 | if [ "$(docker ps -aqf name=$DOCKER_DEBUG_CONTAINER_NAME)" ]; then 55 | # Container exists 56 | if [ "$(docker ps -qf name=$DOCKER_DEBUG_CONTAINER_NAME)" ]; then 57 | # Container is runnking 58 | echo "Kill debug container" 59 | docker kill $DOCKER_DEBUG_CONTAINER_NAME 60 | fi 61 | echo "Remove debug container" 62 | docker rm -f $DOCKER_DEBUG_CONTAINER_NAME 63 | fi 64 | fi 65 | -------------------------------------------------------------------------------- /docker/console: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | if [[ -n "${STACTOOLS_DEBUG}" ]]; then 6 | set -x 7 | fi 8 | 9 | source $(dirname "$0")/env 10 | 11 | function usage() { 12 | echo -n \ 13 | "Usage: $(basename "$0") 14 | Run a console in a docker container with all prerequisites installed. 15 | " 16 | } 17 | 18 | if [ "${BASH_SOURCE[0]}" = "${0}" ]; then 19 | docker run --rm -it \ 20 | -v `pwd`:/opt/stactools \ 21 | -p 8000:8000 \ 22 | --entrypoint /bin/bash \ 23 | $DOCKER_REGISTRY/$DOCKER_ORG/$DOCKER_REPO:$DOCKER_TAG_DEV 24 | fi 25 | -------------------------------------------------------------------------------- /docker/debug: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | if [[ -n "${STACTOOLS_DEBUG}" ]]; then 6 | set -x 7 | fi 8 | 9 | source $(dirname "$0")/env 10 | 11 | function usage() { 12 | echo -n \ 13 | "Usage: $(basename "$0") 14 | Run a console in a docker container for debugging. 15 | " 16 | } 17 | 18 | if [ "${BASH_SOURCE[0]}" = "${0}" ]; then 19 | if [ "$(docker ps -aqf name=$DOCKER_DEBUG_CONTAINER_NAME)" ]; then 20 | # Container already exists 21 | if [ ! "$(docker ps -qf name=$DOCKER_DEBUG_CONTAINER_NAME)" ]; then 22 | # Container is stopped 23 | echo "Starting debug container" 24 | docker start $DOCKER_DEBUG_CONTAINER_NAME 25 | fi 26 | echo "Attaching debug container" 27 | docker attach $DOCKER_DEBUG_CONTAINER_NAME 28 | else 29 | # Container doesn't exist, run it 30 | echo "Running debug container" 31 | docker run --name $DOCKER_DEBUG_CONTAINER_NAME -it \ 32 | -v `pwd`:/opt/stactools \ 33 | -p 8000:8000 \ 34 | -p 5678:5678 \ 35 | --entrypoint /bin/bash \ 36 | -e NETWORK_DEBUGGING_PORT=5678 \ 37 | $DOCKER_REGISTRY/$DOCKER_ORG/$DOCKER_REPO:$DOCKER_TAG_DEV 38 | fi 39 | fi 40 | -------------------------------------------------------------------------------- /docker/docs-server: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | if [[ -n "${STACTOOLS_DEBUG}" ]]; then 6 | set -x 7 | fi 8 | 9 | source $(dirname "$0")/env 10 | 11 | function usage() { 12 | echo -n \ 13 | "Usage: $(basename "$0") 14 | Build and serve documentation from a docker container with all prerequisites installed. 15 | " 16 | } 17 | 18 | if [ "${BASH_SOURCE[0]}" = "${0}" ]; then 19 | docker run --rm -it \ 20 | -p 8000:8000 \ 21 | -v `pwd`:/opt/stactools \ 22 | -w /opt/stactools/docs \ 23 | --entrypoint /bin/bash \ 24 | $DOCKER_REGISTRY/$DOCKER_ORG/$DOCKER_REPO:$DOCKER_TAG_DEV \ 25 | -c "make livehtml" 26 | fi 27 | -------------------------------------------------------------------------------- /docker/env: -------------------------------------------------------------------------------- 1 | DOCKER_REGISTRY=ghcr.io 2 | DOCKER_ORG=stac-utils 3 | DOCKER_REPO=stactools 4 | DOCKER_TAG=local 5 | DOCKER_TAG_DEV=local-dev 6 | DOCKER_DEBUG_CONTAINER_NAME=stactools-debug 7 | -------------------------------------------------------------------------------- /docker/format: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | if [[ -n "${STACTOOLS_DEBUG}" ]]; then 6 | set -x 7 | fi 8 | 9 | source $(dirname "$0")/env 10 | 11 | function usage() { 12 | echo -n \ 13 | "Usage: $(basename "$0") 14 | Run code formatters in a docker container with all prerequisites installed. 15 | " 16 | } 17 | 18 | if [ "${BASH_SOURCE[0]}" = "${0}" ]; then 19 | docker run --rm -it \ 20 | -v `pwd`:/opt/stactools \ 21 | --entrypoint scripts/format \ 22 | $DOCKER_REGISTRY/$DOCKER_ORG/$DOCKER_REPO:$DOCKER_TAG_DEV 23 | fi 24 | -------------------------------------------------------------------------------- /docker/notebook: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | if [[ -n "${STACTOOLS_DEBUG}" ]]; then 6 | set -x 7 | fi 8 | 9 | source $(dirname "$0")/env 10 | 11 | function usage() { 12 | echo -n \ 13 | "Usage: $(basename "$0") 14 | Launches a Jupyter notebook in a docker container with all prerequisites installed. 15 | " 16 | } 17 | 18 | if [ "${BASH_SOURCE[0]}" = "${0}" ]; then 19 | docker run --rm -it \ 20 | -v `pwd`:/opt/stactools \ 21 | -v ${HOME}/.planet.json:/root/.planet.json:ro \ 22 | --entrypoint jupyter \ 23 | -p 8888:8888 \ 24 | $DOCKER_REGISTRY/$DOCKER_ORG/$DOCKER_REPO:$DOCKER_TAG_DEV \ 25 | notebook \ 26 | --ip=0.0.0.0 \ 27 | --port=8888 \ 28 | --no-browser \ 29 | --allow-root \ 30 | --notebook-dir=/opt/stactools 31 | fi 32 | -------------------------------------------------------------------------------- /docker/pull: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | if [[ -n "${STACTOOLS_DEBUG}" ]]; then 6 | set -x 7 | fi 8 | 9 | source $(dirname "$0")/env 10 | 11 | function usage() { 12 | 13 | echo -n \ 14 | "Usage: $(basename "$0") 15 | Pull stactools container images from registry. Must be run from the repository root 16 | " 17 | } 18 | 19 | if [ "${BASH_SOURCE[0]}" = "${0}" ]; then 20 | if [ "${1:-}" = "--help" ]; then 21 | usage 22 | else 23 | docker pull $DOCKER_REGISTRY/$DOCKER_ORG/$DOCKER_REPO:main 24 | docker tag $DOCKER_REGISTRY/$DOCKER_ORG/$DOCKER_REPO:main $DOCKER_REGISTRY/$DOCKER_ORG/$DOCKER_REPO:$DOCKER_TAG 25 | docker pull $DOCKER_REGISTRY/$DOCKER_ORG/$DOCKER_REPO:main-dev 26 | docker tag $DOCKER_REGISTRY/$DOCKER_ORG/$DOCKER_REPO:main-dev $DOCKER_REGISTRY/$DOCKER_ORG/$DOCKER_REPO:$DOCKER_TAG_DEV 27 | fi 28 | exit 29 | fi 30 | -------------------------------------------------------------------------------- /docker/stac: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | if [[ -n "${STACTOOLS_DEBUG}" ]]; then 6 | set -x 7 | fi 8 | 9 | source $(dirname "$0")/env 10 | 11 | function usage() { 12 | echo -n \ 13 | "Usage: $(basename "$0") 14 | Run the stactools CLI in a docker container. Mounts the source 15 | directory inside the container, so any edits to the repository 16 | will be reflected in the execution. 17 | " 18 | } 19 | 20 | if [ "${BASH_SOURCE[0]}" = "${0}" ]; then 21 | docker run --rm -it \ 22 | -v `pwd`:/opt/stactools \ 23 | $DOCKER_REGISTRY/$DOCKER_ORG/$DOCKER_REPO:$DOCKER_TAG "${@}" 24 | fi 25 | -------------------------------------------------------------------------------- /docker/test: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | if [[ -n "${STACTOOLS_DEBUG}" ]]; then 6 | set -x 7 | fi 8 | 9 | source $(dirname "$0")/env 10 | 11 | function usage() { 12 | echo -n \ 13 | "Usage: $(basename "$0") 14 | Run linting and tests in a docker container with all prerequisites installed. 15 | " 16 | } 17 | 18 | if [ "${BASH_SOURCE[0]}" = "${0}" ]; then 19 | docker run --rm -it \ 20 | -v `pwd`:/opt/stactools \ 21 | --entrypoint scripts/test \ 22 | $DOCKER_REGISTRY/$DOCKER_ORG/$DOCKER_REPO:$DOCKER_TAG_DEV 23 | fi 24 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | SOURCEDIR = . 8 | BUILDDIR = _build 9 | 10 | # Put it first so that "make" without argument is like "make help". 11 | help: 12 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 13 | 14 | livehtml: 15 | sphinx-autobuild --watch ../stactools --host 0.0.0.0 ${SOURCEDIR} $(BUILDDIR)/html -d _build/doctrees 16 | 17 | .PHONY: help Makefile 18 | 19 | # Catch-all target: route all unknown targets to Sphinx using the new 20 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 21 | %: Makefile 22 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 23 | -------------------------------------------------------------------------------- /docs/_static/landsat-8-example-polygon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stac-utils/stactools/8acd72d4d8914b680e747d655e5964cf53280a27/docs/_static/landsat-8-example-polygon.png -------------------------------------------------------------------------------- /docs/_static/landsat-8-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stac-utils/stactools/8acd72d4d8914b680e747d655e5964cf53280a27/docs/_static/landsat-8-example.png -------------------------------------------------------------------------------- /docs/_static/modis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stac-utils/stactools/8acd72d4d8914b680e747d655e5964cf53280a27/docs/_static/modis.png -------------------------------------------------------------------------------- /docs/_static/sentinel-2-partial-data-only.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stac-utils/stactools/8acd72d4d8914b680e747d655e5964cf53280a27/docs/_static/sentinel-2-partial-data-only.png -------------------------------------------------------------------------------- /docs/_static/sentinel-2-partial.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stac-utils/stactools/8acd72d4d8914b680e747d655e5964cf53280a27/docs/_static/sentinel-2-partial.png -------------------------------------------------------------------------------- /docs/_static/stactools.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stac-utils/stactools/8acd72d4d8914b680e747d655e5964cf53280a27/docs/_static/stactools.png -------------------------------------------------------------------------------- /docs/api.rst: -------------------------------------------------------------------------------- 1 | API Reference 2 | ============= 3 | 4 | This is the auto-generated API reference documentation. 5 | 6 | Core 7 | ---- 8 | 9 | The top-level stactools namespace. 10 | 11 | These core functions and classes provide building blocks for working with STAC 12 | catalogs and creating new STAC metadata. 13 | 14 | Input and output 15 | ~~~~~~~~~~~~~~~~ 16 | 17 | .. automodule:: stactools.core.io 18 | :members: 19 | 20 | .. automodule:: stactools.core.io.xml 21 | :members: 22 | 23 | General utilities 24 | ~~~~~~~~~~~~~~~~~ 25 | 26 | .. automodule:: stactools.core.utils 27 | :members: 28 | 29 | Antimeridian support 30 | ~~~~~~~~~~~~~~~~~~~~ 31 | 32 | .. automodule:: stactools.core.utils.antimeridian 33 | :members: 34 | 35 | Converting assets 36 | ~~~~~~~~~~~~~~~~~ 37 | 38 | .. automodule:: stactools.core.utils.convert 39 | :members: 40 | 41 | Running subprocesses 42 | ~~~~~~~~~~~~~~~~~~~~ 43 | 44 | .. automodule:: stactools.core.utils.subprocess 45 | :members: 46 | 47 | Adding items to catalogs 48 | ~~~~~~~~~~~~~~~~~~~~~~~~ 49 | 50 | .. automodule:: stactools.core.add 51 | :members: 52 | 53 | Adding the raster extension 54 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 55 | 56 | .. automodule:: stactools.core.add_raster 57 | :members: 58 | 59 | Copying 60 | ~~~~~~~ 61 | 62 | .. automodule:: stactools.core.copy 63 | :members: 64 | 65 | Creating 66 | ~~~~~~~~ 67 | 68 | .. automodule:: stactools.core.create 69 | :members: 70 | 71 | Laying out STAC catalogs 72 | ~~~~~~~~~~~~~~~~~~~~~~~~ 73 | 74 | .. automodule:: stactools.core.layout 75 | :members: 76 | 77 | Merging 78 | ~~~~~~~ 79 | 80 | .. automodule:: stactools.core.merge 81 | :members: 82 | 83 | Reprojection 84 | ~~~~~~~~~~~~ 85 | 86 | .. automodule:: stactools.core.projection 87 | :members: 88 | 89 | Raster footprint generation 90 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 91 | 92 | .. automodule:: stactools.core.utils.raster_footprint 93 | :members: 94 | 95 | Geometry 96 | ~~~~~~~~ 97 | 98 | .. automodule:: stactools.core.geometry 99 | :members: 100 | 101 | Testing 102 | ------- 103 | 104 | Utilities for tests, usually used in stactools-packages. 105 | 106 | Command line testing 107 | ~~~~~~~~~~~~~~~~~~~~ 108 | 109 | .. automodule:: stactools.testing.cli_test 110 | :members: 111 | 112 | Fetching and using test data 113 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 114 | 115 | .. automodule:: stactools.testing.test_data 116 | :members: 117 | -------------------------------------------------------------------------------- /docs/cli.rst: -------------------------------------------------------------------------------- 1 | .. _cli: 2 | .. highlight:: shell 3 | 4 | 5 | Command line interface (CLI) 6 | ============================ 7 | 8 | ``stactools`` installs :program:`stac` as a command-line entrypoint. 9 | To display all the available commands:: 10 | 11 | $ stac --help 12 | 13 | `stactools-packages `_ can extend the command line interface with their own commands via a plugin mechanism. 14 | For example, you can browse a STAC catalog via a local server running `stac-browser `_ via:: 15 | 16 | $ pip install stactools-browse 17 | $ stac browse catalog.json 18 | 19 | See specific ``stactools-package`` documentation for information about what 20 | commands are available. 21 | 22 | .. note:: 23 | 24 | If you've installed ``stactools`` with AWS S3 support via ``pip install 'stactools[s3]'``, you can enable requester pays via:: 25 | 26 | $ AWS_REQUEST_PAYER='requester' stac copy # ...etc... 27 | 28 | Full documentation 29 | ------------------ 30 | 31 | .. click:: stactools.cli.cli:cli 32 | :prog: stac 33 | :nested: full 34 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | ``stactools`` documentation 2 | ########################### 3 | 4 | ``stactools`` is a library for working with `SpatioTemporal Asset Catalogs (STAC) `_. 5 | It is based on `PySTAC `_. 6 | The ``stactools`` package provides: 7 | 8 | - A core Python API, available via :py:mod:`stactools.core`, which provides 9 | high-level utility functions for working with STAC objects 10 | - A command-line interface, available via the ``stac`` command, e.g.: 11 | 12 | .. code-block:: shell 13 | 14 | $ stac --help 15 | 16 | There are a variety of ``stactools`` packages built for specific datasets or to provide extra functionality. 17 | See the `stactools-packages website `_ and the `stactools-packages Github organization `_ for more information. 18 | 19 | Requirements 20 | ============ 21 | 22 | * `Python 3.10 or greater `_ 23 | 24 | STAC version support 25 | ==================== 26 | 27 | All versions of ``stactools`` support STAC v1.0.0. 28 | 29 | Installation 30 | ============ 31 | 32 | .. code-block:: shell 33 | 34 | $ pip install stactools 35 | 36 | Filesystem I/O is provided by `fsspec `_. 37 | To enable AWS S3 support via `s3fs `_, you can enable it during installation. 38 | 39 | .. code-block:: shell 40 | 41 | $ pip install 'stactools[s3]' 42 | 43 | .. note:: 44 | 45 | If you need to access s3 data via requester pays, use this environment variable: ``AWS_REQUEST_PAYER='requester'``. 46 | 47 | .. toctree:: 48 | :maxdepth: 1 49 | :hidden: 50 | 51 | cli 52 | api 53 | footprint 54 | -------------------------------------------------------------------------------- /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=sphinx-build 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.http://sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /environment.yml: -------------------------------------------------------------------------------- 1 | name: stactools 2 | channels: 3 | - conda-forge 4 | - defaults 5 | dependencies: 6 | - conda-forge::gdal>=3.10 7 | - conda-forge::geos>=3.3 8 | - conda-forge::rasterio>=1.3 9 | - conda-forge::libgdal-hdf5 10 | - conda-forge::libgdal-jp2openjpeg 11 | -------------------------------------------------------------------------------- /scripts/format: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | if [[ -n "${CI}" ]]; then 6 | set -x 7 | fi 8 | 9 | function usage() { 10 | echo -n \ 11 | "Usage: $(basename "$0") 12 | Format code with black 13 | " 14 | } 15 | 16 | if [ "${BASH_SOURCE[0]}" = "${0}" ]; then 17 | if [ "${1:-}" = "--help" ]; then 18 | usage 19 | else 20 | pre-commit run black --all-files 21 | fi 22 | fi 23 | -------------------------------------------------------------------------------- /scripts/install-min-requirements: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | """Installs the minimum version of all stactools dependencies, with pip. 4 | 5 | Assumptions: 6 | - You've installed the development dependencies: `pip install '.[dev]'` 7 | - All of the dependencies in pyproject.toml are specified with `>=` 8 | 9 | For more context on the approach and rationale behind testing against minimum 10 | requirements, see 11 | https://www.gadom.ski/2022/02/18/dependency-protection-with-python-and-github-actions.html. 12 | 13 | """ 14 | 15 | import subprocess 16 | import sys 17 | from pathlib import Path 18 | 19 | from packaging.requirements import Requirement 20 | 21 | assert sys.version_info[0] == 3 22 | if sys.version_info[1] < 11: 23 | import tomli as toml 24 | else: 25 | import tomllib as toml 26 | 27 | 28 | root = Path(__file__).parents[1] 29 | with open(root / "pyproject.toml", "rb") as f: 30 | pyproject_toml = toml.load(f) 31 | requirements = [] 32 | for install_requires in filter( 33 | bool, 34 | (i.strip() for i in pyproject_toml["project"]["dependencies"]), 35 | ): 36 | requirement = Requirement(install_requires) 37 | assert len(requirement.specifier) == 1 38 | specifier = list(requirement.specifier)[0] 39 | assert specifier.operator == ">=" 40 | install_requires = install_requires.replace(">=", "==") 41 | requirements.append(install_requires) 42 | 43 | subprocess.run(["pip", "install", *requirements]) 44 | -------------------------------------------------------------------------------- /scripts/lint: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | if [[ -n "${CI}" ]]; then 6 | set -x 7 | fi 8 | 9 | function usage() { 10 | echo -n \ 11 | "Usage: $(basename "$0") 12 | Execute project linters. 13 | " 14 | } 15 | 16 | if [ "${BASH_SOURCE[0]}" = "${0}" ]; then 17 | if [ "${1:-}" = "--help" ]; then 18 | usage 19 | else 20 | pre-commit run codespell --all-files 21 | pre-commit run doc8 --all-files 22 | pre-commit run ruff --all-files 23 | pre-commit run mypy --all-files 24 | fi 25 | fi 26 | -------------------------------------------------------------------------------- /scripts/notebook: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | if [[ -n "${CI}" ]]; then 6 | set -x 7 | fi 8 | 9 | function usage() { 10 | echo -n \ 11 | "Usage: $(basename "$0") 12 | Launches a Jupyter notebook. 13 | " 14 | } 15 | 16 | if [ "${BASH_SOURCE[0]}" = "${0}" ]; then 17 | if [ "${1:-}" = "--help" ]; then 18 | usage 19 | else 20 | jupyter notebook \ 21 | --ip=0.0.0.0 \ 22 | --port=8888 23 | fi 24 | fi 25 | -------------------------------------------------------------------------------- /scripts/publish: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | if [[ -n "${CI}" ]]; then 6 | set -x 7 | fi 8 | 9 | function usage() { 10 | echo -n \ 11 | "Usage: $(basename "$0") 12 | Publish all stactools packages. 13 | 14 | Options: 15 | --test Publish to test pypi 16 | " 17 | } 18 | 19 | POSITIONAL=() 20 | while [[ $# -gt 0 ]] 21 | do 22 | key="$1" 23 | case $key in 24 | 25 | --help) 26 | usage 27 | exit 0 28 | shift 29 | ;; 30 | 31 | --test) 32 | TEST_PYPI="--repository testpypi" 33 | shift 34 | ;; 35 | 36 | *) # unknown option 37 | POSITIONAL+=("$1") # save it in an array for later 38 | shift # past argument 39 | ;; 40 | esac 41 | done 42 | set -- "${POSITIONAL[@]}" # restore positional parameters 43 | 44 | # Fail if this isn't CI and we aren't publishing to test pypi 45 | if [ -z "${TEST_PYPI}" ] && [ -z "${CI}" ]; then 46 | echo "Only CI can publish to pypi" 47 | exit 1 48 | fi 49 | 50 | if [ "${BASH_SOURCE[0]}" = "${0}" ]; then 51 | rm -rf dist 52 | pip install build twine 53 | python -m build --sdist --wheel 54 | twine upload ${TEST_PYPI} dist/* 55 | fi 56 | -------------------------------------------------------------------------------- /scripts/rewrite_test_data.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | from typing import cast 5 | 6 | import pystac 7 | from dateutil.tz import UTC 8 | from pystac import Collection, Item 9 | 10 | root = os.path.dirname(os.path.dirname(__file__)) 11 | directory = os.path.join(root, "tests", "data-files") 12 | 13 | invalid_file_names = ["area-1-1-imagery-invalid.json"] 14 | 15 | 16 | def remap_property(item: Item, before: str, after: str) -> None: 17 | value = item.properties.pop(before, None) 18 | if value: 19 | item.properties[after] = value 20 | 21 | 22 | collection_id = None 23 | for directory, _, file_names in os.walk(directory): 24 | for file_name in file_names: 25 | if os.path.splitext(file_name)[1] != ".json": 26 | continue 27 | path = os.path.join(directory, file_name) 28 | try: 29 | object = pystac.read_file(path) 30 | except Exception as e: 31 | print(f"FIX REQUIRED: {path}") 32 | raise e 33 | 34 | if object.STAC_OBJECT_TYPE == "Collection": 35 | collection = cast(Collection, object) 36 | collection_id = collection.id 37 | for i, interval in enumerate(collection.extent.temporal.intervals): 38 | for j, datetime in enumerate(interval): 39 | if datetime: 40 | collection.extent.temporal.intervals[i][j] = ( 41 | datetime.astimezone(UTC) 42 | ) 43 | 44 | if object.STAC_OBJECT_TYPE == "Feature": 45 | item = cast(Item, object) 46 | remap_property(item, "label:property", "label:properties") 47 | remap_property(item, "label:method", "label:methods") 48 | remap_property(item, "label:task", "label:tasks") 49 | remap_property(item, "proj:epsg_code", "proj:epsg") 50 | remap_property(item, "eo:epsg", "proj:epsg") 51 | remap_property(item, "eo:off_nadir", "view:off_nadir") 52 | remap_property(item, "eo:sun_azimuth", "view:sun_azimuth") 53 | remap_property(item, "eo:sun_elevation", "view:sun_elevation") 54 | 55 | if item.collection_id is None and item.get_single_link("collection"): 56 | item.collection_id = collection_id 57 | 58 | for key, asset in item.assets.items(): 59 | bands = asset.extra_fields.pop("eo:bands", None) 60 | if bands: 61 | item.assets[key].extra_fields["eo:bands"] = [ 62 | {"name": str(band)} for band in bands 63 | ] 64 | 65 | if file_name not in invalid_file_names: 66 | try: 67 | object.validate() 68 | except Exception as e: 69 | print(f"FIX REQUIRED: {path}") 70 | raise e 71 | object.save_object(include_self_link=False, dest_href=path) 72 | -------------------------------------------------------------------------------- /scripts/stac: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | if [[ -n "${CI}" ]]; then 6 | set -x 7 | fi 8 | 9 | if [ "${BASH_SOURCE[0]}" = "${0}" ]; then 10 | python -m stactools.cli "$@" 11 | fi 12 | -------------------------------------------------------------------------------- /scripts/test: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | if [[ -n "${CI}" ]]; then 6 | set -x 7 | fi 8 | 9 | function usage() { 10 | echo -n \ 11 | "Usage: $(basename "$0") 12 | Execute project linters and test suites. 13 | " 14 | } 15 | 16 | if [ "${BASH_SOURCE[0]}" = "${0}" ]; then 17 | if [ "${1:-}" = "--help" ]; then 18 | usage 19 | else 20 | ./scripts/lint 21 | ./scripts/format 22 | 23 | pytest --cov=stactools tests/ 24 | coverage xml 25 | fi 26 | fi 27 | -------------------------------------------------------------------------------- /scripts/update: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | if [[ -n "${CI}" ]]; then 6 | set -x 7 | fi 8 | 9 | function usage() { 10 | echo -n \ 11 | "Usage: $(basename "$0") 12 | Install requirements for all subpackages and development. 13 | " 14 | } 15 | 16 | if [ "${BASH_SOURCE[0]}" = "${0}" ]; then 17 | if [ "${1:-}" = "--help" ]; then 18 | usage 19 | else 20 | python -m pip install --upgrade pip 21 | pip install '.[dev]' 22 | fi 23 | fi 24 | -------------------------------------------------------------------------------- /src/stactools/cli/__main__.py: -------------------------------------------------------------------------------- 1 | from stactools.cli.cli import run_cli 2 | 3 | if __name__ == "__main__": 4 | run_cli() 5 | -------------------------------------------------------------------------------- /src/stactools/cli/cli.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from typing import Union 3 | 4 | import click 5 | 6 | from stactools.cli import registry 7 | 8 | 9 | def setup_logging(level: Union[str, int]) -> None: 10 | logger = logging.getLogger("stactools") 11 | logger.setLevel(level) 12 | 13 | ch = logging.StreamHandler() 14 | ch.setLevel(level) 15 | formatter = logging.Formatter("%(message)s") 16 | ch.setFormatter(formatter) 17 | 18 | logger.addHandler(ch) 19 | 20 | 21 | @click.group() 22 | @click.option("-v", "--verbose", help=("Use verbose mode"), is_flag=True) 23 | @click.option("-q", "--quiet", help=("Use quiet mode (no output)"), is_flag=True) 24 | def cli(verbose: bool, quiet: bool) -> None: 25 | logging_level = logging.INFO 26 | if verbose: 27 | logging_level = logging.DEBUG 28 | if quiet: 29 | logging_level = logging.ERROR 30 | setup_logging(logging_level) 31 | 32 | 33 | for create_subcommand in registry.get_create_subcommand_functions(): 34 | create_subcommand(cli) 35 | 36 | 37 | def run_cli() -> None: 38 | cli(prog_name="stac") 39 | 40 | 41 | if __name__ == "__main__": 42 | run_cli() 43 | -------------------------------------------------------------------------------- /src/stactools/cli/commands/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stac-utils/stactools/8acd72d4d8914b680e747d655e5964cf53280a27/src/stactools/cli/commands/__init__.py -------------------------------------------------------------------------------- /src/stactools/cli/commands/add.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | import click 4 | from pystac import Catalog, Item, read_file 5 | 6 | from stactools.core import add_item 7 | 8 | 9 | def add( 10 | source_item: str, 11 | target_catalog: str, 12 | collection_id: Optional[str] = None, 13 | move_assets: bool = False, 14 | ) -> None: 15 | source = read_file(source_item) 16 | if not isinstance(source, Item): 17 | raise click.BadArgumentUsage(f"{source_item} is not a STAC Item") 18 | target = read_file(target_catalog) 19 | if not isinstance(target, Catalog): 20 | raise click.BadArgumentUsage(f"{target_catalog} is not a STAC Catalog") 21 | 22 | if collection_id is not None: 23 | target_collection = target.get_child(collection_id, recursive=True) 24 | if target_collection is None: 25 | raise click.BadOptionUsage( 26 | "collection", 27 | "A collection with ID {} does not exist in {}".format( 28 | collection_id, target_catalog 29 | ), 30 | ) 31 | 32 | add_item(source, target_collection, move_assets) 33 | target_collection.save() 34 | else: 35 | add_item(source, target, move_assets) 36 | target.save() 37 | 38 | 39 | def create_add_command(cli: click.Group) -> click.Command: 40 | @cli.command("add", short_help="Add an item to a catalog/collection.") 41 | @click.argument("source_item") 42 | @click.argument("target_catalog") 43 | @click.option( 44 | "--collection", 45 | help=( 46 | "The collection ID to add to. If not set, will " 47 | "add to the root catalog or collection." 48 | ), 49 | ) 50 | @click.option( 51 | "-a", 52 | "--move-assets", 53 | is_flag=True, 54 | help="Move assets to the target catalog Item locations.", 55 | ) 56 | def add_command( 57 | source_item: str, target_catalog: str, collection: str, move_assets: bool 58 | ) -> None: 59 | add( 60 | source_item, 61 | target_catalog, 62 | collection_id=collection, 63 | move_assets=move_assets, 64 | ) 65 | 66 | return add_command 67 | -------------------------------------------------------------------------------- /src/stactools/cli/commands/add_raster.py: -------------------------------------------------------------------------------- 1 | import click 2 | import pystac 3 | 4 | from stactools.core import add_raster_to_item 5 | 6 | 7 | def add_raster(item_path: str) -> None: 8 | item = pystac.read_file(item_path) 9 | if not isinstance(item, pystac.Item): 10 | raise click.BadArgumentUsage(f"{item_path} is not a STAC Item") 11 | item = add_raster_to_item(item) 12 | item.save_object() 13 | 14 | 15 | def create_add_raster_command(cli: click.Group) -> click.Command: 16 | @cli.command("add-raster", short_help="Add raster extension to an Item.") 17 | @click.argument("item_path") 18 | def add_raster_command(item_path: str) -> None: 19 | add_raster(item_path) 20 | 21 | return add_raster_command 22 | -------------------------------------------------------------------------------- /src/stactools/cli/commands/create.py: -------------------------------------------------------------------------------- 1 | import json 2 | import sys 3 | from typing import List 4 | 5 | import click 6 | 7 | from stactools.core import create 8 | 9 | 10 | def create_create_item_command(cli: click.Group) -> click.Command: 11 | @cli.command("create-item", short_help="Creates an item from an asset") 12 | @click.argument("href") 13 | @click.argument("asset_key", default="data") 14 | @click.option( 15 | "-r", 16 | "--role", 17 | "roles", 18 | help="Optional, semantic roles of the asset", 19 | multiple=True, 20 | default=["data"], 21 | ) 22 | def create_item_command(href: str, asset_key: str, roles: List[str]) -> None: 23 | """Creates an Item from a href. 24 | 25 | The href must be a `rasterio` readable asset. The item's dictionary will 26 | be printed to stdout. This item is intentinonally _extremely_ minimal. 27 | If you need additional capabilities, we recommend using [rio 28 | stac](https://github.com/developmentseed/rio-stac/). 29 | """ 30 | item = create.item(href, asset_key=asset_key, roles=roles) 31 | json.dump(item.to_dict(), sys.stdout) 32 | 33 | return create_item_command 34 | -------------------------------------------------------------------------------- /src/stactools/cli/commands/layout.py: -------------------------------------------------------------------------------- 1 | import click 2 | import pystac 3 | 4 | from stactools.core import layout_catalog 5 | 6 | 7 | def create_layout_command(cli: click.Group) -> click.Command: 8 | @cli.command( 9 | "layout", short_help="Reformat the layout of a STAC based on templating." 10 | ) 11 | @click.argument("catalog") 12 | @click.argument("item_path_template") 13 | @click.option( 14 | "-s", 15 | "--create-subcatalogs", 16 | is_flag=True, 17 | help=( 18 | "Create subcatalogs based on the template values instead of " 19 | "just creating directories." 20 | ), 21 | ) 22 | @click.option( 23 | "-k", 24 | "--remove-existing-subcatalogs", 25 | is_flag=True, 26 | help=( 27 | "If this flag is set, existing subcatalogs will be" 28 | "removed. If --create_subcatalogs is used, all items" 29 | "will be places in the new subcatalogs from the source_catalog." 30 | ), 31 | ) 32 | @click.option( 33 | "-a", 34 | "--move-assets", 35 | is_flag=True, 36 | help="Move assets to the target catalog Item locations.", 37 | ) 38 | def layout_command( 39 | catalog: str, 40 | item_path_template: str, 41 | create_subcatalogs: bool, 42 | remove_existing_subcatalogs: bool, 43 | move_assets: bool, 44 | ) -> None: 45 | source = pystac.read_file(catalog) 46 | if not isinstance(source, pystac.Catalog): 47 | raise click.BadArgumentUsage(f"{catalog} is not a STAC Catalog") 48 | 49 | layout_catalog( 50 | source, 51 | item_path_template, 52 | create_subcatalogs=create_subcatalogs, 53 | remove_existing_subcatalogs=remove_existing_subcatalogs, 54 | move_assets=move_assets, 55 | ) 56 | 57 | source.save() 58 | 59 | return layout_command 60 | -------------------------------------------------------------------------------- /src/stactools/cli/commands/lint.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from typing import Optional 3 | 4 | import click 5 | from stac_check.lint import Linter 6 | 7 | 8 | def create_lint_command(cli: click.Group) -> click.Command: 9 | @cli.command("lint", short_help="Lint a stac object with stac-check.") 10 | @click.option( 11 | "--quiet", 12 | is_flag=True, 13 | help=( 14 | "Do not print anything to standard output, " 15 | "simply set the process exit code to 1 on error." 16 | ), 17 | ) 18 | @click.option( 19 | "--config-file", 20 | help="Path to a configuration file to use instead of the default configuration", 21 | ) 22 | @click.argument("href") 23 | def lint_command(href: str, quiet: bool, config_file: Optional[str]) -> None: 24 | """Lint a STAC object via stac-check. 25 | 26 | Prints any warnings to stdout. 27 | 28 | stac-check: https://github.com/stac-utils/stac-check 29 | """ 30 | linter = Linter(href, config_file=config_file) 31 | if not config_file: 32 | # While this is currently recommended in the STAC best practices, 33 | # this conflicts with the best practices layouts, so we silence the 34 | # warning. See https://github.com/radiantearth/stac-spec/pull/1173 35 | # for more information. 36 | linter.config["linting"]["links_self"] = False 37 | linter_results = linter.create_best_practices_dict() 38 | if len(linter_results.keys()) == 0: 39 | if not quiet: 40 | click.secho("OK", fg="green", nl=False) 41 | click.echo(f" STAC object at {href} has no warnings!") 42 | else: 43 | if not quiet: 44 | for _, v in linter_results.items(): 45 | click.secho("WARNING", fg="yellow", nl=False) 46 | for value in v: 47 | click.echo(f" {value}") 48 | sys.exit(1) 49 | 50 | return lint_command 51 | -------------------------------------------------------------------------------- /src/stactools/cli/commands/migrate.py: -------------------------------------------------------------------------------- 1 | import click 2 | import pystac 3 | 4 | from stactools.core import migrate_object 5 | 6 | 7 | def _migrate( 8 | href: str, save: bool = False, recursive: bool = False, show_diff: bool = True 9 | ) -> pystac.STACObject: 10 | if save is False and show_diff is False: 11 | raise click.BadArgumentUsage( 12 | "It is only valid to use 'hide-diff' when 'save' is enabled " 13 | "otherwise there would be no output." 14 | ) 15 | 16 | stac_object = pystac.read_file(href) 17 | if recursive and not isinstance(stac_object, (pystac.Catalog, pystac.Collection)): 18 | raise click.BadArgumentUsage( 19 | "'recursive' is only a valid option for " 20 | "pystac.Catalogs and pystac.Collections" 21 | ) 22 | return migrate_object( 23 | stac_object, save=save, recursive=recursive, show_diff=show_diff 24 | ) 25 | 26 | 27 | def create_migrate_command(cli: click.Group) -> click.Command: 28 | @cli.command("migrate", short_help="Migrate a STAC object to the latest version") 29 | @click.argument("href") 30 | @click.option( 31 | "-s", 32 | "--save", 33 | is_flag=True, 34 | help="Save migrated STAC object in original location.", 35 | ) 36 | @click.option( 37 | "-r", 38 | "--recursive", 39 | is_flag=True, 40 | help="Recurse through all child objects and migrate them as well.", 41 | ) 42 | @click.option( 43 | "--show-diff/--hide-diff", 44 | default=True, 45 | help=( 46 | "Whether to dump diff between original and migrated object to stdout. " 47 | "Defaults to --show-diff. " 48 | ), 49 | ) 50 | def migrate_command( 51 | href: str, save: bool, recursive: bool, show_diff: bool 52 | ) -> None: 53 | _migrate(href, save=save, recursive=recursive, show_diff=show_diff) 54 | 55 | return migrate_command 56 | -------------------------------------------------------------------------------- /src/stactools/cli/commands/summary.py: -------------------------------------------------------------------------------- 1 | import json 2 | from typing import Any, Dict, Optional 3 | 4 | import click 5 | from pystac import Collection 6 | from pystac.summaries import Summarizer 7 | 8 | 9 | def format_summary(summary: Dict[str, Any], indent: int = 4) -> str: 10 | out = "" 11 | for var in summary: 12 | if summary[var] is dict: 13 | out += var + ": \n" + " " * indent + str(summary[var]) + "\n" 14 | else: 15 | out += var + ": " + str(summary[var]) + "\n" 16 | return out 17 | 18 | 19 | def create_summary_command(cli: click.Group) -> click.Command: 20 | @cli.command("summary", short_help="Summarize a STAC collection's contents.") 21 | @click.argument("href") 22 | @click.option( 23 | "-f", 24 | "--fields", 25 | help=( 26 | "the path to the json file with field descriptions. " 27 | "If no file is passed, a default one will be used." 28 | ), 29 | ) 30 | @click.option( 31 | "-u", 32 | "--update", 33 | is_flag=True, 34 | default=False, 35 | help=( 36 | "Instead of printing the summary information, " 37 | "update the collection itself, then print it to stdout." 38 | ), 39 | ) 40 | @click.option( 41 | "-i", 42 | "--inplace", 43 | is_flag=True, 44 | default=False, 45 | help=( 46 | "If updating, update the collection in-place, " 47 | "instead of printing it to stdout." 48 | ), 49 | ) 50 | def summary_command( 51 | href: str, fields: Optional[str], update: bool, inplace: bool 52 | ) -> None: 53 | collection = Collection.from_file(href) 54 | summaries = Summarizer(fields).summarize(collection) 55 | if update: 56 | collection.summaries = summaries 57 | if inplace: 58 | collection.save_object(include_self_link=False, dest_href=href) 59 | else: 60 | print(json.dumps(collection.to_dict(include_self_link=False), indent=2)) 61 | else: 62 | print(format_summary(summaries.to_dict())) 63 | 64 | return summary_command 65 | -------------------------------------------------------------------------------- /src/stactools/cli/commands/update_extent.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | import click 4 | from pystac import Collection 5 | 6 | 7 | def create_update_extent_command(cli: click.Group) -> click.Command: 8 | @cli.command("update-extent", short_help="Update a STAC collection's extent.") 9 | @click.argument("href") 10 | @click.option( 11 | "-i", 12 | "--inplace", 13 | is_flag=True, 14 | default=False, 15 | help="Update the collection in-place, instead of printing it to stdout.", 16 | ) 17 | def update_extent_command(href: str, inplace: bool) -> None: 18 | collection = Collection.from_file(href) 19 | collection.update_extent_from_items() 20 | if inplace: 21 | collection.save_object(include_self_link=False, dest_href=href) 22 | else: 23 | print(json.dumps(collection.to_dict(include_self_link=False), indent=2)) 24 | 25 | return update_extent_command 26 | -------------------------------------------------------------------------------- /src/stactools/cli/commands/validate.py: -------------------------------------------------------------------------------- 1 | import json 2 | import sys 3 | from typing import Optional 4 | 5 | import click 6 | from stac_validator.validate import StacValidate 7 | 8 | 9 | def create_validate_command(cli: click.Group) -> click.Command: 10 | @cli.command("validate", short_help="Validate a stac object.") 11 | @click.argument("href") 12 | @click.option( 13 | "--recursive/--no-recursive", 14 | help="Recursively validate all STAC objects in this catalog.", 15 | default=True, 16 | ) 17 | @click.option( 18 | "--validate-links/--no-validate-links", help="Validate links.", default=True 19 | ) 20 | @click.option( 21 | "--validate-assets/--no-validate-assets", help="Validate assets.", default=True 22 | ) 23 | @click.option("-v", "--verbose", is_flag=True, help="Enables verbose output.") 24 | @click.option( 25 | "--log-file", 26 | help="Save output to file (local filepath).", 27 | ) 28 | def validate_command( 29 | href: str, 30 | recursive: bool, 31 | validate_links: bool, 32 | validate_assets: bool, 33 | verbose: bool, 34 | log_file: Optional[str], 35 | ) -> None: 36 | """Validates a STAC object. 37 | 38 | This is a thin wrapper around 39 | [stac-validate](https://github.com/stac-utils/stac-validator). Not all 40 | command-line options are exposed. If you want more control over 41 | validation, use `stac-validator` directly. 42 | 43 | If you'd like linting, use `stac lint`. 44 | """ 45 | validate = StacValidate( 46 | href, 47 | recursive=recursive, 48 | links=validate_links, 49 | assets=validate_assets, 50 | verbose=verbose, 51 | log=log_file or "", 52 | ) 53 | is_valid = validate.run() 54 | click.echo(json.dumps(validate.message, indent=4)) 55 | if is_valid: 56 | sys.exit(0) 57 | else: 58 | sys.exit(1) 59 | 60 | return validate_command 61 | -------------------------------------------------------------------------------- /src/stactools/cli/commands/version.py: -------------------------------------------------------------------------------- 1 | import pystac 2 | from click import echo 3 | from click.core import Command, Group 4 | from pystac.version import get_stac_version 5 | 6 | from stactools.core import __version__ 7 | 8 | 9 | def create_version_command(cli: Group) -> Command: 10 | @cli.command("version", short_help="Display version info.") 11 | def version_command() -> None: 12 | """Display version info.""" 13 | echo(f"stactools version {__version__}") 14 | echo(f"PySTAC version {pystac.__version__}") 15 | echo(f"STAC version {get_stac_version()}") 16 | 17 | return version_command 18 | -------------------------------------------------------------------------------- /src/stactools/cli/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stac-utils/stactools/8acd72d4d8914b680e747d655e5964cf53280a27/src/stactools/cli/py.typed -------------------------------------------------------------------------------- /src/stactools/cli/registry.py: -------------------------------------------------------------------------------- 1 | from pkgutil import ModuleInfo 2 | from types import ModuleType 3 | from typing import Callable, Iterator, List 4 | 5 | from click import Command, Group 6 | 7 | 8 | class Registry: 9 | """A registry for resources that are built-in or contributed by plugins.""" 10 | 11 | def __init__(self) -> None: 12 | self._create_command_functions: List[Callable[[Group], Command]] = [] 13 | 14 | def register_subcommand( 15 | self, create_command_function: Callable[[Group], Command] 16 | ) -> None: 17 | self._create_command_functions.append(create_command_function) 18 | 19 | def get_create_subcommand_functions(self) -> List[Callable[[Group], Command]]: 20 | return self._create_command_functions[:] 21 | 22 | def load_plugins(self) -> None: 23 | """Discover all plugins and register their resources. 24 | 25 | Import each Python module within the stactools namespace package 26 | and call the register_plugin function at its root (if it 27 | exists). 28 | """ 29 | import importlib 30 | import pkgutil 31 | 32 | import stactools 33 | 34 | # From https://packaging.python.org/guides/creating-and-discovering-plugins/#using-namespace-packages # noqa 35 | def iter_namespace(ns_pkg: ModuleType) -> Iterator[ModuleInfo]: 36 | # Specifying the second argument (prefix) to iter_modules makes the 37 | # returned name an absolute name instead of a relative one. This allows 38 | # import_module to work without having to do additional modification to 39 | # the name. 40 | return pkgutil.iter_modules(ns_pkg.__path__, ns_pkg.__name__ + ".") 41 | 42 | discovered_plugins = { 43 | name: importlib.import_module(name) 44 | for finder, name, ispkg in iter_namespace(stactools) 45 | } 46 | 47 | for name, module in discovered_plugins.items(): 48 | register_plugin = getattr(module, "register_plugin", None) 49 | if register_plugin: 50 | register_plugin(self) 51 | -------------------------------------------------------------------------------- /src/stactools/core/__init__.py: -------------------------------------------------------------------------------- 1 | from stactools.core.add import add_item 2 | from stactools.core.add_asset import add_asset, add_asset_to_item 3 | from stactools.core.add_raster import add_raster_to_item 4 | from stactools.core.copy import ( 5 | copy_catalog, 6 | move_all_assets, 7 | move_asset_file, 8 | move_asset_file_to_item, 9 | move_assets, 10 | ) 11 | from stactools.core.io import use_fsspec 12 | from stactools.core.layout import layout_catalog 13 | from stactools.core.merge import merge_all_items, merge_items 14 | from stactools.core.migrate import migrate_object 15 | 16 | __all__ = [ 17 | "add_item", 18 | "add_asset", 19 | "add_asset_to_item", 20 | "add_raster_to_item", 21 | "copy_catalog", 22 | "layout_catalog", 23 | "merge_all_items", 24 | "merge_items", 25 | "migrate_object", 26 | "move_asset_file", 27 | "move_asset_file_to_item", 28 | "move_assets", 29 | "move_all_assets", 30 | "use_fsspec", 31 | ] 32 | __version__ = "0.5.3" 33 | -------------------------------------------------------------------------------- /src/stactools/core/add.py: -------------------------------------------------------------------------------- 1 | """Add items to catalogs.""" 2 | 3 | import os 4 | 5 | from pystac import Catalog, Collection, Item 6 | from pystac.layout import BestPracticesLayoutStrategy 7 | 8 | from stactools.core.copy import move_assets as do_move_assets 9 | 10 | 11 | def add_item( 12 | source_item: Item, target_catalog: Catalog, move_assets: bool = False 13 | ) -> None: 14 | """Adds an item to a catalog. 15 | 16 | Args: 17 | source_item (pystac.Item): 18 | The Item that will be added. 19 | This item is not mutated in this operation. 20 | target_catalog (pystac.Catalog): 21 | The destination catalog. 22 | This catalog will be mutated in this operation. 23 | move_assets (bool): If true, move the asset files alongside the target item. 24 | """ 25 | 26 | target_item_ids = [item.id for item in target_catalog.get_items(recursive=True)] 27 | if source_item.id in target_item_ids: 28 | raise ValueError( 29 | f"An item with ID {source_item.id} already exists in the target catalog" 30 | ) 31 | self_href = target_catalog.get_self_href() 32 | if self_href: 33 | parent_dir = os.path.dirname(self_href) 34 | layout_strategy = BestPracticesLayoutStrategy() 35 | item_copy = source_item.clone() 36 | item_copy.set_self_href(layout_strategy.get_item_href(item_copy, parent_dir)) 37 | target_catalog.add_item(item_copy) 38 | 39 | if isinstance(target_catalog, Collection): 40 | item_copy.set_collection(target_catalog) 41 | target_catalog.update_extent_from_items() 42 | else: 43 | item_copy.set_collection(None) 44 | 45 | if move_assets: 46 | do_move_assets(item_copy, copy=False) 47 | else: 48 | raise ValueError( 49 | f"Cannot add Item {source_item.id} because {target_catalog} does " 50 | "not have a self href." 51 | ) 52 | -------------------------------------------------------------------------------- /src/stactools/core/add_raster.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from typing import List 3 | 4 | import numpy 5 | import rasterio 6 | from pystac import Item 7 | from pystac.extensions.raster import ( 8 | DataType, 9 | Histogram, 10 | RasterBand, 11 | RasterExtension, 12 | Statistics, 13 | ) 14 | from pystac.utils import make_absolute_href 15 | 16 | logger = logging.getLogger(__name__) 17 | 18 | BINS = 256 19 | 20 | 21 | def add_raster_to_item( 22 | item: Item, statistics: bool = True, histogram: bool = True 23 | ) -> Item: 24 | """Adds the raster extension to an item. 25 | 26 | Args: 27 | item (Item): The PySTAC Item to extend. 28 | statistics (bool): Compute band statistics (min/max). Defaults to True 29 | histogram (bool): Compute band histogram. Defaults to True 30 | 31 | Returns: 32 | Item: 33 | Returns an updated Item. 34 | This operation mutates the Item. 35 | """ 36 | RasterExtension.add_to(item) 37 | for asset in item.assets.values(): 38 | if asset.roles and "data" in asset.roles: 39 | raster = RasterExtension.ext(asset) 40 | href = make_absolute_href(asset.href, item.get_self_href()) 41 | bands = _read_bands(href, statistics, histogram) 42 | if bands: 43 | raster.apply(bands) 44 | return item 45 | 46 | 47 | def _read_bands(href: str, statistics: bool, histogram: bool) -> List[RasterBand]: 48 | bands = [] 49 | with rasterio.open(href) as dataset: 50 | for i, index in enumerate(dataset.indexes): 51 | band = RasterBand.create() 52 | band.nodata = dataset.nodatavals[i] 53 | band.spatial_resolution = dataset.transform[0] 54 | band.data_type = DataType(dataset.dtypes[i]) 55 | 56 | if statistics or histogram: 57 | data = dataset.read(index, masked=True) 58 | minimum = float(numpy.nanmin(data)) 59 | maximum = float(numpy.nanmax(data)) 60 | if statistics: 61 | band.statistics = Statistics.create(minimum=minimum, maximum=maximum) 62 | if histogram: 63 | # the entire array is masked, or all values are NAN. 64 | # won't be able to compute histogram and will return empty array. 65 | if numpy.isnan(minimum): 66 | band.histogram = Histogram.create(0, minimum, maximum, []) 67 | else: 68 | hist_data, _ = numpy.histogram( 69 | data, range=(minimum, maximum), bins=BINS 70 | ) 71 | band.histogram = Histogram.create( 72 | BINS, 73 | minimum, 74 | maximum, 75 | hist_data.tolist(), # type: ignore 76 | ) 77 | bands.append(band) 78 | return bands 79 | -------------------------------------------------------------------------------- /src/stactools/core/create.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import os.path 3 | from typing import List, Optional 4 | 5 | import rasterio 6 | import shapely.geometry 7 | from pystac import Asset, Item 8 | from pystac.extensions.projection import ProjectionExtension 9 | 10 | import stactools.core.projection 11 | 12 | from .io import ReadHrefModifier 13 | 14 | 15 | def item( 16 | href: str, 17 | *, 18 | asset_key: str = "data", 19 | roles: List[str] = ["data"], 20 | read_href_modifier: Optional[ReadHrefModifier] = None, 21 | ) -> Item: 22 | """Creates a STAC Item from the asset at the provided href. 23 | 24 | The ``read_href_modifer`` argument can be used to modify the href for the 25 | rasterio read, e.g. if you need to sign a url. 26 | 27 | This function is intentionally minimal in its signature and capabilities. If 28 | you need to customize your Item, do so after creation. 29 | 30 | Args: 31 | href (str): The href of the asset that will be used to create the item. 32 | asset_key (str): The unique key of the asset 33 | roles (List[str]): The semantic roles of the asset 34 | read_href_modifier (Optional[ReadHrefModifier]): 35 | An optional callable that will be used to modify the href before reading. 36 | 37 | Returns: 38 | pystac.Item: A PySTAC Item. 39 | """ 40 | id = os.path.splitext(os.path.basename(href))[0] 41 | if read_href_modifier: 42 | modified_href = read_href_modifier(href) 43 | else: 44 | modified_href = href 45 | with rasterio.open(modified_href) as dataset: 46 | crs = dataset.crs 47 | proj_bbox = dataset.bounds 48 | proj_transform = list(dataset.transform)[0:6] 49 | proj_shape = dataset.shape 50 | geom = stactools.core.projection.reproject_shape( 51 | crs, "EPSG:4326", shapely.geometry.box(*proj_bbox), precision=6 52 | ) 53 | bbox = list(geom.bounds) 54 | geojson = shapely.geometry.mapping(geom) 55 | item = Item( 56 | id=id, 57 | geometry=geojson, 58 | bbox=bbox, 59 | datetime=datetime.datetime.now(), 60 | properties={}, 61 | ) 62 | 63 | projection = ProjectionExtension.ext(item, add_if_missing=True) 64 | epsg = crs.to_epsg() 65 | if epsg: 66 | projection.epsg = epsg 67 | else: 68 | projection.wkt2 = crs.to_wkt("WKT2") 69 | projection.transform = proj_transform 70 | projection.shape = proj_shape 71 | 72 | item.add_asset(asset_key, Asset(href=href, roles=roles)) 73 | 74 | return item 75 | -------------------------------------------------------------------------------- /src/stactools/core/geometry.py: -------------------------------------------------------------------------------- 1 | from functools import reduce 2 | from typing import Any, Dict, List, Protocol 3 | 4 | import rasterio.features 5 | from shapely import Geometry 6 | 7 | 8 | def bounding_box(geom: Dict[str, Any]) -> List[float]: 9 | """Extracts and returns the bounding box of a GeoJSON geometry. 10 | 11 | Args: 12 | geom (dict): A GeoJSON Feature, GeoJSON FeatureCollection, GeoJSON geometry, 13 | STAC Item, or STAC ItemCollection. 14 | 15 | Returns: 16 | list: A list of float values containing the bounding box of the GeoJSON 17 | geometry in the format [min X, min Y, max X, max Y] 18 | """ 19 | return list(rasterio.features.bounds(geom)) 20 | 21 | 22 | def mutual_intersection(geoms: List[Geometry]) -> Geometry: 23 | """Finds the mutual intersection of a set of geometries. 24 | 25 | Args: 26 | geoms (List[Geometry]): A non-empty list of geometries to intersect 27 | 28 | Returns: 29 | Geometry: The mutual intersection of all geometries 30 | """ 31 | assert len(geoms) > 0, "Must provide non-empty list of geometries" 32 | 33 | return reduce( 34 | lambda current, to_intersect: current.intersection(to_intersect), 35 | geoms[1:], 36 | geoms[0], 37 | ) 38 | 39 | 40 | class GeoInterface(Protocol): 41 | """A simple protocol for things that have a ``__geo_interface__`` method. 42 | 43 | The ``__geo_interface__`` protocol is described `here 44 | `_, and is used within `shapely 45 | `_ to 46 | extract geometries from objects. 47 | """ 48 | 49 | def __geo_interface__(self) -> Dict[str, Any]: ... 50 | -------------------------------------------------------------------------------- /src/stactools/core/layout.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from pystac import Catalog 4 | from pystac.layout import TemplateLayoutStrategy 5 | 6 | from stactools.core import move_all_assets 7 | 8 | 9 | def layout_catalog( 10 | catalog: Catalog, 11 | item_path_template: str, 12 | create_subcatalogs: bool = False, 13 | remove_existing_subcatalogs: bool = False, 14 | move_assets: bool = False, 15 | ) -> Catalog: 16 | """Modifies the layout of a STAC. 17 | 18 | Given a catalog and a layout template, modifies the layout of the STAC to 19 | either generate subcatalogs based on item properties, or create 20 | subdirectories to organize item properties. Both of these are based on the 21 | template string provided. See the ``LayoutTemplate`` PySTAC API docs for 22 | more information on template strings. 23 | 24 | Args: 25 | catalog (pystac.Catalog or pystac.Collection): 26 | The Catalog or Collection to change the layout of. 27 | item_path_template (str): 28 | A string that represents a path of item properties, e.g. 29 | ``"${year}/${month}"`` 30 | create_subcatalogs (bool): 31 | If True, create subcatalogs for each of the template directory 32 | levels using the item properties to determine which catalog it 33 | belongs to. 34 | remove_existing_subcatalogs (bool): 35 | If True, apply the subcatalogs to all items throughout the catalog 36 | and clear any child catalogs, using the newly generated subcatalogs 37 | or item paths. 38 | move_assets (bool): 39 | If True, the assets of the Items will be moved alongside of the 40 | Items. Otherwise the asset will remain in place, with the moved 41 | Item's asset HREFs reflecting the existing location. 42 | 43 | Returns: 44 | pystac.Catalog or pystac.Collection: 45 | The passed in Catalog or Collection. This operation mutates the 46 | catalog or collection. 47 | """ 48 | 49 | if remove_existing_subcatalogs: 50 | items = catalog.get_items(recursive=True) 51 | for item in items: 52 | parent = item.get_parent() 53 | assert parent is not None 54 | parent.remove_item(item.id) 55 | catalog.add_item(item) 56 | 57 | catalog.clear_children() 58 | 59 | if create_subcatalogs: 60 | catalog.generate_subcatalogs(template=item_path_template) 61 | catalog.normalize_hrefs(os.path.dirname(catalog.self_href)) 62 | else: 63 | strategy = TemplateLayoutStrategy(item_template=item_path_template) 64 | catalog.normalize_hrefs(os.path.dirname(catalog.self_href), strategy=strategy) 65 | 66 | if move_assets: 67 | move_all_assets(catalog, ignore_conflicts=True) 68 | 69 | return catalog 70 | -------------------------------------------------------------------------------- /src/stactools/core/migrate.py: -------------------------------------------------------------------------------- 1 | import difflib 2 | import json 3 | from itertools import chain 4 | 5 | import pystac 6 | from pystac.stac_io import DefaultStacIO 7 | 8 | 9 | def _print_diff(stac_object: pystac.STACObject) -> None: 10 | href = stac_object.get_self_href() 11 | if href is None: 12 | raise ValueError(f"Could not determine diff for {stac_object}, missing href") 13 | input = DefaultStacIO().read_text(href) 14 | output = json.dumps(stac_object.to_dict(), indent=2) 15 | for diffs in difflib.unified_diff( 16 | input.splitlines(), output.splitlines(), fromfile=f"a{href}", tofile=f"b{href}" 17 | ): 18 | print(diffs) 19 | 20 | 21 | def migrate_object( 22 | stac_object: pystac.STACObject, 23 | save: bool = False, 24 | recursive: bool = False, 25 | show_diff: bool = True, 26 | ) -> pystac.STACObject: 27 | """Migrate a STAC object and all its extensions to the latest version of STAC 28 | 29 | Note: 30 | Migrating a STAC object will set the keys to be in the standard order. 31 | This might result in a diff even for a valid and up-to-date STAC object. 32 | 33 | Args: 34 | stac_object : STAC object to migrate 35 | save : Whether to save the object back to its original location. 36 | Defaults to False. 37 | recursive : Whether to recurse through all the child object and migrate 38 | them as well. Defaults to False. 39 | show_diff : Whether to print the diff between the original and new STAC 40 | object. Defaults to True. 41 | Returns: 42 | STACObject : The migrated object - modified inplace. 43 | """ 44 | # migration happens implicitly on load 45 | if show_diff: 46 | _print_diff(stac_object) 47 | 48 | if recursive: 49 | if not isinstance(stac_object, (pystac.Catalog, pystac.Collection)): 50 | raise KeyError( 51 | "'recursive' is only a valid option for " 52 | "pystac.Catalogs and pystac.Collections" 53 | ) 54 | stac_object.fully_resolve() 55 | if show_diff: 56 | for _, children, items in stac_object.walk(): 57 | for obj in chain(children, items): 58 | _print_diff(obj) 59 | if save: 60 | stac_object.save() 61 | else: 62 | if save: 63 | stac_object.save_object() 64 | 65 | return stac_object 66 | -------------------------------------------------------------------------------- /src/stactools/core/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stac-utils/stactools/8acd72d4d8914b680e747d655e5964cf53280a27/src/stactools/core/py.typed -------------------------------------------------------------------------------- /src/stactools/core/utils/__init__.py: -------------------------------------------------------------------------------- 1 | """General utility functions.""" 2 | 3 | import warnings 4 | from contextlib import contextmanager 5 | from typing import Callable, Generator, Optional, TypeVar 6 | 7 | import fsspec 8 | import pystac.utils 9 | import rasterio 10 | from rasterio.errors import NotGeoreferencedWarning 11 | 12 | T = TypeVar("T") 13 | U = TypeVar("U") 14 | 15 | 16 | def map_opt(fn: Callable[[T], U], v: Optional[T]) -> Optional[U]: 17 | """DEPRECATED: use :py:meth:`pystac.utils.map_opt` instead.""" 18 | deprecate("stactools.core.utils.map_opt", "pystac.utils.map_opt", "v0.5.0") 19 | return pystac.utils.map_opt(fn, v) 20 | 21 | 22 | def href_exists(href: str) -> bool: 23 | """Returns true if there is a file at the given href. 24 | 25 | Uses fssepc and its `exists 26 | `_ 27 | method. 28 | 29 | Args: 30 | href (str): The href to check. 31 | 32 | Returns: 33 | bool: True if the href exists, False if not. 34 | """ 35 | fs, _, paths = fsspec.get_fs_token_paths(href) 36 | return bool(paths and fs.exists(paths[0])) 37 | 38 | 39 | def gdal_driver_is_enabled(name: str) -> bool: 40 | """Checks to see if the named GDAL driver is enabled. 41 | 42 | Checks for the name in :py:meth:`rasterio.Env.drivers`. 43 | 44 | Args: 45 | name (str): The name of the driver. 46 | 47 | Returns: 48 | bool: True if the driver is enabled, False otherwise. 49 | """ 50 | with rasterio.Env() as env: 51 | return name in env.drivers().keys() 52 | 53 | 54 | def deprecate(from_: str, to: str, version: str) -> None: 55 | r"""Warn with :py:class:`DeprecationWarning` and a pre-canned message. 56 | 57 | The message is something like: 58 | 59 | Foo is deprecated and will be removed in v0.42.0. Use Bar instead. 60 | 61 | Args: 62 | from\_ (str): The current function/method/class name. 63 | to (str): The name that should be used instead. 64 | version (str): The version at which the function/method/class will be removed. 65 | """ 66 | warnings.warn( 67 | f"{from_} is deprecated and will be removed in {version}. Use {to} instead.", 68 | DeprecationWarning, 69 | stacklevel=2, 70 | ) 71 | 72 | 73 | @contextmanager 74 | def ignore_not_georeferenced() -> Generator[None, None, None]: 75 | """Suppress rasterio's warning when opening a dataset that contains no 76 | georeferencing information.""" 77 | with warnings.catch_warnings(): 78 | warnings.simplefilter("ignore", category=NotGeoreferencedWarning) 79 | yield 80 | -------------------------------------------------------------------------------- /src/stactools/core/utils/round.py: -------------------------------------------------------------------------------- 1 | from typing import Any, List, TypeVar 2 | 3 | from pystac import Collection, Item 4 | 5 | # Roughly 1 centimeter in geodetic coordinates 6 | DEFAULT_PRECISION = 7 7 | 8 | S = TypeVar("S", Item, Collection) 9 | 10 | 11 | def round_coordinates(stac_object: S, precision: int = DEFAULT_PRECISION) -> S: 12 | """Rounds Item geometry and bbox coordinates or Collection spatial extent 13 | bbox coordinates to specified precision. 14 | 15 | Args: 16 | stac_object (S): A pystac Item or Collection. 17 | precision (int): Number of decimal places for rounding. 18 | 19 | Returns: 20 | S: The original PySTAC Item or Collection, with rounded coordinates. 21 | """ 22 | if isinstance(stac_object, Item): 23 | if stac_object.geometry is not None: 24 | stac_object.geometry["coordinates"] = recursive_round( 25 | list(stac_object.geometry["coordinates"]), precision 26 | ) 27 | 28 | if stac_object.bbox is not None: 29 | stac_object.bbox = recursive_round(list(stac_object.bbox), precision) 30 | 31 | elif isinstance(stac_object, Collection): 32 | stac_object.extent.spatial.bboxes = recursive_round( 33 | list(stac_object.extent.spatial.bboxes), precision 34 | ) 35 | 36 | return stac_object 37 | 38 | 39 | def recursive_round(coordinates: List[Any], precision: int) -> List[Any]: 40 | """Rounds a list of numbers. The list can contain additional nested lists 41 | or tuples of numbers. 42 | 43 | Any tuples encountered will be converted to lists. 44 | 45 | Args: 46 | coordinates (List[Any]): A list of numbers, possibly containing nested 47 | lists or tuples of numbers. 48 | precision (int): Number of decimal places to use for rounding. 49 | 50 | Returns: 51 | List[Any]: a list (possibly nested) of numbers rounded to the given 52 | precision. 53 | """ 54 | for idx, value in enumerate(coordinates): 55 | if isinstance(value, (int, float)): 56 | coordinates[idx] = round(value, precision) 57 | else: 58 | coordinates[idx] = list(value) # handle any tuples 59 | coordinates[idx] = recursive_round(coordinates[idx], precision) 60 | return coordinates 61 | -------------------------------------------------------------------------------- /src/stactools/core/utils/subprocess.py: -------------------------------------------------------------------------------- 1 | """Run subprocesses.""" 2 | 3 | import logging 4 | from subprocess import PIPE, STDOUT, Popen 5 | from typing import IO, List 6 | 7 | logger = logging.getLogger(__name__) 8 | 9 | 10 | def call(command: List[str]) -> int: 11 | """Call a command using :py:class:`subprocess.Popen`. 12 | 13 | The standard output of the call will be logged at the INFO level. 14 | 15 | Args: 16 | command (list[str]): The command to execute. 17 | 18 | Returns: 19 | int: The return code of the process. 20 | """ 21 | 22 | def log_subprocess_output(pipe: IO[bytes]) -> None: 23 | for line in iter(pipe.readline, b""): # b'\n'-separated lines 24 | logger.info(line.decode("utf-8").strip("\n")) 25 | 26 | process = Popen(command, stdout=PIPE, stderr=STDOUT) 27 | if process.stdout: 28 | with process.stdout: 29 | log_subprocess_output(process.stdout) 30 | return process.wait() 31 | -------------------------------------------------------------------------------- /src/stactools/testing/__init__.py: -------------------------------------------------------------------------------- 1 | import stactools.core 2 | 3 | from .cli_test import CliTestCase 4 | from .test_data import TestData 5 | 6 | __all__ = [TestData.__name__, CliTestCase.__name__] 7 | 8 | __version__ = stactools.core.__version__ 9 | -------------------------------------------------------------------------------- /src/stactools/testing/cli.py: -------------------------------------------------------------------------------- 1 | """CLI for test data maintenance and generation.""" 2 | 3 | import logging 4 | import os 5 | import shutil 6 | from tempfile import TemporaryDirectory 7 | 8 | import click 9 | 10 | from stactools.core.utils.subprocess import call 11 | 12 | logger = logging.getLogger(__name__) 13 | 14 | 15 | @click.group() 16 | def cli() -> None: 17 | pass 18 | 19 | 20 | @cli.command("make-rasters-smaller") 21 | @click.option("--dir", required=True, help="Directory to walk and transform rasters.") 22 | @click.option( 23 | "-n", "--dry-run", required=True, help="Do a dry run; print commands.", is_flag=True 24 | ) 25 | def make_rasters_smaller_cmd(dir: str, dry_run: bool) -> None: 26 | def make_it_smaller(tif_path: str) -> None: 27 | with TemporaryDirectory() as tmp_dir: 28 | tmp_path = os.path.join(tmp_dir, "smaller.tif") 29 | translate_cmd = [ 30 | "gdal_translate", 31 | "-of", 32 | "GTiff", 33 | "-outsize", 34 | "512", 35 | "512", 36 | tif_path, 37 | tmp_path, 38 | ] 39 | if dry_run: 40 | logger.info(" ".join(translate_cmd)) 41 | else: 42 | call(translate_cmd) 43 | 44 | shutil.move(tmp_path, tif_path) 45 | 46 | for root, _, files in os.walk(dir): 47 | for f in files: 48 | if f.lower().endswith(".tif"): 49 | full_path = os.path.join(root, f) 50 | make_it_smaller(full_path) 51 | 52 | 53 | def run_cli() -> None: 54 | cli(prog_name="testutils") 55 | 56 | 57 | if __name__ == "__main__": 58 | run_cli() 59 | -------------------------------------------------------------------------------- /src/stactools/testing/cli_test.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import unittest 3 | import warnings 4 | from abc import ABC, abstractmethod 5 | from typing import Callable, List, Optional, Sequence, Union 6 | 7 | import click 8 | from click.testing import CliRunner, Result 9 | 10 | 11 | class CliTestCase(unittest.TestCase, ABC): 12 | """A command-line interface test case.""" 13 | 14 | def use_debug_logging(self) -> None: 15 | """Enable debug logging for these tests.""" 16 | logger = logging.getLogger("stactools") 17 | logger.setLevel(logging.DEBUG) 18 | 19 | ch = logging.StreamHandler() 20 | ch.setLevel(logging.DEBUG) 21 | formatter = logging.Formatter("%(message)s") 22 | ch.setFormatter(formatter) 23 | 24 | logger.addHandler(ch) 25 | 26 | def setUp(self) -> None: 27 | """Sets up a mock cli group for testing.""" 28 | 29 | @click.group() 30 | def cli() -> None: 31 | pass 32 | 33 | warnings.warn( 34 | "CliTestCase is deprecated in v0.5.0 and will be removed in v0.6.0. " 35 | "Please use `click.testing.CliRunner` instead", 36 | DeprecationWarning, 37 | ) 38 | for create_subcommand in self.create_subcommand_functions(): 39 | create_subcommand(cli) 40 | self.cli = cli 41 | 42 | def run_command(self, cmd: Optional[Union[str, Sequence[str]]]) -> Result: 43 | """Runs a command, returning its result. 44 | 45 | If there is output, print it to stdout. 46 | 47 | Args: 48 | cmd (str): The command to run. 49 | 50 | Returns: 51 | click.Result: The command-line invocation result. 52 | """ 53 | runner = CliRunner() 54 | result = runner.invoke(self.cli, cmd, catch_exceptions=False) 55 | if result.output: 56 | print(result.output) 57 | return result 58 | 59 | @abstractmethod 60 | def create_subcommand_functions( 61 | self, 62 | ) -> List[Callable[[click.Group], click.Command]]: 63 | """Return list of 'create_command' functions from implementations. 64 | 65 | Returns: 66 | list[Callable[[click.Group], click.Command]]: The commands to run. 67 | """ 68 | pass 69 | -------------------------------------------------------------------------------- /src/stactools/testing/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stac-utils/stactools/8acd72d4d8914b680e747d655e5964cf53280a27/src/stactools/testing/py.typed -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from stactools.testing import TestData 4 | 5 | 6 | class Logging: 7 | _logging_setup: bool = False 8 | 9 | @classmethod 10 | def setup_logging(cls, level): 11 | if cls._logging_setup: 12 | return 13 | 14 | logger = logging.getLogger() 15 | logger.setLevel(level) 16 | 17 | ch = logging.StreamHandler() 18 | ch.setLevel(level) 19 | formatter = logging.Formatter("%(message)s") 20 | ch.setFormatter(formatter) 21 | 22 | logger.addHandler(ch) 23 | 24 | cls._logging_setup = True 25 | 26 | 27 | Logging.setup_logging(logging.INFO) 28 | 29 | test_data = TestData(__file__) 30 | -------------------------------------------------------------------------------- /tests/cli/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stac-utils/stactools/8acd72d4d8914b680e747d655e5964cf53280a27/tests/cli/__init__.py -------------------------------------------------------------------------------- /tests/cli/commands/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stac-utils/stactools/8acd72d4d8914b680e747d655e5964cf53280a27/tests/cli/commands/__init__.py -------------------------------------------------------------------------------- /tests/cli/commands/test_add.py: -------------------------------------------------------------------------------- 1 | import pystac 2 | import pystac.utils 3 | import pytest 4 | from click.testing import CliRunner 5 | 6 | from stactools.cli.cli import cli 7 | from tests import test_data 8 | 9 | 10 | @pytest.fixture(scope="module") 11 | def item_path() -> str: 12 | return test_data.get_path( 13 | "data-files/basic/country-1/area-1-1" 14 | "/area-1-1-imagery/area-1-1-imagery-invalid.json" 15 | ) 16 | 17 | 18 | def test_add_item(item_path: str, tmp_planet_disaster: pystac.Collection): 19 | collection = tmp_planet_disaster 20 | collection_path = collection.get_self_href() 21 | items = list(collection.get_items(recursive=True)) 22 | assert len(items) == 5 23 | 24 | runner = CliRunner() 25 | result = runner.invoke(cli, ["add", item_path, collection_path]) 26 | assert result.exit_code == 0 27 | 28 | collection_after = pystac.read_file(collection_path) 29 | items = list(collection_after.get_items(recursive=True)) 30 | assert len(items) == 6 31 | 32 | 33 | def test_add_item_to_specific_collection( 34 | item_path: str, tmp_planet_disaster: pystac.Collection 35 | ): 36 | collection = tmp_planet_disaster 37 | collection_path = collection.get_self_href() 38 | items = list(collection.get_items(recursive=True)) 39 | assert len(items) == 5 40 | item_before = pystac.read_file(item_path) 41 | 42 | runner = CliRunner() 43 | result = runner.invoke( 44 | cli, 45 | [ 46 | "add", 47 | item_path, 48 | collection_path, 49 | "--collection", 50 | "hurricane-harvey", 51 | ], 52 | ) 53 | assert result.exit_code == 0 54 | 55 | collection_after = pystac.read_file(collection_path) 56 | items_after = collection_after.get_child("hurricane-harvey").get_items() 57 | assert any(item.id == item_before.id for item in items_after) 58 | 59 | 60 | def test_add_item_to_missing_collection( 61 | item_path: str, tmp_planet_disaster: pystac.Collection 62 | ): 63 | collection = tmp_planet_disaster 64 | collection_path = collection.get_self_href() 65 | items = list(collection.get_items(recursive=True)) 66 | assert len(items) == 5 67 | 68 | runner = CliRunner() 69 | result = runner.invoke( 70 | cli, 71 | [ 72 | "add", 73 | item_path, 74 | collection_path, 75 | "--collection", 76 | "WRONG", 77 | ], 78 | ) 79 | assert result.exit_code == 2 80 | assert " A collection with ID WRONG does not exist" in result.output 81 | -------------------------------------------------------------------------------- /tests/cli/commands/test_add_asset.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | import pystac 4 | import pystac.utils 5 | from click.testing import CliRunner 6 | 7 | from stactools.cli.cli import cli 8 | from tests import test_data 9 | 10 | 11 | def test_add_asset_to_item(tmp_item_path: str) -> None: 12 | asset_path = test_data.get_path("data-files/core/byte.tif") 13 | item_path = tmp_item_path 14 | item = pystac.Item.from_file(item_path) 15 | assert "test-asset" not in item.assets 16 | 17 | runner = CliRunner() 18 | result = runner.invoke( 19 | cli, 20 | [ 21 | "add-asset", 22 | item_path, 23 | "test-asset", 24 | asset_path, 25 | "--title", 26 | "test", 27 | "--description", 28 | "placeholder asset", 29 | "--role", 30 | "thumbnail", 31 | "--role", 32 | "overview", 33 | ], 34 | ) 35 | assert result.exit_code == 0 36 | 37 | item = pystac.Item.from_file(item_path) 38 | asset = item.assets["test-asset"] 39 | assert isinstance(asset, pystac.Asset), asset 40 | assert asset.href is not None, asset.to_dict() 41 | assert os.path.isfile(asset.href), asset.to_dict() 42 | assert asset.title == "test", asset.to_dict() 43 | assert asset.description == "placeholder asset", asset.to_dict() 44 | assert asset.roles == ["thumbnail", "overview"] 45 | 46 | 47 | def test_add_asset_to_item_with_relative_paths(tmp_item_path: str) -> None: 48 | asset_path = test_data.get_path("data-files/core/byte.tif") 49 | item_path = tmp_item_path 50 | runner = CliRunner() 51 | result = runner.invoke( 52 | cli, 53 | [ 54 | "add-asset", 55 | pystac.utils.make_relative_href(item_path, os.getcwd(), start_is_dir=True), 56 | "test-asset", 57 | pystac.utils.make_relative_href(asset_path, os.getcwd(), start_is_dir=True), 58 | ], 59 | ) 60 | assert result.exit_code == 0 61 | -------------------------------------------------------------------------------- /tests/cli/commands/test_add_raster.py: -------------------------------------------------------------------------------- 1 | import pystac 2 | import pystac.utils 3 | from click.testing import CliRunner 4 | 5 | from stactools.cli.cli import cli 6 | from tests.conftest import expected_json 7 | 8 | 9 | def test_add_raster_to_items(tmp_planet_disaster: pystac.Collection): 10 | collection = tmp_planet_disaster 11 | collection_path = collection.get_self_href() 12 | items = list(collection.get_items(recursive=True)) 13 | item_path = pystac.utils.make_absolute_href( 14 | items[0].get_self_href(), collection_path 15 | ) 16 | 17 | runner = CliRunner() 18 | result = runner.invoke(cli, ["add-raster", item_path]) 19 | assert result.exit_code == 0 20 | 21 | updated = pystac.read_file(collection_path) 22 | item = list(updated.get_items(recursive=True))[0] 23 | asset = item.get_assets().get("analytic") 24 | assert asset is not None 25 | expected = expected_json("rasterbands.json") 26 | for a, b in zip(expected, asset.to_dict().get("raster:bands")): 27 | assert a == b 28 | -------------------------------------------------------------------------------- /tests/cli/commands/test_create.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from click.testing import CliRunner 4 | 5 | from stactools.cli.cli import cli 6 | from tests import test_data 7 | 8 | 9 | def test_create_item(): 10 | path = test_data.get_path("data-files/core/byte.tif") 11 | runner = CliRunner() 12 | result = runner.invoke(cli, ["create-item", path]) 13 | assert result.exit_code == 0 14 | d = json.loads(result.output) 15 | assert list(d["assets"].keys()) == ["data"] 16 | 17 | 18 | def test_create_item_with_asset_key(): 19 | path = test_data.get_path("data-files/core/byte.tif") 20 | runner = CliRunner() 21 | result = runner.invoke(cli, ["create-item", path, "foo"]) 22 | assert result.exit_code == 0 23 | d = json.loads(result.output) 24 | assert list(d["assets"].keys()) == ["foo"] 25 | 26 | 27 | def test_create_item_with_asset_roles(): 28 | path = test_data.get_path("data-files/core/byte.tif") 29 | runner = CliRunner() 30 | result = runner.invoke(cli, ["create-item", path, "-r", "reference"]) 31 | assert result.exit_code == 0 32 | d = json.loads(result.output) 33 | assert d["assets"]["data"]["roles"] == ["reference"] 34 | -------------------------------------------------------------------------------- /tests/cli/commands/test_info.py: -------------------------------------------------------------------------------- 1 | import pystac 2 | from click.testing import CliRunner 3 | 4 | from stactools.cli.cli import cli 5 | 6 | 7 | def test_info(planet_disaster: pystac.Collection) -> None: 8 | collection_path = planet_disaster.get_self_href() 9 | 10 | runner = CliRunner() 11 | result = runner.invoke(cli, ["info", collection_path]) 12 | assert result.exit_code == 0 13 | 14 | 15 | def test_describe(planet_disaster: pystac.Collection) -> None: 16 | collection_path = planet_disaster.get_self_href() 17 | 18 | runner = CliRunner() 19 | result = runner.invoke(cli, ["describe", collection_path]) 20 | assert result.exit_code == 0 21 | -------------------------------------------------------------------------------- /tests/cli/commands/test_lint.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from click.testing import CliRunner 3 | 4 | from stactools.cli.cli import cli 5 | from tests import test_data 6 | 7 | pytest.importorskip("stac_check") 8 | 9 | 10 | def test_invalid_item() -> None: 11 | path = test_data.get_path("data-files/linting/core-item.json") 12 | 13 | runner = CliRunner() 14 | result = runner.invoke(cli, ["lint", path]) 15 | assert result.exit_code == 1 16 | 17 | 18 | def test_collection_with_invalid_name() -> None: 19 | path = test_data.get_path( 20 | "data-files/basic/country-1/area-1-1/collection-invalid.json" 21 | ) 22 | 23 | runner = CliRunner() 24 | result = runner.invoke(cli, ["lint", path]) 25 | assert result.exit_code == 1 26 | -------------------------------------------------------------------------------- /tests/cli/commands/test_summary.py: -------------------------------------------------------------------------------- 1 | from click.testing import CliRunner 2 | 3 | from stactools.cli.cli import cli 4 | from tests import test_data 5 | 6 | 7 | def test_summary() -> None: 8 | path = test_data.get_path("data-files/planet-disaster/collection.json") 9 | 10 | runner = CliRunner() 11 | result = runner.invoke(cli, ["summary", path]) 12 | assert result.exit_code == 0 13 | -------------------------------------------------------------------------------- /tests/cli/commands/test_update_extent.py: -------------------------------------------------------------------------------- 1 | from click.testing import CliRunner 2 | 3 | from stactools.cli.cli import cli 4 | from tests import test_data 5 | 6 | 7 | def test_update_extent(): 8 | path = test_data.get_path( 9 | "data-files/basic/country-1/area-1-1/collection.json", 10 | ) 11 | runner = CliRunner() 12 | result = runner.invoke(cli, ["update-extent", path]) 13 | assert result.exit_code == 0 14 | -------------------------------------------------------------------------------- /tests/cli/commands/test_update_geometry.py: -------------------------------------------------------------------------------- 1 | import shutil 2 | from pathlib import Path 3 | 4 | from click.testing import CliRunner 5 | 6 | from stactools.cli.cli import cli 7 | from tests import test_data 8 | 9 | 10 | def test_update_geometry(tmp_path: Path) -> None: 11 | item_path = test_data.get_path( 12 | "data-files/raster_footprint/LC08_L1TP_198029_20220331_20220406_02_T1_B2.json" 13 | ) 14 | asset_path = test_data.get_path( 15 | "data-files/raster_footprint/LC08_L1TP_198029_20220331_20220406_02_T1_B2.TIF" 16 | ) 17 | item_path = shutil.copy(item_path, str(tmp_path)) 18 | asset_path = shutil.copy(asset_path, str(tmp_path)) 19 | 20 | runner = CliRunner() 21 | result = runner.invoke(cli, ["update-geometry", item_path]) 22 | assert result.exit_code == 0 23 | -------------------------------------------------------------------------------- /tests/cli/commands/test_validate.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from click.testing import CliRunner 3 | 4 | from stactools.cli.cli import cli 5 | from tests import test_data 6 | 7 | pytest.importorskip("stac_validator") 8 | 9 | 10 | def test_valid_item() -> None: 11 | path = test_data.get_path( 12 | "data-files/basic/country-1/area-1-1/" "area-1-1-imagery/area-1-1-imagery.json" 13 | ) 14 | runner = CliRunner() 15 | result = runner.invoke( 16 | cli, 17 | [ 18 | "validate", 19 | path, 20 | "--no-validate-assets", 21 | ], 22 | ) 23 | assert result.exit_code == 0 24 | 25 | 26 | @pytest.mark.parametrize( 27 | "path", 28 | [ 29 | ( 30 | "data-files/basic/country-1/area-1-1/" 31 | "area-1-1-imagery/area-1-1-imagery-invalid.json" 32 | ), 33 | "data-files/basic/country-1/area-1-1/collection-invalid.json", 34 | ], 35 | ) 36 | def test_invalid(path: str) -> None: 37 | runner = CliRunner() 38 | result = runner.invoke(cli, ["validate", test_data.get_path(path)]) 39 | assert result.exit_code == 1 40 | 41 | 42 | def test_collection_invalid_asset() -> None: 43 | path = test_data.get_path( 44 | "data-files/basic/country-1" "/area-1-1/area-1-1-imagery/area-1-1-imagery.json" 45 | ) 46 | runner = CliRunner() 47 | result = runner.invoke(cli, ["validate", path]) 48 | assert result.exit_code == 0, "Unreachable links aren't an error" 49 | -------------------------------------------------------------------------------- /tests/cli/commands/test_version.py: -------------------------------------------------------------------------------- 1 | import pystac 2 | from click.testing import CliRunner 3 | 4 | import stactools 5 | from stactools.cli.cli import cli 6 | from stactools.core.utils.subprocess import call 7 | 8 | 9 | def test_hello_world(): 10 | runner = CliRunner() 11 | result = runner.invoke(cli, ["version"]) 12 | assert result.exit_code == 0 13 | 14 | assert result.output == ( 15 | f"stactools version {stactools.core.__version__}\n" 16 | f"PySTAC version {pystac.__version__}\n" 17 | f"STAC version {pystac.version.get_stac_version()}\n" 18 | ) 19 | 20 | 21 | def test_entry_point(): 22 | result = call(["stac", "version"]) 23 | assert result == 0 24 | -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | import json 2 | import shutil 3 | from pathlib import Path 4 | 5 | import pystac 6 | import pytest 7 | 8 | from tests import test_data 9 | 10 | 11 | def expected_json(filename): 12 | path = Path(__file__).resolve().parent / "expected" / filename 13 | with open(path) as f: 14 | return json.load(f) 15 | 16 | 17 | @pytest.fixture(scope="module") 18 | def planet_disaster() -> pystac.Collection: 19 | return pystac.Collection.from_file( 20 | test_data.get_path("data-files/planet-disaster/collection.json") 21 | ) 22 | 23 | 24 | @pytest.fixture(scope="function") 25 | def tmp_planet_disaster(tmp_path: Path) -> pystac.Collection: 26 | src = test_data.get_path("data-files/planet-disaster") 27 | dst = tmp_path / "planet-disaster" 28 | shutil.copytree(src, str(dst)) 29 | 30 | return pystac.Collection.from_file(str(dst / "collection.json")) 31 | 32 | 33 | @pytest.fixture(scope="function") 34 | def tmp_item_path(tmp_path: Path) -> str: 35 | src = test_data.get_path("data-files/core/simple-item.json") 36 | dst = tmp_path / "item.json" 37 | shutil.copyfile(src, dst) 38 | return str(dst) 39 | 40 | 41 | @pytest.fixture(scope="function") 42 | def tmp_asset_path(tmp_path: Path) -> str: 43 | src = test_data.get_path("data-files/core/byte.tif") 44 | dst = tmp_path / "byte.tif" 45 | shutil.copyfile(src, dst) 46 | return str(dst) 47 | -------------------------------------------------------------------------------- /tests/core/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stac-utils/stactools/8acd72d4d8914b680e747d655e5964cf53280a27/tests/core/__init__.py -------------------------------------------------------------------------------- /tests/core/test_create.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | 4 | import pytest 5 | from pystac.extensions.projection import ProjectionExtension 6 | 7 | from stactools.core import create 8 | from tests import test_data 9 | 10 | 11 | @pytest.fixture(scope="module") 12 | def asset_path() -> str: 13 | return test_data.get_path( 14 | "data-files/planet-disaster/hurricane-harvey/" 15 | "hurricane-harvey-0831/20170831_172754_101c/20170831_172754_101c_3b_Visual.tif" 16 | ) 17 | 18 | 19 | def test_one_datetime(asset_path: str) -> None: 20 | item = create.item(asset_path) 21 | assert os.path.splitext(os.path.basename(asset_path))[0] == item.id 22 | assert item.datetime is not None 23 | 24 | # convert any tuples to lists 25 | geojson = json.loads(json.dumps(item.geometry)) 26 | assert geojson == { 27 | "type": "Polygon", 28 | "coordinates": [ 29 | [ 30 | [-95.780872, 29.517294], 31 | [-95.783782, 29.623358], 32 | [-96.041791, 29.617689], 33 | [-96.038613, 29.511649], 34 | [-95.780872, 29.517294], 35 | ] 36 | ], 37 | } 38 | assert item.bbox == [-96.041791, 29.511649, -95.780872, 29.623358] 39 | assert item.common_metadata.start_datetime is None 40 | assert item.common_metadata.end_datetime is None 41 | 42 | projection = ProjectionExtension.ext(item) 43 | assert projection.epsg == 32615 44 | assert projection.wkt2 is None 45 | assert projection.projjson is None 46 | assert projection.transform == [ 47 | 97.69921875, 48 | 0.0, 49 | 205437.0, 50 | 0.0, 51 | -45.9609375, 52 | 3280290.0, 53 | ] 54 | 55 | assert projection.shape == (256, 256) 56 | 57 | data = item.assets["data"] 58 | assert data.href == asset_path 59 | assert data.title is None 60 | assert data.description is None 61 | assert data.roles == ["data"] 62 | assert data.media_type is None 63 | item.validate() 64 | 65 | 66 | def test_read_href_modifer(asset_path: str) -> None: 67 | did_it = False 68 | 69 | def do_it(href: str) -> str: 70 | nonlocal did_it 71 | did_it = True 72 | return href 73 | 74 | item = create.item(asset_path, read_href_modifier=do_it) 75 | assert did_it 76 | assert item.id == "20170831_172754_101c_3b_Visual" 77 | -------------------------------------------------------------------------------- /tests/core/test_io.py: -------------------------------------------------------------------------------- 1 | import io 2 | from pathlib import Path 3 | from unittest.mock import create_autospec, patch 4 | 5 | import pystac 6 | 7 | import stactools.core.io 8 | from stactools.core import use_fsspec 9 | 10 | 11 | def test_fsspec_io(tmp_path: Path): 12 | use_fsspec() 13 | 14 | catalog_url = ( 15 | "https://raw.githubusercontent.com/stac-utils/pystac/v0.5.2/tests/data-files/" 16 | "catalogs/test-case-1/catalog.json" 17 | ) 18 | 19 | cat = pystac.read_file(catalog_url) 20 | col = cat.get_child("country-1") 21 | assert len(list(col.get_children())) == 2 22 | 23 | cat.normalize_and_save(str(tmp_path), pystac.CatalogType.SELF_CONTAINED) 24 | 25 | cat2 = pystac.read_file(str(tmp_path / "catalog.json")) 26 | col2 = cat2.get_child("country-1") 27 | assert len(list(col2.get_children())) == 2 28 | 29 | 30 | @patch("stactools.core.io.fsspec.open") 31 | def test_fsspec_kwargs(mock_open): 32 | open_file = create_autospec(io.TextIOBase) 33 | open_file.read.return_value = "string" 34 | use_fsspec() 35 | url = "url" 36 | mock_open.return_value.__enter__.return_value = open_file 37 | stactools.core.io.read_text(url, requester_pays=True) 38 | mock_open.assert_called_with(url, "r", requester_pays=True) 39 | -------------------------------------------------------------------------------- /tests/core/test_projection.py: -------------------------------------------------------------------------------- 1 | from shapely.geometry import Point 2 | 3 | from stactools.core import projection 4 | 5 | 6 | def test_no_precision() -> None: 7 | # This errors in stactools v0.5.0 because precision is None (needs to be an integer) 8 | projection.reproject_shape("EPSG:4326", "EPSG:4326", Point((0, 0))) 9 | -------------------------------------------------------------------------------- /tests/core/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stac-utils/stactools/8acd72d4d8914b680e747d655e5964cf53280a27/tests/core/utils/__init__.py -------------------------------------------------------------------------------- /tests/core/utils/test_convert.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | 3 | import rasterio 4 | 5 | from stactools.core import utils 6 | from stactools.core.utils.convert import cogify, cogify_subdatasets 7 | from tests import test_data 8 | 9 | 10 | def test_default(tmp_path: Path): 11 | infile = test_data.get_path("data-files/core/byte.tif") 12 | outfile = tmp_path / "byte.tif" 13 | cogify(infile, str(outfile)) 14 | 15 | assert outfile.exists() 16 | with rasterio.open(outfile) as dataset: 17 | assert dataset.compression == rasterio.enums.Compression.deflate 18 | 19 | 20 | def test_profile(tmp_path: Path): 21 | infile = test_data.get_path("data-files/core/byte.tif") 22 | outfile = tmp_path / "byte.tif" 23 | 24 | cogify(infile, str(outfile), profile={"compress": "lzw"}) 25 | 26 | assert outfile.exists() 27 | with rasterio.open(outfile) as dataset: 28 | assert dataset.compression == rasterio.enums.Compression.lzw 29 | 30 | 31 | def test_subdataset(tmp_path: Path): 32 | infile = test_data.get_path("data-files/hdf/AMSR_E_L3_RainGrid_B05_200707.h5") 33 | with utils.ignore_not_georeferenced(): 34 | paths, names = cogify_subdatasets(infile, str(tmp_path)) 35 | 36 | assert set(names) == { 37 | "MonthlyRainTotal_GeoGrid_Data_Fields_RrLandRain", 38 | "MonthlyRainTotal_GeoGrid_Data_Fields_TbOceanRain", 39 | } 40 | for path in paths: 41 | assert Path(path).exists() 42 | with utils.ignore_not_georeferenced(): 43 | with rasterio.open(path) as dataset: 44 | assert dataset.compression == rasterio.enums.Compression.deflate 45 | -------------------------------------------------------------------------------- /tests/data-files/basic/catalog.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Catalog", 3 | "id": "test", 4 | "stac_version": "1.0.0", 5 | "description": "test catalog", 6 | "links": [ 7 | { 8 | "rel": "child", 9 | "href": "./country-1/catalog.json", 10 | "type": "application/json" 11 | }, 12 | { 13 | "rel": "child", 14 | "href": "./country-2/catalog.json", 15 | "type": "application/json" 16 | }, 17 | { 18 | "rel": "root", 19 | "href": "./catalog.json", 20 | "type": "application/json" 21 | } 22 | ], 23 | "stac_extensions": [] 24 | } -------------------------------------------------------------------------------- /tests/data-files/basic/country-1/area-1-1/area-1-1-imagery/area-1-1-imagery-invalid.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Feature", 3 | "stac_version": "1.0.0", 4 | "id": "area-1-1-imagery", 5 | "properties": { 6 | "datetime": "2019-10-04T18:55:37Z" 7 | }, 8 | "geometry": { 9 | "type": "Polygon", 10 | "coordinates": [ 11 | [ 12 | [ 13 | -2.5048828125, 14 | 3.8916575492899987 15 | ], 16 | [ 17 | -1.9610595703125, 18 | 3.8916575492899987 19 | ], 20 | [ 21 | -1.9610595703125, 22 | 4.275202171119132 23 | ], 24 | [ 25 | -2.5048828125, 26 | 4.275202171119132 27 | ], 28 | [ 29 | -2.5048828125, 30 | 3.8916575492899987 31 | ] 32 | ] 33 | ] 34 | }, 35 | "links": [ 36 | { 37 | "rel": "root", 38 | "href": "../../../catalog.json", 39 | "type": "application/json" 40 | }, 41 | { 42 | "rel": "parent", 43 | "href": "../collection.json", 44 | "type": "application/json" 45 | } 46 | ], 47 | "assets": { 48 | "ortho": { 49 | "href": "http://example.com/area-1-1_ortho.tif", 50 | "type": "image/vnd.stac.geotiff" 51 | }, 52 | "dsm": { 53 | "href": "http://example.com/area-1-1_dsm.tif", 54 | "type": "image/vnd.stac.geotiff" 55 | } 56 | }, 57 | "bbox": [ 58 | -2.5048828125, 59 | 3.8916575492899987, 60 | -1.9610595703125, 61 | 3.8916575492899987 62 | ], 63 | "stac_extensions": [], 64 | "collection": "area-1-1" 65 | } -------------------------------------------------------------------------------- /tests/data-files/basic/country-1/area-1-1/area-1-1-imagery/area-1-1-imagery.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Feature", 3 | "stac_version": "1.0.0", 4 | "id": "area-1-1-imagery", 5 | "properties": { 6 | "datetime": "2019-10-04T18:55:37Z" 7 | }, 8 | "geometry": { 9 | "type": "Polygon", 10 | "coordinates": [ 11 | [ 12 | [ 13 | -2.5048828125, 14 | 3.8916575492899987 15 | ], 16 | [ 17 | -1.9610595703125, 18 | 3.8916575492899987 19 | ], 20 | [ 21 | -1.9610595703125, 22 | 4.275202171119132 23 | ], 24 | [ 25 | -2.5048828125, 26 | 4.275202171119132 27 | ], 28 | [ 29 | -2.5048828125, 30 | 3.8916575492899987 31 | ] 32 | ] 33 | ] 34 | }, 35 | "links": [ 36 | { 37 | "rel": "collection", 38 | "href": "../collection.json", 39 | "type": "application/json" 40 | }, 41 | { 42 | "rel": "root", 43 | "href": "../../../catalog.json", 44 | "type": "application/json" 45 | }, 46 | { 47 | "rel": "parent", 48 | "href": "../collection.json", 49 | "type": "application/json" 50 | } 51 | ], 52 | "assets": { 53 | "ortho": { 54 | "href": "http://example.com/area-1-1_ortho.tif", 55 | "type": "image/vnd.stac.geotiff" 56 | }, 57 | "dsm": { 58 | "href": "http://example.com/area-1-1_dsm.tif", 59 | "type": "image/vnd.stac.geotiff" 60 | } 61 | }, 62 | "bbox": [ 63 | -2.5048828125, 64 | 3.8916575492899987, 65 | -1.9610595703125, 66 | 3.8916575492899987 67 | ], 68 | "stac_extensions": [], 69 | "collection": "area-1-1" 70 | } -------------------------------------------------------------------------------- /tests/data-files/basic/country-1/area-1-1/area-1-1-labels/area-1-1-labels.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Feature", 3 | "stac_version": "1.0.0", 4 | "id": "area-1-1-labels", 5 | "properties": { 6 | "datetime": "2019-10-04T18:55:37Z", 7 | "label:description": "labels for area-1-1", 8 | "label:type": "vector", 9 | "label:properties": [ 10 | "label" 11 | ], 12 | "label:classes": [ 13 | { 14 | "name": "label", 15 | "classes": [ 16 | "one", 17 | "two" 18 | ] 19 | } 20 | ], 21 | "label:methods": [ 22 | "manual" 23 | ], 24 | "label:tasks": [ 25 | "classification" 26 | ] 27 | }, 28 | "geometry": { 29 | "type": "Polygon", 30 | "coordinates": [ 31 | [ 32 | [ 33 | -2.5048828125, 34 | 3.8916575492899987 35 | ], 36 | [ 37 | -1.9610595703125, 38 | 3.8916575492899987 39 | ], 40 | [ 41 | -1.9610595703125, 42 | 4.275202171119132 43 | ], 44 | [ 45 | -2.5048828125, 46 | 4.275202171119132 47 | ], 48 | [ 49 | -2.5048828125, 50 | 3.8916575492899987 51 | ] 52 | ] 53 | ] 54 | }, 55 | "links": [ 56 | { 57 | "rel": "source", 58 | "href": "../area-1-1-imagery/area-1-1-imagery.json", 59 | "type": "application/json" 60 | }, 61 | { 62 | "rel": "collection", 63 | "href": "../collection.json", 64 | "type": "application/json" 65 | }, 66 | { 67 | "rel": "root", 68 | "href": "../../../catalog.json", 69 | "type": "application/json" 70 | }, 71 | { 72 | "rel": "parent", 73 | "href": "../collection.json", 74 | "type": "application/json" 75 | } 76 | ], 77 | "assets": { 78 | "labels": { 79 | "href": "http://example.com/area-1-1-labels.geojson", 80 | "type": "application/geo+json" 81 | } 82 | }, 83 | "bbox": [ 84 | -2.5048828125, 85 | 3.8916575492899987, 86 | -1.9610595703125, 87 | 3.8916575492899987 88 | ], 89 | "stac_extensions": [ 90 | "https://stac-extensions.github.io/label/v1.0.0/schema.json" 91 | ], 92 | "collection": "area-1-1" 93 | } -------------------------------------------------------------------------------- /tests/data-files/basic/country-1/area-1-1/collection-invalid.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Collection", 3 | "id": "area-1-1", 4 | "stac_version": "1.0.0", 5 | "description": "test collection country-1", 6 | "links": [ 7 | { 8 | "rel": "item", 9 | "href": "./area-1-1-imagery/area-1-1-imagery-invalid.json", 10 | "type": "application/json" 11 | }, 12 | { 13 | "rel": "item", 14 | "href": "./area-1-1-labels/area-1-1-labels.json", 15 | "type": "application/json" 16 | }, 17 | { 18 | "rel": "root", 19 | "href": "../../catalog.json", 20 | "type": "application/json" 21 | }, 22 | { 23 | "rel": "parent", 24 | "href": "../catalog.json", 25 | "type": "application/json" 26 | } 27 | ], 28 | "stac_extensions": [], 29 | "extent": { 30 | "spatial": { 31 | "bbox": [ 32 | [ 33 | -2.5048828125, 34 | 3.8916575492899987, 35 | -1.9610595703125, 36 | 4.275202171119132 37 | ] 38 | ] 39 | }, 40 | "temporal": { 41 | "interval": [ 42 | [ 43 | "2019-10-04T18:55:37Z", 44 | null 45 | ] 46 | ] 47 | } 48 | }, 49 | "license": "proprietary" 50 | } -------------------------------------------------------------------------------- /tests/data-files/basic/country-1/area-1-1/collection.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Collection", 3 | "id": "area-1-1", 4 | "stac_version": "1.0.0", 5 | "description": "test collection country-1", 6 | "links": [ 7 | { 8 | "rel": "item", 9 | "href": "./area-1-1-imagery/area-1-1-imagery.json", 10 | "type": "application/json" 11 | }, 12 | { 13 | "rel": "item", 14 | "href": "./area-1-1-labels/area-1-1-labels.json", 15 | "type": "application/json" 16 | }, 17 | { 18 | "rel": "root", 19 | "href": "../../catalog.json", 20 | "type": "application/json" 21 | }, 22 | { 23 | "rel": "parent", 24 | "href": "../catalog.json", 25 | "type": "application/json" 26 | } 27 | ], 28 | "stac_extensions": [], 29 | "extent": { 30 | "spatial": { 31 | "bbox": [ 32 | [ 33 | -2.5048828125, 34 | 3.8916575492899987, 35 | -1.9610595703125, 36 | 4.275202171119132 37 | ] 38 | ] 39 | }, 40 | "temporal": { 41 | "interval": [ 42 | [ 43 | "2019-10-04T18:55:37Z", 44 | null 45 | ] 46 | ] 47 | } 48 | }, 49 | "license": "proprietary" 50 | } -------------------------------------------------------------------------------- /tests/data-files/basic/country-1/area-1-2/area-1-2-imagery/area-1-2-imagery.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Feature", 3 | "stac_version": "1.0.0", 4 | "id": "area-1-2-imagery", 5 | "properties": { 6 | "datetime": "2019-10-04T18:55:37Z" 7 | }, 8 | "geometry": { 9 | "type": "Polygon", 10 | "coordinates": [ 11 | [ 12 | [ 13 | -2.5048828125, 14 | 3.8916575492899987 15 | ], 16 | [ 17 | -1.9610595703125, 18 | 3.8916575492899987 19 | ], 20 | [ 21 | -1.9610595703125, 22 | 4.275202171119132 23 | ], 24 | [ 25 | -2.5048828125, 26 | 4.275202171119132 27 | ], 28 | [ 29 | -2.5048828125, 30 | 3.8916575492899987 31 | ] 32 | ] 33 | ] 34 | }, 35 | "links": [ 36 | { 37 | "rel": "collection", 38 | "href": "../collection.json", 39 | "type": "application/json" 40 | }, 41 | { 42 | "rel": "root", 43 | "href": "../../../catalog.json", 44 | "type": "application/json" 45 | }, 46 | { 47 | "rel": "parent", 48 | "href": "../collection.json", 49 | "type": "application/json" 50 | } 51 | ], 52 | "assets": { 53 | "ortho": { 54 | "href": "http://example.com/area-1-2_ortho.tif", 55 | "type": "image/vnd.stac.geotiff" 56 | }, 57 | "dsm": { 58 | "href": "http://example.com/area-1-2_dsm.tif", 59 | "type": "image/vnd.stac.geotiff" 60 | } 61 | }, 62 | "bbox": [ 63 | -2.5048828125, 64 | 3.8916575492899987, 65 | -1.9610595703125, 66 | 3.8916575492899987 67 | ], 68 | "stac_extensions": [], 69 | "collection": "area-1-2" 70 | } -------------------------------------------------------------------------------- /tests/data-files/basic/country-1/area-1-2/area-1-2-labels/area-1-2-labels.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Feature", 3 | "stac_version": "1.0.0", 4 | "id": "area-1-2-labels", 5 | "properties": { 6 | "datetime": "2019-10-04T18:55:37Z", 7 | "label:description": "labels for area-1-2", 8 | "label:type": "vector", 9 | "label:properties": [ 10 | "label" 11 | ], 12 | "label:classes": [ 13 | { 14 | "name": "label", 15 | "classes": [ 16 | "one", 17 | "two" 18 | ] 19 | } 20 | ], 21 | "label:methods": [ 22 | "manual" 23 | ], 24 | "label:tasks": [ 25 | "classification" 26 | ] 27 | }, 28 | "geometry": { 29 | "type": "Polygon", 30 | "coordinates": [ 31 | [ 32 | [ 33 | -2.5048828125, 34 | 3.8916575492899987 35 | ], 36 | [ 37 | -1.9610595703125, 38 | 3.8916575492899987 39 | ], 40 | [ 41 | -1.9610595703125, 42 | 4.275202171119132 43 | ], 44 | [ 45 | -2.5048828125, 46 | 4.275202171119132 47 | ], 48 | [ 49 | -2.5048828125, 50 | 3.8916575492899987 51 | ] 52 | ] 53 | ] 54 | }, 55 | "links": [ 56 | { 57 | "rel": "source", 58 | "href": "../area-1-2-imagery/area-1-2-imagery.json", 59 | "type": "application/json" 60 | }, 61 | { 62 | "rel": "collection", 63 | "href": "../collection.json", 64 | "type": "application/json" 65 | }, 66 | { 67 | "rel": "root", 68 | "href": "../../../catalog.json", 69 | "type": "application/json" 70 | }, 71 | { 72 | "rel": "parent", 73 | "href": "../collection.json", 74 | "type": "application/json" 75 | } 76 | ], 77 | "assets": { 78 | "labels": { 79 | "href": "http://example.com/area-1-2-labels.geojson", 80 | "type": "application/geo+json" 81 | } 82 | }, 83 | "bbox": [ 84 | -2.5048828125, 85 | 3.8916575492899987, 86 | -1.9610595703125, 87 | 3.8916575492899987 88 | ], 89 | "stac_extensions": [ 90 | "https://stac-extensions.github.io/label/v1.0.0/schema.json" 91 | ], 92 | "collection": "area-1-2" 93 | } -------------------------------------------------------------------------------- /tests/data-files/basic/country-1/area-1-2/collection.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Collection", 3 | "id": "area-1-2", 4 | "stac_version": "1.0.0", 5 | "description": "test collection country-1", 6 | "links": [ 7 | { 8 | "rel": "item", 9 | "href": "./area-1-2-imagery/area-1-2-imagery.json", 10 | "type": "application/json" 11 | }, 12 | { 13 | "rel": "item", 14 | "href": "./area-1-2-labels/area-1-2-labels.json", 15 | "type": "application/json" 16 | }, 17 | { 18 | "rel": "root", 19 | "href": "../../catalog.json", 20 | "type": "application/json" 21 | }, 22 | { 23 | "rel": "parent", 24 | "href": "../catalog.json", 25 | "type": "application/json" 26 | } 27 | ], 28 | "stac_extensions": [], 29 | "extent": { 30 | "spatial": { 31 | "bbox": [ 32 | [ 33 | -2.5048828125, 34 | 3.8916575492899987, 35 | -1.9610595703125, 36 | 4.275202171119132 37 | ] 38 | ] 39 | }, 40 | "temporal": { 41 | "interval": [ 42 | [ 43 | "2019-10-04T18:55:37Z", 44 | null 45 | ] 46 | ] 47 | } 48 | }, 49 | "license": "proprietary" 50 | } -------------------------------------------------------------------------------- /tests/data-files/basic/country-1/catalog.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Catalog", 3 | "id": "country-1", 4 | "stac_version": "1.0.0", 5 | "description": "test catalog country-1", 6 | "links": [ 7 | { 8 | "rel": "child", 9 | "href": "./area-1-1/collection.json", 10 | "type": "application/json" 11 | }, 12 | { 13 | "rel": "child", 14 | "href": "./area-1-2/collection.json", 15 | "type": "application/json" 16 | }, 17 | { 18 | "rel": "root", 19 | "href": "../catalog.json", 20 | "type": "application/json" 21 | }, 22 | { 23 | "rel": "parent", 24 | "href": "../catalog.json", 25 | "type": "application/json" 26 | } 27 | ], 28 | "stac_extensions": [] 29 | } -------------------------------------------------------------------------------- /tests/data-files/basic/country-2/area-2-1/area-2-1-imagery/area-2-1-imagery.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Feature", 3 | "stac_version": "1.0.0", 4 | "id": "area-2-1-imagery", 5 | "properties": { 6 | "datetime": "2019-10-04T18:55:37Z" 7 | }, 8 | "geometry": { 9 | "type": "Polygon", 10 | "coordinates": [ 11 | [ 12 | [ 13 | -2.5048828125, 14 | 3.8916575492899987 15 | ], 16 | [ 17 | -1.9610595703125, 18 | 3.8916575492899987 19 | ], 20 | [ 21 | -1.9610595703125, 22 | 4.275202171119132 23 | ], 24 | [ 25 | -2.5048828125, 26 | 4.275202171119132 27 | ], 28 | [ 29 | -2.5048828125, 30 | 3.8916575492899987 31 | ] 32 | ] 33 | ] 34 | }, 35 | "links": [ 36 | { 37 | "rel": "collection", 38 | "href": "../collection.json", 39 | "type": "application/json" 40 | }, 41 | { 42 | "rel": "root", 43 | "href": "../../../catalog.json", 44 | "type": "application/json" 45 | }, 46 | { 47 | "rel": "parent", 48 | "href": "../collection.json", 49 | "type": "application/json" 50 | } 51 | ], 52 | "assets": { 53 | "ortho": { 54 | "href": "http://example.com/area-2-1_ortho.tif", 55 | "type": "image/vnd.stac.geotiff" 56 | }, 57 | "dsm": { 58 | "href": "http://example.com/area-2-1_dsm.tif", 59 | "type": "image/vnd.stac.geotiff" 60 | } 61 | }, 62 | "bbox": [ 63 | -2.5048828125, 64 | 3.8916575492899987, 65 | -1.9610595703125, 66 | 3.8916575492899987 67 | ], 68 | "stac_extensions": [], 69 | "collection": "area-2-1" 70 | } -------------------------------------------------------------------------------- /tests/data-files/basic/country-2/area-2-1/area-2-1-labels/area-2-1-labels.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Feature", 3 | "stac_version": "1.0.0", 4 | "id": "area-2-1-labels", 5 | "properties": { 6 | "datetime": "2019-10-04T18:55:37Z", 7 | "label:description": "labels for area-2-1", 8 | "label:type": "vector", 9 | "label:properties": [ 10 | "label" 11 | ], 12 | "label:classes": [ 13 | { 14 | "name": "label", 15 | "classes": [ 16 | "one", 17 | "two" 18 | ] 19 | } 20 | ], 21 | "label:methods": [ 22 | "manual" 23 | ], 24 | "label:tasks": [ 25 | "classification" 26 | ] 27 | }, 28 | "geometry": { 29 | "type": "Polygon", 30 | "coordinates": [ 31 | [ 32 | [ 33 | -2.5048828125, 34 | 3.8916575492899987 35 | ], 36 | [ 37 | -1.9610595703125, 38 | 3.8916575492899987 39 | ], 40 | [ 41 | -1.9610595703125, 42 | 4.275202171119132 43 | ], 44 | [ 45 | -2.5048828125, 46 | 4.275202171119132 47 | ], 48 | [ 49 | -2.5048828125, 50 | 3.8916575492899987 51 | ] 52 | ] 53 | ] 54 | }, 55 | "links": [ 56 | { 57 | "rel": "source", 58 | "href": "../area-2-1-imagery/area-2-1-imagery.json", 59 | "type": "application/json" 60 | }, 61 | { 62 | "rel": "collection", 63 | "href": "../collection.json", 64 | "type": "application/json" 65 | }, 66 | { 67 | "rel": "root", 68 | "href": "../../../catalog.json", 69 | "type": "application/json" 70 | }, 71 | { 72 | "rel": "parent", 73 | "href": "../collection.json", 74 | "type": "application/json" 75 | } 76 | ], 77 | "assets": { 78 | "labels": { 79 | "href": "http://example.com/area-2-1-labels.geojson", 80 | "type": "application/geo+json" 81 | } 82 | }, 83 | "bbox": [ 84 | -2.5048828125, 85 | 3.8916575492899987, 86 | -1.9610595703125, 87 | 3.8916575492899987 88 | ], 89 | "stac_extensions": [ 90 | "https://stac-extensions.github.io/label/v1.0.0/schema.json" 91 | ], 92 | "collection": "area-2-1" 93 | } -------------------------------------------------------------------------------- /tests/data-files/basic/country-2/area-2-1/collection.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Collection", 3 | "id": "area-2-1", 4 | "stac_version": "1.0.0", 5 | "description": "test collection country-2", 6 | "links": [ 7 | { 8 | "rel": "item", 9 | "href": "./area-2-1-imagery/area-2-1-imagery.json", 10 | "type": "application/json" 11 | }, 12 | { 13 | "rel": "item", 14 | "href": "./area-2-1-labels/area-2-1-labels.json", 15 | "type": "application/json" 16 | }, 17 | { 18 | "rel": "root", 19 | "href": "../../catalog.json", 20 | "type": "application/json" 21 | }, 22 | { 23 | "rel": "parent", 24 | "href": "../catalog.json", 25 | "type": "application/json" 26 | } 27 | ], 28 | "stac_extensions": [], 29 | "extent": { 30 | "spatial": { 31 | "bbox": [ 32 | [ 33 | -2.5048828125, 34 | 3.8916575492899987, 35 | -1.9610595703125, 36 | 4.275202171119132 37 | ] 38 | ] 39 | }, 40 | "temporal": { 41 | "interval": [ 42 | [ 43 | "2019-10-04T18:55:37Z", 44 | null 45 | ] 46 | ] 47 | } 48 | }, 49 | "license": "proprietary" 50 | } -------------------------------------------------------------------------------- /tests/data-files/basic/country-2/area-2-2/area-2-2-imagery/area-2-2-imagery.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Feature", 3 | "stac_version": "1.0.0", 4 | "id": "area-2-2-imagery", 5 | "properties": { 6 | "datetime": "2019-10-04T18:55:37Z" 7 | }, 8 | "geometry": { 9 | "type": "Polygon", 10 | "coordinates": [ 11 | [ 12 | [ 13 | -2.5048828125, 14 | 3.8916575492899987 15 | ], 16 | [ 17 | -1.9610595703125, 18 | 3.8916575492899987 19 | ], 20 | [ 21 | -1.9610595703125, 22 | 4.275202171119132 23 | ], 24 | [ 25 | -2.5048828125, 26 | 4.275202171119132 27 | ], 28 | [ 29 | -2.5048828125, 30 | 3.8916575492899987 31 | ] 32 | ] 33 | ] 34 | }, 35 | "links": [ 36 | { 37 | "rel": "collection", 38 | "href": "../collection.json", 39 | "type": "application/json" 40 | }, 41 | { 42 | "rel": "root", 43 | "href": "../../../catalog.json", 44 | "type": "application/json" 45 | }, 46 | { 47 | "rel": "parent", 48 | "href": "../collection.json", 49 | "type": "application/json" 50 | } 51 | ], 52 | "assets": { 53 | "ortho": { 54 | "href": "http://example.com/area-2-2_ortho.tif", 55 | "type": "image/vnd.stac.geotiff" 56 | }, 57 | "dsm": { 58 | "href": "http://example.com/area-2-2_dsm.tif", 59 | "type": "image/vnd.stac.geotiff" 60 | } 61 | }, 62 | "bbox": [ 63 | -2.5048828125, 64 | 3.8916575492899987, 65 | -1.9610595703125, 66 | 3.8916575492899987 67 | ], 68 | "stac_extensions": [], 69 | "collection": "area-2-2" 70 | } -------------------------------------------------------------------------------- /tests/data-files/basic/country-2/area-2-2/area-2-2-labels/area-2-2-labels.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Feature", 3 | "stac_version": "1.0.0", 4 | "id": "area-2-2-labels", 5 | "properties": { 6 | "datetime": "2019-10-04T18:55:37Z", 7 | "label:description": "labels for area-2-2", 8 | "label:type": "vector", 9 | "label:properties": [ 10 | "label" 11 | ], 12 | "label:classes": [ 13 | { 14 | "name": "label", 15 | "classes": [ 16 | "one", 17 | "two" 18 | ] 19 | } 20 | ], 21 | "label:methods": [ 22 | "manual" 23 | ], 24 | "label:tasks": [ 25 | "classification" 26 | ] 27 | }, 28 | "geometry": { 29 | "type": "Polygon", 30 | "coordinates": [ 31 | [ 32 | [ 33 | -2.5048828125, 34 | 3.8916575492899987 35 | ], 36 | [ 37 | -1.9610595703125, 38 | 3.8916575492899987 39 | ], 40 | [ 41 | -1.9610595703125, 42 | 4.275202171119132 43 | ], 44 | [ 45 | -2.5048828125, 46 | 4.275202171119132 47 | ], 48 | [ 49 | -2.5048828125, 50 | 3.8916575492899987 51 | ] 52 | ] 53 | ] 54 | }, 55 | "links": [ 56 | { 57 | "rel": "source", 58 | "href": "../area-2-2-imagery/area-2-2-imagery.json", 59 | "type": "application/json" 60 | }, 61 | { 62 | "rel": "collection", 63 | "href": "../collection.json", 64 | "type": "application/json" 65 | }, 66 | { 67 | "rel": "root", 68 | "href": "../../../catalog.json", 69 | "type": "application/json" 70 | }, 71 | { 72 | "rel": "parent", 73 | "href": "../collection.json", 74 | "type": "application/json" 75 | } 76 | ], 77 | "assets": { 78 | "labels": { 79 | "href": "http://example.com/area-2-2-labels.geojson", 80 | "type": "application/geo+json" 81 | } 82 | }, 83 | "bbox": [ 84 | -2.5048828125, 85 | 3.8916575492899987, 86 | -1.9610595703125, 87 | 3.8916575492899987 88 | ], 89 | "stac_extensions": [ 90 | "https://stac-extensions.github.io/label/v1.0.0/schema.json" 91 | ], 92 | "collection": "area-2-2" 93 | } -------------------------------------------------------------------------------- /tests/data-files/basic/country-2/area-2-2/collection.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Collection", 3 | "id": "area-2-2", 4 | "stac_version": "1.0.0", 5 | "description": "test collection country-2", 6 | "links": [ 7 | { 8 | "rel": "item", 9 | "href": "./area-2-2-imagery/area-2-2-imagery.json", 10 | "type": "application/json" 11 | }, 12 | { 13 | "rel": "item", 14 | "href": "./area-2-2-labels/area-2-2-labels.json", 15 | "type": "application/json" 16 | }, 17 | { 18 | "rel": "root", 19 | "href": "../../catalog.json", 20 | "type": "application/json" 21 | }, 22 | { 23 | "rel": "parent", 24 | "href": "../catalog.json", 25 | "type": "application/json" 26 | } 27 | ], 28 | "stac_extensions": [], 29 | "extent": { 30 | "spatial": { 31 | "bbox": [ 32 | [ 33 | -2.5048828125, 34 | 3.8916575492899987, 35 | -1.9610595703125, 36 | 4.275202171119132 37 | ] 38 | ] 39 | }, 40 | "temporal": { 41 | "interval": [ 42 | [ 43 | "2019-10-04T18:55:37Z", 44 | null 45 | ] 46 | ] 47 | } 48 | }, 49 | "license": "proprietary" 50 | } -------------------------------------------------------------------------------- /tests/data-files/basic/country-2/catalog.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Catalog", 3 | "id": "country-2", 4 | "stac_version": "1.0.0", 5 | "description": "test catalog country-2", 6 | "links": [ 7 | { 8 | "rel": "child", 9 | "href": "./area-2-1/collection.json", 10 | "type": "application/json" 11 | }, 12 | { 13 | "rel": "child", 14 | "href": "./area-2-2/collection.json", 15 | "type": "application/json" 16 | }, 17 | { 18 | "rel": "root", 19 | "href": "../catalog.json", 20 | "type": "application/json" 21 | }, 22 | { 23 | "rel": "parent", 24 | "href": "../catalog.json", 25 | "type": "application/json" 26 | } 27 | ], 28 | "stac_extensions": [] 29 | } -------------------------------------------------------------------------------- /tests/data-files/catalogs/collection-assets/catalog.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "examples", 3 | "type": "Catalog", 4 | "stac_version": "1.0.0", 5 | "description": "This catalog is a simple demonstration of an example catalog", 6 | "links": [ 7 | { 8 | "rel": "root", 9 | "href": "./catalog.json", 10 | "type": "application/json" 11 | }, 12 | { 13 | "rel": "child", 14 | "href": "./sentinel-2/collection.json", 15 | "type": "application/json", 16 | "title": "Collection with no items, only assets" 17 | } 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /tests/data-files/core/byte.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stac-utils/stactools/8acd72d4d8914b680e747d655e5964cf53280a27/tests/data-files/core/byte.tif -------------------------------------------------------------------------------- /tests/data-files/core/simple-item.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Feature", 3 | "stac_version": "1.0.0", 4 | "id": "CS3-20160503_132131_05", 5 | "properties": { 6 | "datetime": "2016-05-03T13:22:30.040000Z", 7 | "title": "A CS3 item", 8 | "license": "PDDL-1.0", 9 | "providers": [ 10 | { 11 | "name": "CoolSat", 12 | "roles": [ 13 | "producer", 14 | "licensor" 15 | ], 16 | "url": "https://cool-sat.com/" 17 | } 18 | ] 19 | }, 20 | "geometry": { 21 | "type": "Polygon", 22 | "coordinates": [ 23 | [ 24 | [ 25 | -122.308150179, 26 | 37.488035566 27 | ], 28 | [ 29 | -122.597502109, 30 | 37.538869539 31 | ], 32 | [ 33 | -122.576687533, 34 | 37.613537207 35 | ], 36 | [ 37 | -122.2880486, 38 | 37.562818007 39 | ], 40 | [ 41 | -122.308150179, 42 | 37.488035566 43 | ] 44 | ] 45 | ] 46 | }, 47 | "links": [ 48 | { 49 | "rel": "collection", 50 | "href": "https://raw.githubusercontent.com/radiantearth/stac-spec/v0.8.1/collection-spec/examples/sentinel2.json" 51 | } 52 | ], 53 | "assets": { 54 | "analytic": { 55 | "href": "http://cool-sat.com/catalog/CS3-20160503_132130_04/analytic.tif", 56 | "title": "4-Band Analytic", 57 | "product": "http://cool-sat.com/catalog/products/analytic.json" 58 | }, 59 | "thumbnail": { 60 | "href": "http://cool-sat.com/catalog/CS3-20160503_132130_04/thumbnail.png", 61 | "title": "Thumbnail" 62 | } 63 | }, 64 | "bbox": [ 65 | -122.59750209, 66 | 37.48803556, 67 | -122.2880486, 68 | 37.613537207 69 | ], 70 | "stac_extensions": [], 71 | "collection": "CS3" 72 | } -------------------------------------------------------------------------------- /tests/data-files/external-child/catalog.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "test", 3 | "type": "Catalog", 4 | "stac_extensions": [], 5 | "stac_version": "1.0.0", 6 | "description": "test", 7 | "title": "test", 8 | "links": [ 9 | { 10 | "rel": "child", 11 | "href": "https://raw.githubusercontent.com/radiantearth/stac-spec/v1.0.0/examples/collection.json", 12 | "type": "application/json" 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /tests/data-files/hdf/AMSR_E_L3_RainGrid_B05_200707.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stac-utils/stactools/8acd72d4d8914b680e747d655e5964cf53280a27/tests/data-files/hdf/AMSR_E_L3_RainGrid_B05_200707.h5 -------------------------------------------------------------------------------- /tests/data-files/planet-disaster-v1.0.0-beta.2/hurricane-harvey/catalog.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "hurricane-harvey", 3 | "stac_version": "1.0.0-beta.2", 4 | "description": "Planet Disaster Data makes imagery available directly to the public, volunteers, humanitarian organizations, and other coordinating bodies in support of the International Charter for Space and Major Disasters. This catalog of data is released for Hurricane Harvey, providing a 30 day window pre- and post-disaster. Imagery is provided under Creative Commons licenses, free of charge, with either CC-BY-SA or CC-BY-NC. All new Planet scenes are made available each day, immediately after production. ", 5 | "links": [ 6 | { 7 | "rel": "root", 8 | "href": "../collection.json", 9 | "type": "application/json" 10 | }, 11 | { 12 | "rel": "parent", 13 | "href": "../collection.json", 14 | "type": "application/json" 15 | }, 16 | { 17 | "rel": "child", 18 | "href": "./hurricane-harvey-0831/catalog.json", 19 | "title": "8/31" 20 | } 21 | ], 22 | "title": "Hurricane Harvey" 23 | } -------------------------------------------------------------------------------- /tests/data-files/planet-disaster-v1.0.0-beta.2/hurricane-harvey/hurricane-harvey-0831/catalog.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "hurricane-harvey-0831", 3 | "stac_version": "1.0.0-beta.2", 4 | "description": "Planet Scenes and Composites for Hurricane Harvey on Aug 31, 2017", 5 | "links": [ 6 | { 7 | "rel": "root", 8 | "href": "../../collection.json", 9 | "type": "application/json" 10 | }, 11 | { 12 | "rel": "parent", 13 | "href": "../catalog.json", 14 | "type": "application/json" 15 | }, 16 | { 17 | "rel": "item", 18 | "href": "./20170831_172754_101c/20170831_172754_101c.json", 19 | "title": "20170831_172754_101c" 20 | }, 21 | { 22 | "rel": "item", 23 | "href": "./2017831_195552_SS02/2017831_195552_SS02.json", 24 | "title": "20170831_195552_SS02" 25 | }, 26 | { 27 | "rel": "item", 28 | "href": "./20170831_195425_SS02/20170831_195425_SS02.json", 29 | "title": "20170831_195425_SS02" 30 | }, 31 | { 32 | "rel": "item", 33 | "href": "./20170831_162740_ssc1d1/20170831_162740_ssc1d1.json", 34 | "title": "20170831_162740_ssc1d1" 35 | }, 36 | { 37 | "rel": "item", 38 | "href": "./Houston-East-20170831-103f-100d-0f4f-RGB/Houston-East-20170831-103f-100d-0f4f-RGB.json", 39 | "title": "Houston-East-20170831-103f-100d-0f4f-RGB" 40 | } 41 | ], 42 | "title": "Hurricane Harvey 08-31-2017" 43 | } -------------------------------------------------------------------------------- /tests/data-files/planet-disaster/hurricane-harvey/catalog.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Catalog", 3 | "id": "hurricane-harvey", 4 | "stac_version": "1.0.0", 5 | "description": "Planet Disaster Data makes imagery available directly to the public, volunteers, humanitarian organizations, and other coordinating bodies in support of the International Charter for Space and Major Disasters. This catalog of data is released for Hurricane Harvey, providing a 30 day window pre- and post-disaster. Imagery is provided under Creative Commons licenses, free of charge, with either CC-BY-SA or CC-BY-NC. All new Planet scenes are made available each day, immediately after production. ", 6 | "links": [ 7 | { 8 | "rel": "root", 9 | "href": "../collection.json", 10 | "type": "application/json", 11 | "title": "Planet Disaster Data" 12 | }, 13 | { 14 | "rel": "child", 15 | "href": "./hurricane-harvey-0831/catalog.json", 16 | "title": "8/31" 17 | }, 18 | { 19 | "rel": "parent", 20 | "href": "../collection.json", 21 | "type": "application/json" 22 | } 23 | ], 24 | "stac_extensions": [], 25 | "title": "Hurricane Harvey" 26 | } -------------------------------------------------------------------------------- /tests/data-files/planet-disaster/hurricane-harvey/hurricane-harvey-0831/20170831_162740_ssc1d1/SkySat_Freeport_s03_20170831T162740Z.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stac-utils/stactools/8acd72d4d8914b680e747d655e5964cf53280a27/tests/data-files/planet-disaster/hurricane-harvey/hurricane-harvey-0831/20170831_162740_ssc1d1/SkySat_Freeport_s03_20170831T162740Z.png -------------------------------------------------------------------------------- /tests/data-files/planet-disaster/hurricane-harvey/hurricane-harvey-0831/20170831_162740_ssc1d1/SkySat_Freeport_s03_20170831T162740Z.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stac-utils/stactools/8acd72d4d8914b680e747d655e5964cf53280a27/tests/data-files/planet-disaster/hurricane-harvey/hurricane-harvey-0831/20170831_162740_ssc1d1/SkySat_Freeport_s03_20170831T162740Z.tif -------------------------------------------------------------------------------- /tests/data-files/planet-disaster/hurricane-harvey/hurricane-harvey-0831/20170831_172754_101c/20170831_172754_101c_3B_AnalyticMS.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stac-utils/stactools/8acd72d4d8914b680e747d655e5964cf53280a27/tests/data-files/planet-disaster/hurricane-harvey/hurricane-harvey-0831/20170831_172754_101c/20170831_172754_101c_3B_AnalyticMS.tif -------------------------------------------------------------------------------- /tests/data-files/planet-disaster/hurricane-harvey/hurricane-harvey-0831/20170831_172754_101c/20170831_172754_101c_3B_AnalyticMS_DN_udm.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stac-utils/stactools/8acd72d4d8914b680e747d655e5964cf53280a27/tests/data-files/planet-disaster/hurricane-harvey/hurricane-harvey-0831/20170831_172754_101c/20170831_172754_101c_3B_AnalyticMS_DN_udm.tif -------------------------------------------------------------------------------- /tests/data-files/planet-disaster/hurricane-harvey/hurricane-harvey-0831/20170831_172754_101c/20170831_172754_101c_3b_Visual.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stac-utils/stactools/8acd72d4d8914b680e747d655e5964cf53280a27/tests/data-files/planet-disaster/hurricane-harvey/hurricane-harvey-0831/20170831_172754_101c/20170831_172754_101c_3b_Visual.tif -------------------------------------------------------------------------------- /tests/data-files/planet-disaster/hurricane-harvey/hurricane-harvey-0831/20170831_172754_101c/20170831_172754_101c_thumb_large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stac-utils/stactools/8acd72d4d8914b680e747d655e5964cf53280a27/tests/data-files/planet-disaster/hurricane-harvey/hurricane-harvey-0831/20170831_172754_101c/20170831_172754_101c_thumb_large.png -------------------------------------------------------------------------------- /tests/data-files/planet-disaster/hurricane-harvey/hurricane-harvey-0831/20170831_195425_SS02/SkySat_PortArthur_s02_20170831T195425Z.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stac-utils/stactools/8acd72d4d8914b680e747d655e5964cf53280a27/tests/data-files/planet-disaster/hurricane-harvey/hurricane-harvey-0831/20170831_195425_SS02/SkySat_PortArthur_s02_20170831T195425Z.png -------------------------------------------------------------------------------- /tests/data-files/planet-disaster/hurricane-harvey/hurricane-harvey-0831/20170831_195425_SS02/SkySat_PortArthur_s02_20170831T195425Z.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stac-utils/stactools/8acd72d4d8914b680e747d655e5964cf53280a27/tests/data-files/planet-disaster/hurricane-harvey/hurricane-harvey-0831/20170831_195425_SS02/SkySat_PortArthur_s02_20170831T195425Z.tif -------------------------------------------------------------------------------- /tests/data-files/planet-disaster/hurricane-harvey/hurricane-harvey-0831/2017831_195552_SS02/SkySat_20170831T195552Z_RGB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stac-utils/stactools/8acd72d4d8914b680e747d655e5964cf53280a27/tests/data-files/planet-disaster/hurricane-harvey/hurricane-harvey-0831/2017831_195552_SS02/SkySat_20170831T195552Z_RGB.png -------------------------------------------------------------------------------- /tests/data-files/planet-disaster/hurricane-harvey/hurricane-harvey-0831/2017831_195552_SS02/SkySat_20170831T195552Z_RGB.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stac-utils/stactools/8acd72d4d8914b680e747d655e5964cf53280a27/tests/data-files/planet-disaster/hurricane-harvey/hurricane-harvey-0831/2017831_195552_SS02/SkySat_20170831T195552Z_RGB.tif -------------------------------------------------------------------------------- /tests/data-files/planet-disaster/hurricane-harvey/hurricane-harvey-0831/2017831_195552_SS02/SkySat_20170831T195552Z_RGB_Corrected.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stac-utils/stactools/8acd72d4d8914b680e747d655e5964cf53280a27/tests/data-files/planet-disaster/hurricane-harvey/hurricane-harvey-0831/2017831_195552_SS02/SkySat_20170831T195552Z_RGB_Corrected.jpg -------------------------------------------------------------------------------- /tests/data-files/planet-disaster/hurricane-harvey/hurricane-harvey-0831/Houston-East-20170831-103f-100d-0f4f-RGB/Houston-East-20170831-103f-100d-0f4f-3-band.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stac-utils/stactools/8acd72d4d8914b680e747d655e5964cf53280a27/tests/data-files/planet-disaster/hurricane-harvey/hurricane-harvey-0831/Houston-East-20170831-103f-100d-0f4f-RGB/Houston-East-20170831-103f-100d-0f4f-3-band.png -------------------------------------------------------------------------------- /tests/data-files/planet-disaster/hurricane-harvey/hurricane-harvey-0831/Houston-East-20170831-103f-100d-0f4f-RGB/Houston-East-20170831-103f-100d-0f4f-3-band.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stac-utils/stactools/8acd72d4d8914b680e747d655e5964cf53280a27/tests/data-files/planet-disaster/hurricane-harvey/hurricane-harvey-0831/Houston-East-20170831-103f-100d-0f4f-RGB/Houston-East-20170831-103f-100d-0f4f-3-band.tif -------------------------------------------------------------------------------- /tests/data-files/planet-disaster/hurricane-harvey/hurricane-harvey-0831/Houston-East-20170831-103f-100d-0f4f-RGB/Houston-East-20170831-103f-100d-0f4f-RGB.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Feature", 3 | "stac_version": "1.0.0", 4 | "id": "Houston-East-20170831-103f-100d-0f4f-RGB", 5 | "properties": { 6 | "datetime": "2017-08-31T17:24:57.555491Z", 7 | "constellation": "planetscope", 8 | "instruments": [ 9 | "PS2" 10 | ], 11 | "gsd": 3.7, 12 | "eo:cloud_cover": 2, 13 | "view:sun_azimuth": 145.5, 14 | "view:sun_elevation": 64.9, 15 | "view:off_nadir": 0.2, 16 | "pl:ground_control": true, 17 | "proj:epsg": 32615 18 | }, 19 | "geometry": { 20 | "type": "Polygon", 21 | "coordinates": [ 22 | [ 23 | [ 24 | -95.73737276800716, 25 | 30.14525788823348 26 | ], 27 | [ 28 | -95.06532619920118, 29 | 30.157560439570304 30 | ], 31 | [ 32 | -95.05332428370095, 33 | 29.57334931237589 34 | ], 35 | [ 36 | -95.7214758280382, 37 | 29.561332400220497 38 | ], 39 | [ 40 | -95.73737276800716, 41 | 30.14525788823348 42 | ] 43 | ] 44 | ] 45 | }, 46 | "links": [ 47 | { 48 | "rel": "collection", 49 | "href": "../../../collection.json" 50 | }, 51 | { 52 | "rel": "root", 53 | "href": "../../../collection.json", 54 | "type": "application/json", 55 | "title": "Planet Disaster Data" 56 | }, 57 | { 58 | "rel": "parent", 59 | "href": "../catalog.json", 60 | "type": "application/json" 61 | } 62 | ], 63 | "assets": { 64 | "thumbnail": { 65 | "href": "./Houston-East-20170831-103f-100d-0f4f-3-band.png", 66 | "type": "image/png", 67 | "title": "Thumbnail", 68 | "roles": [ 69 | "thumbnail" 70 | ] 71 | }, 72 | "mosaic": { 73 | "href": "./Houston-East-20170831-103f-100d-0f4f-3-band.tif", 74 | "type": "image/vnd.stac.geotiff; cloud-optimized=true", 75 | "title": "3 Band RGB Mosaic", 76 | "roles": [ 77 | "data" 78 | ] 79 | } 80 | }, 81 | "bbox": [ 82 | -95.73737276800716, 83 | 29.561332400220497, 84 | -95.05332428370095, 85 | 30.157560439570304 86 | ], 87 | "stac_extensions": [ 88 | "https://stac-extensions.github.io/eo/v1.0.0/schema.json", 89 | "https://stac-extensions.github.io/view/v1.0.0/schema.json", 90 | "https://stac-extensions.github.io/projection/v1.0.0/schema.json" 91 | ], 92 | "collection": "planet-disaster-data" 93 | } -------------------------------------------------------------------------------- /tests/data-files/planet-disaster/hurricane-harvey/hurricane-harvey-0831/catalog.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Catalog", 3 | "id": "hurricane-harvey-0831", 4 | "stac_version": "1.0.0", 5 | "description": "Planet Scenes and Composites for Hurricane Harvey on Aug 31, 2017", 6 | "links": [ 7 | { 8 | "rel": "root", 9 | "href": "../../collection.json", 10 | "type": "application/json", 11 | "title": "Planet Disaster Data" 12 | }, 13 | { 14 | "rel": "item", 15 | "href": "./20170831_172754_101c/20170831_172754_101c.json", 16 | "title": "20170831_172754_101c" 17 | }, 18 | { 19 | "rel": "item", 20 | "href": "./2017831_195552_SS02/2017831_195552_SS02.json", 21 | "title": "20170831_195552_SS02" 22 | }, 23 | { 24 | "rel": "item", 25 | "href": "./20170831_195425_SS02/20170831_195425_SS02.json", 26 | "title": "20170831_195425_SS02" 27 | }, 28 | { 29 | "rel": "item", 30 | "href": "./20170831_162740_ssc1d1/20170831_162740_ssc1d1.json", 31 | "title": "20170831_162740_ssc1d1" 32 | }, 33 | { 34 | "rel": "item", 35 | "href": "./Houston-East-20170831-103f-100d-0f4f-RGB/Houston-East-20170831-103f-100d-0f4f-RGB.json", 36 | "title": "Houston-East-20170831-103f-100d-0f4f-RGB" 37 | }, 38 | { 39 | "rel": "parent", 40 | "href": "../catalog.json", 41 | "type": "application/json" 42 | } 43 | ], 44 | "stac_extensions": [], 45 | "title": "Hurricane Harvey 08-31-2017" 46 | } -------------------------------------------------------------------------------- /tests/data-files/raster_footprint/AST_L1T_00310012006175412_20150516104359-SWIR-cropped.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stac-utils/stactools/8acd72d4d8914b680e747d655e5964cf53280a27/tests/data-files/raster_footprint/AST_L1T_00310012006175412_20150516104359-SWIR-cropped.tif -------------------------------------------------------------------------------- /tests/data-files/raster_footprint/LC08_L1TP_198029_20220331_20220406_02_T1_B2.TIF: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stac-utils/stactools/8acd72d4d8914b680e747d655e5964cf53280a27/tests/data-files/raster_footprint/LC08_L1TP_198029_20220331_20220406_02_T1_B2.TIF -------------------------------------------------------------------------------- /tests/data-files/raster_footprint/LC08_LST_crop.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stac-utils/stactools/8acd72d4d8914b680e747d655e5964cf53280a27/tests/data-files/raster_footprint/LC08_LST_crop.tif -------------------------------------------------------------------------------- /tests/data-files/raster_footprint/MCD43A4.A2001055.h25v06.006.2016113010159_B01.TIF: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stac-utils/stactools/8acd72d4d8914b680e747d655e5964cf53280a27/tests/data-files/raster_footprint/MCD43A4.A2001055.h25v06.006.2016113010159_B01.TIF -------------------------------------------------------------------------------- /tests/data-files/raster_footprint/S2A_OPER_MSI_L2A_TL_ATOS_20220620T162319_A036527_T32TLS_N04.00_R60m_B01.jp2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stac-utils/stactools/8acd72d4d8914b680e747d655e5964cf53280a27/tests/data-files/raster_footprint/S2A_OPER_MSI_L2A_TL_ATOS_20220620T162319_A036527_T32TLS_N04.00_R60m_B01.jp2 -------------------------------------------------------------------------------- /tests/data-files/raster_footprint/S2B_OPER_MSI_L2A_TL_2BPS_20220618T135630_A027590_T32TLS_N04.00_R60m_B01.jp2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stac-utils/stactools/8acd72d4d8914b680e747d655e5964cf53280a27/tests/data-files/raster_footprint/S2B_OPER_MSI_L2A_TL_2BPS_20220618T135630_A027590_T32TLS_N04.00_R60m_B01.jp2 -------------------------------------------------------------------------------- /tests/data-files/raster_footprint/aster/AST_L1T_00305032000040446_20150409135350_78838.SWIR.SIMPLIFIED.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stac-utils/stactools/8acd72d4d8914b680e747d655e5964cf53280a27/tests/data-files/raster_footprint/aster/AST_L1T_00305032000040446_20150409135350_78838.SWIR.SIMPLIFIED.tif -------------------------------------------------------------------------------- /tests/data-files/raster_footprint/aster/AST_L1T_00305032000040446_20150409135350_78838.TIR.SIMPLIFIED.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stac-utils/stactools/8acd72d4d8914b680e747d655e5964cf53280a27/tests/data-files/raster_footprint/aster/AST_L1T_00305032000040446_20150409135350_78838.TIR.SIMPLIFIED.tif -------------------------------------------------------------------------------- /tests/data-files/raster_footprint/aster/AST_L1T_00305032000040446_20150409135350_78838.VNIR.SIMPLIFIED.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stac-utils/stactools/8acd72d4d8914b680e747d655e5964cf53280a27/tests/data-files/raster_footprint/aster/AST_L1T_00305032000040446_20150409135350_78838.VNIR.SIMPLIFIED.tif -------------------------------------------------------------------------------- /tests/data-files/training/acc/collection.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Collection", 3 | "id": "acc", 4 | "stac_version": "1.0.0", 5 | "description": "Tier 1 training data from acc", 6 | "links": [ 7 | { 8 | "rel": "item", 9 | "href": "./665946/665946.json", 10 | "type": "application/json" 11 | }, 12 | { 13 | "rel": "item", 14 | "href": "./665946-labels/665946-labels.json", 15 | "type": "application/json" 16 | }, 17 | { 18 | "rel": "item", 19 | "href": "./a42435/a42435.json", 20 | "type": "application/json" 21 | }, 22 | { 23 | "rel": "item", 24 | "href": "./a42435-labels/a42435-labels.json", 25 | "type": "application/json" 26 | }, 27 | { 28 | "rel": "item", 29 | "href": "./ca041a/ca041a.json", 30 | "type": "application/json" 31 | }, 32 | { 33 | "rel": "item", 34 | "href": "./ca041a-labels/ca041a-labels.json", 35 | "type": "application/json" 36 | }, 37 | { 38 | "rel": "item", 39 | "href": "./d41d81/d41d81.json", 40 | "type": "application/json" 41 | }, 42 | { 43 | "rel": "item", 44 | "href": "./d41d81-labels/d41d81-labels.json", 45 | "type": "application/json" 46 | }, 47 | { 48 | "rel": "root", 49 | "href": "../catalog.json", 50 | "type": "application/json" 51 | }, 52 | { 53 | "rel": "parent", 54 | "href": "../catalog.json", 55 | "type": "application/json" 56 | } 57 | ], 58 | "stac_extensions": [], 59 | "extent": { 60 | "spatial": { 61 | "bbox": [ 62 | [ 63 | -0.20863145179911316, 64 | 5.573262528211078, 65 | -0.18948660187120017, 66 | 5.593203677296213 67 | ] 68 | ] 69 | }, 70 | "temporal": { 71 | "interval": [ 72 | [ 73 | "2019-10-29T00:00:00Z", 74 | null 75 | ] 76 | ] 77 | } 78 | }, 79 | "license": "various" 80 | } -------------------------------------------------------------------------------- /tests/data-files/training/catalog.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Catalog", 3 | "id": "train_tier_1", 4 | "stac_version": "1.0.0", 5 | "description": "Tier 1 training data and labels", 6 | "links": [ 7 | { 8 | "rel": "child", 9 | "href": "./acc/collection.json", 10 | "type": "application/json" 11 | }, 12 | { 13 | "rel": "child", 14 | "href": "./mon/collection.json", 15 | "type": "application/json" 16 | }, 17 | { 18 | "rel": "child", 19 | "href": "./ptn/collection.json", 20 | "type": "application/json" 21 | }, 22 | { 23 | "rel": "child", 24 | "href": "./kam/collection.json", 25 | "type": "application/json" 26 | }, 27 | { 28 | "rel": "child", 29 | "href": "./dar/collection.json", 30 | "type": "application/json" 31 | }, 32 | { 33 | "rel": "child", 34 | "href": "./znz/collection.json", 35 | "type": "application/json" 36 | }, 37 | { 38 | "rel": "child", 39 | "href": "./nia/collection.json", 40 | "type": "application/json" 41 | }, 42 | { 43 | "rel": "root", 44 | "href": "./catalog.json", 45 | "type": "application/json" 46 | } 47 | ], 48 | "stac_extensions": [] 49 | } -------------------------------------------------------------------------------- /tests/data-files/training/dar/collection.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Collection", 3 | "id": "dar", 4 | "stac_version": "1.0.0", 5 | "description": "Tier 1 training data from dar", 6 | "links": [ 7 | { 8 | "rel": "item", 9 | "href": "./a017f9/a017f9.json", 10 | "type": "application/json" 11 | }, 12 | { 13 | "rel": "item", 14 | "href": "./a017f9-labels/a017f9-labels.json", 15 | "type": "application/json" 16 | }, 17 | { 18 | "rel": "item", 19 | "href": "./b15fce/b15fce.json", 20 | "type": "application/json" 21 | }, 22 | { 23 | "rel": "item", 24 | "href": "./b15fce-labels/b15fce-labels.json", 25 | "type": "application/json" 26 | }, 27 | { 28 | "rel": "item", 29 | "href": "./353093/353093.json", 30 | "type": "application/json" 31 | }, 32 | { 33 | "rel": "item", 34 | "href": "./353093-labels/353093-labels.json", 35 | "type": "application/json" 36 | }, 37 | { 38 | "rel": "item", 39 | "href": "./f883a0/f883a0.json", 40 | "type": "application/json" 41 | }, 42 | { 43 | "rel": "item", 44 | "href": "./f883a0-labels/f883a0-labels.json", 45 | "type": "application/json" 46 | }, 47 | { 48 | "rel": "item", 49 | "href": "./42f235/42f235.json", 50 | "type": "application/json" 51 | }, 52 | { 53 | "rel": "item", 54 | "href": "./42f235-labels/42f235-labels.json", 55 | "type": "application/json" 56 | }, 57 | { 58 | "rel": "item", 59 | "href": "./0a4c40/0a4c40.json", 60 | "type": "application/json" 61 | }, 62 | { 63 | "rel": "item", 64 | "href": "./0a4c40-labels/0a4c40-labels.json", 65 | "type": "application/json" 66 | }, 67 | { 68 | "rel": "root", 69 | "href": "../catalog.json", 70 | "type": "application/json" 71 | }, 72 | { 73 | "rel": "parent", 74 | "href": "../catalog.json", 75 | "type": "application/json" 76 | } 77 | ], 78 | "stac_extensions": [], 79 | "extent": { 80 | "spatial": { 81 | "bbox": [ 82 | [ 83 | 39.27617850435042, 84 | -6.831966577377629, 85 | 39.28590140581279, 86 | -6.827274081760294 87 | ] 88 | ] 89 | }, 90 | "temporal": { 91 | "interval": [ 92 | [ 93 | "2019-10-29T00:00:00Z", 94 | null 95 | ] 96 | ] 97 | } 98 | }, 99 | "license": "various" 100 | } -------------------------------------------------------------------------------- /tests/data-files/training/kam/collection.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Collection", 3 | "id": "kam", 4 | "stac_version": "1.0.0", 5 | "description": "Tier 1 training data from kam", 6 | "links": [ 7 | { 8 | "rel": "item", 9 | "href": "./4e7c7f/4e7c7f.json", 10 | "type": "application/json" 11 | }, 12 | { 13 | "rel": "item", 14 | "href": "./4e7c7f-labels/4e7c7f-labels.json", 15 | "type": "application/json" 16 | }, 17 | { 18 | "rel": "root", 19 | "href": "../catalog.json", 20 | "type": "application/json" 21 | }, 22 | { 23 | "rel": "parent", 24 | "href": "../catalog.json", 25 | "type": "application/json" 26 | } 27 | ], 28 | "stac_extensions": [], 29 | "extent": { 30 | "spatial": { 31 | "bbox": [ 32 | [ 33 | 32.626179443806286, 34 | 0.24927592951780594, 35 | 32.638649276300896, 36 | 0.26207074609958386 37 | ] 38 | ] 39 | }, 40 | "temporal": { 41 | "interval": [ 42 | [ 43 | "2019-10-29T00:00:00Z", 44 | null 45 | ] 46 | ] 47 | } 48 | }, 49 | "license": "various" 50 | } -------------------------------------------------------------------------------- /tests/data-files/training/mon/collection.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Collection", 3 | "id": "mon", 4 | "stac_version": "1.0.0", 5 | "description": "Tier 1 training data from mon", 6 | "links": [ 7 | { 8 | "rel": "item", 9 | "href": "./401175/401175.json", 10 | "type": "application/json" 11 | }, 12 | { 13 | "rel": "item", 14 | "href": "./401175-labels/401175-labels.json", 15 | "type": "application/json" 16 | }, 17 | { 18 | "rel": "item", 19 | "href": "./493701/493701.json", 20 | "type": "application/json" 21 | }, 22 | { 23 | "rel": "item", 24 | "href": "./493701-labels/493701-labels.json", 25 | "type": "application/json" 26 | }, 27 | { 28 | "rel": "item", 29 | "href": "./207cc7/207cc7.json", 30 | "type": "application/json" 31 | }, 32 | { 33 | "rel": "item", 34 | "href": "./207cc7-labels/207cc7-labels.json", 35 | "type": "application/json" 36 | }, 37 | { 38 | "rel": "item", 39 | "href": "./f15272/f15272.json", 40 | "type": "application/json" 41 | }, 42 | { 43 | "rel": "item", 44 | "href": "./f15272-labels/f15272-labels.json", 45 | "type": "application/json" 46 | }, 47 | { 48 | "rel": "root", 49 | "href": "../catalog.json", 50 | "type": "application/json" 51 | }, 52 | { 53 | "rel": "parent", 54 | "href": "../catalog.json", 55 | "type": "application/json" 56 | } 57 | ], 58 | "stac_extensions": [], 59 | "extent": { 60 | "spatial": { 61 | "bbox": [ 62 | [ 63 | -10.801045209329727, 64 | 6.32481451523328, 65 | -10.793669675961551, 66 | 6.331302091125989 67 | ] 68 | ] 69 | }, 70 | "temporal": { 71 | "interval": [ 72 | [ 73 | "2019-10-29T00:00:00Z", 74 | null 75 | ] 76 | ] 77 | } 78 | }, 79 | "license": "various" 80 | } -------------------------------------------------------------------------------- /tests/data-files/training/nia/825a50/825a50.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Feature", 3 | "stac_version": "1.0.0", 4 | "id": "825a50", 5 | "properties": { 6 | "area": "nia", 7 | "license": "CC-BY-4.0", 8 | "datetime": "2017-09-19T00:00:00Z" 9 | }, 10 | "geometry": { 11 | "coordinates": [ 12 | [ 13 | [ 14 | 2.000607112710697, 15 | 13.577784497569377 16 | ], 17 | [ 18 | 2.000938627053272, 19 | 13.57440384053762 20 | ], 21 | [ 22 | 2.0026898208721526, 23 | 13.572186843360377 24 | ], 25 | [ 26 | 2.0046604894641256, 27 | 13.570445755015827 28 | ], 29 | [ 30 | 2.005587501792436, 31 | 13.572743332485638 32 | ], 33 | [ 34 | 2.004114104714325, 35 | 13.574600773336414 36 | ], 37 | [ 38 | 2.007048620561563, 39 | 13.576033006956274 40 | ], 41 | [ 42 | 2.0084759739809837, 43 | 13.579792579072723 44 | ], 45 | [ 46 | 2.0089069498293726, 47 | 13.580816192675927 48 | ], 49 | [ 50 | 2.007310769661418, 51 | 13.581639705514045 52 | ], 53 | [ 54 | 2.007598074888608, 55 | 13.58234965082254 56 | ], 57 | [ 58 | 2.0043965058209636, 59 | 13.583969811536608 60 | ], 61 | [ 62 | 2.001787365161808, 63 | 13.578048562749643 64 | ], 65 | [ 66 | 2.000607112710697, 67 | 13.577784497569377 68 | ] 69 | ] 70 | ], 71 | "type": "Polygon" 72 | }, 73 | "links": [ 74 | { 75 | "rel": "collection", 76 | "href": "../collection.json", 77 | "type": "application/json" 78 | }, 79 | { 80 | "rel": "root", 81 | "href": "../../catalog.json", 82 | "type": "application/json" 83 | }, 84 | { 85 | "rel": "parent", 86 | "href": "../collection.json", 87 | "type": "application/json" 88 | } 89 | ], 90 | "assets": { 91 | "image": { 92 | "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/nia/825a50/825a50.tif", 93 | "type": "image/tiff; application=geotiff; profile=cloud-optimized", 94 | "title": "GeoTIFF" 95 | } 96 | }, 97 | "bbox": [ 98 | 2.000607112710697, 99 | 13.570445755015827, 100 | 2.0089069498293726, 101 | 13.583969811536608 102 | ], 103 | "stac_extensions": [], 104 | "collection": "nia" 105 | } -------------------------------------------------------------------------------- /tests/data-files/training/nia/collection.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Collection", 3 | "id": "nia", 4 | "stac_version": "1.0.0", 5 | "description": "Tier 1 training data from nia", 6 | "links": [ 7 | { 8 | "rel": "item", 9 | "href": "./825a50/825a50.json", 10 | "type": "application/json" 11 | }, 12 | { 13 | "rel": "item", 14 | "href": "./825a50-labels/825a50-labels.json", 15 | "type": "application/json" 16 | }, 17 | { 18 | "rel": "root", 19 | "href": "../catalog.json", 20 | "type": "application/json" 21 | }, 22 | { 23 | "rel": "parent", 24 | "href": "../catalog.json", 25 | "type": "application/json" 26 | } 27 | ], 28 | "stac_extensions": [], 29 | "extent": { 30 | "spatial": { 31 | "bbox": [ 32 | [ 33 | 2.000607112710697, 34 | 13.570445755015827, 35 | 2.0089069498293726, 36 | 13.583969811536608 37 | ] 38 | ] 39 | }, 40 | "temporal": { 41 | "interval": [ 42 | [ 43 | "2019-10-29T00:00:00Z", 44 | null 45 | ] 46 | ] 47 | } 48 | }, 49 | "license": "various" 50 | } -------------------------------------------------------------------------------- /tests/data-files/training/ptn/collection.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Collection", 3 | "id": "ptn", 4 | "stac_version": "1.0.0", 5 | "description": "Tier 1 training data from ptn", 6 | "links": [ 7 | { 8 | "rel": "item", 9 | "href": "./abe1a3/abe1a3.json", 10 | "type": "application/json" 11 | }, 12 | { 13 | "rel": "item", 14 | "href": "./abe1a3-labels/abe1a3-labels.json", 15 | "type": "application/json" 16 | }, 17 | { 18 | "rel": "item", 19 | "href": "./f49f31/f49f31.json", 20 | "type": "application/json" 21 | }, 22 | { 23 | "rel": "item", 24 | "href": "./f49f31-labels/f49f31-labels.json", 25 | "type": "application/json" 26 | }, 27 | { 28 | "rel": "root", 29 | "href": "../catalog.json", 30 | "type": "application/json" 31 | }, 32 | { 33 | "rel": "parent", 34 | "href": "../catalog.json", 35 | "type": "application/json" 36 | } 37 | ], 38 | "stac_extensions": [], 39 | "extent": { 40 | "spatial": { 41 | "bbox": [ 42 | [ 43 | 11.885939170933694, 44 | -4.805243717903951, 45 | 11.897849273966862, 46 | -4.797722543259397 47 | ] 48 | ] 49 | }, 50 | "temporal": { 51 | "interval": [ 52 | [ 53 | "2019-10-29T00:00:00Z", 54 | null 55 | ] 56 | ] 57 | } 58 | }, 59 | "license": "various" 60 | } -------------------------------------------------------------------------------- /tests/data-files/training/ptn/f49f31/f49f31.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Feature", 3 | "stac_version": "1.0.0", 4 | "id": "f49f31", 5 | "properties": { 6 | "area": "ptn", 7 | "license": "CC-BY-4.0", 8 | "datetime": "2019-01-04T00:00:00Z" 9 | }, 10 | "geometry": { 11 | "coordinates": [ 12 | [ 13 | [ 14 | 11.8872283746714, 15 | -4.797808782187126 16 | ], 17 | [ 18 | 11.88972534766154, 19 | -4.798264503493327 20 | ], 21 | [ 22 | 11.891605198049556, 23 | -4.798340457044355 24 | ], 25 | [ 26 | 11.8955075180291, 27 | -4.802072082202417 28 | ], 29 | [ 30 | 11.897849273966862, 31 | -4.804253455211011 32 | ], 33 | [ 34 | 11.897268627830597, 35 | -4.804913066085889 36 | ], 37 | [ 38 | 11.89685404132025, 39 | -4.805243717903951 40 | ], 41 | [ 42 | 11.891979599532954, 43 | -4.803719848444295 44 | ], 45 | [ 46 | 11.885939170933694, 47 | -4.801674355838536 48 | ], 49 | [ 50 | 11.886296262431463, 51 | -4.800109049407727 52 | ], 53 | [ 54 | 11.886753664977459, 55 | -4.797722543259397 56 | ], 57 | [ 58 | 11.8872283746714, 59 | -4.797808782187126 60 | ] 61 | ] 62 | ], 63 | "type": "Polygon" 64 | }, 65 | "links": [ 66 | { 67 | "rel": "collection", 68 | "href": "../collection.json", 69 | "type": "application/json" 70 | }, 71 | { 72 | "rel": "root", 73 | "href": "../../catalog.json", 74 | "type": "application/json" 75 | }, 76 | { 77 | "rel": "parent", 78 | "href": "../collection.json", 79 | "type": "application/json" 80 | } 81 | ], 82 | "assets": { 83 | "image": { 84 | "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/ptn/f49f31/f49f31.tif", 85 | "type": "image/tiff; application=geotiff; profile=cloud-optimized", 86 | "title": "GeoTIFF" 87 | } 88 | }, 89 | "bbox": [ 90 | 11.885939170933694, 91 | -4.805243717903951, 92 | 11.897849273966862, 93 | -4.797722543259397 94 | ], 95 | "stac_extensions": [], 96 | "collection": "ptn" 97 | } -------------------------------------------------------------------------------- /tests/data-files/training/znz/06f252-labels/06f252-labels.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Feature", 3 | "stac_version": "1.0.0", 4 | "id": "06f252-labels", 5 | "properties": { 6 | "label:description": "Geojson building labels for scene 06f252", 7 | "area": "znz", 8 | "label:type": "vector", 9 | "label:properties": [ 10 | "building" 11 | ], 12 | "label:overviews": [ 13 | { 14 | "property_key": "building", 15 | "counts": [ 16 | { 17 | "name": "yes", 18 | "count": 1181 19 | } 20 | ] 21 | } 22 | ], 23 | "datetime": "2016-09-21T00:00:00Z", 24 | "label:classes": [ 25 | { 26 | "name": "building", 27 | "classes": [ 28 | "yes" 29 | ] 30 | } 31 | ] 32 | }, 33 | "geometry": { 34 | "coordinates": [ 35 | [ 36 | [ 37 | 39.316367972905894, 38 | -5.905850055917426 39 | ], 40 | [ 41 | 39.31369474037646, 42 | -5.905851570308218 43 | ], 44 | [ 45 | 39.31367952293228, 46 | -5.878740108331854 47 | ], 48 | [ 49 | 39.34078047573221, 50 | -5.878724233277496 51 | ], 52 | [ 53 | 39.340797007857546, 54 | -5.905835621542266 55 | ], 56 | [ 57 | 39.316367972905894, 58 | -5.905850055917426 59 | ] 60 | ] 61 | ], 62 | "type": "Polygon" 63 | }, 64 | "links": [ 65 | { 66 | "rel": "collection", 67 | "href": "../collection.json", 68 | "type": "application/json" 69 | }, 70 | { 71 | "rel": "root", 72 | "href": "../../catalog.json", 73 | "type": "application/json" 74 | }, 75 | { 76 | "rel": "parent", 77 | "href": "../collection.json", 78 | "type": "application/json" 79 | } 80 | ], 81 | "assets": { 82 | "labels": { 83 | "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/06f252-labels/06f252.geojson", 84 | "type": "application/geo+json" 85 | } 86 | }, 87 | "bbox": [ 88 | 39.31367952293228, 89 | -5.905851570308218, 90 | 39.340797007857546, 91 | -5.878724233277496 92 | ], 93 | "stac_extensions": [ 94 | "https://stac-extensions.github.io/label/v1.0.0/schema.json" 95 | ], 96 | "collection": "znz" 97 | } -------------------------------------------------------------------------------- /tests/data-files/training/znz/06f252/06f252.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Feature", 3 | "stac_version": "1.0.0", 4 | "id": "06f252", 5 | "properties": { 6 | "area": "znz", 7 | "datetime": "2016-09-21T00:00:00Z" 8 | }, 9 | "geometry": { 10 | "coordinates": [ 11 | [ 12 | [ 13 | 39.316367972905894, 14 | -5.905850055917426 15 | ], 16 | [ 17 | 39.31369474037646, 18 | -5.905851570308218 19 | ], 20 | [ 21 | 39.31367952293228, 22 | -5.878740108331854 23 | ], 24 | [ 25 | 39.34078047573221, 26 | -5.878724233277496 27 | ], 28 | [ 29 | 39.340797007857546, 30 | -5.905835621542266 31 | ], 32 | [ 33 | 39.316367972905894, 34 | -5.905850055917426 35 | ] 36 | ] 37 | ], 38 | "type": "Polygon" 39 | }, 40 | "links": [ 41 | { 42 | "rel": "collection", 43 | "href": "../collection.json", 44 | "type": "application/json" 45 | }, 46 | { 47 | "rel": "root", 48 | "href": "../../catalog.json", 49 | "type": "application/json" 50 | }, 51 | { 52 | "rel": "parent", 53 | "href": "../collection.json", 54 | "type": "application/json" 55 | } 56 | ], 57 | "assets": { 58 | "image": { 59 | "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/06f252/06f252.tif", 60 | "type": "image/tiff; application=geotiff; profile=cloud-optimized", 61 | "title": "GeoTIFF" 62 | } 63 | }, 64 | "bbox": [ 65 | 39.31367952293228, 66 | -5.905851570308218, 67 | 39.340797007857546, 68 | -5.878724233277496 69 | ], 70 | "stac_extensions": [], 71 | "collection": "znz" 72 | } -------------------------------------------------------------------------------- /tests/data-files/training/znz/076995-labels/076995-labels.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Feature", 3 | "stac_version": "1.0.0", 4 | "id": "076995-labels", 5 | "properties": { 6 | "label:description": "Geojson building labels for scene 076995", 7 | "area": "znz", 8 | "label:type": "vector", 9 | "label:properties": [ 10 | "building" 11 | ], 12 | "label:overviews": [ 13 | { 14 | "property_key": "building", 15 | "counts": [ 16 | { 17 | "name": "yes", 18 | "count": 843 19 | } 20 | ] 21 | } 22 | ], 23 | "datetime": "2016-10-04T00:00:00Z", 24 | "label:classes": [ 25 | { 26 | "name": "building", 27 | "classes": [ 28 | "yes" 29 | ] 30 | } 31 | ] 32 | }, 33 | "geometry": { 34 | "type": "Polygon", 35 | "coordinates": [ 36 | [ 37 | [ 38 | 39.3407474698636, 39 | -5.824437937045834 40 | ], 41 | [ 42 | 39.36248225709067, 43 | -5.824427688553141 44 | ], 45 | [ 46 | 39.3625604145535, 47 | -5.824877893423849 48 | ], 49 | [ 50 | 39.36300752853781, 51 | -5.828561459551643 52 | ], 53 | [ 54 | 39.36335786823858, 55 | -5.832067348597373 56 | ], 57 | [ 58 | 39.3631508602256, 59 | -5.849635373302928 60 | ], 61 | [ 62 | 39.362683761021664, 63 | -5.851560567141806 64 | ], 65 | [ 66 | 39.34075687849739, 67 | -5.851573055804989 68 | ], 69 | [ 70 | 39.3407474698636, 71 | -5.824437937045834 72 | ] 73 | ] 74 | ] 75 | }, 76 | "links": [ 77 | { 78 | "rel": "collection", 79 | "href": "../collection.json", 80 | "type": "application/json" 81 | }, 82 | { 83 | "rel": "root", 84 | "href": "../../catalog.json", 85 | "type": "application/json" 86 | }, 87 | { 88 | "rel": "parent", 89 | "href": "../collection.json", 90 | "type": "application/json" 91 | } 92 | ], 93 | "assets": { 94 | "labels": { 95 | "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/076995-labels/076995.geojson", 96 | "type": "application/geo+json" 97 | } 98 | }, 99 | "bbox": [ 100 | 39.34073844240503, 101 | -5.851576358919395, 102 | 39.36335800442592, 103 | -5.824424385662977 104 | ], 105 | "stac_extensions": [ 106 | "https://stac-extensions.github.io/label/v1.0.0/schema.json" 107 | ], 108 | "collection": "znz" 109 | } -------------------------------------------------------------------------------- /tests/data-files/training/znz/076995/076995.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Feature", 3 | "stac_version": "1.0.0", 4 | "id": "076995", 5 | "properties": { 6 | "area": "znz", 7 | "datetime": "2016-10-04T00:00:00Z" 8 | }, 9 | "geometry": { 10 | "type": "Polygon", 11 | "coordinates": [ 12 | [ 13 | [ 14 | 39.3407474698636, 15 | -5.824437937045834 16 | ], 17 | [ 18 | 39.36248225709067, 19 | -5.824427688553141 20 | ], 21 | [ 22 | 39.3625604145535, 23 | -5.824877893423849 24 | ], 25 | [ 26 | 39.36300752853781, 27 | -5.828561459551643 28 | ], 29 | [ 30 | 39.36335786823858, 31 | -5.832067348597373 32 | ], 33 | [ 34 | 39.3631508602256, 35 | -5.849635373302928 36 | ], 37 | [ 38 | 39.362683761021664, 39 | -5.851560567141806 40 | ], 41 | [ 42 | 39.34075687849739, 43 | -5.851573055804989 44 | ], 45 | [ 46 | 39.3407474698636, 47 | -5.824437937045834 48 | ] 49 | ] 50 | ] 51 | }, 52 | "links": [ 53 | { 54 | "rel": "collection", 55 | "href": "../collection.json", 56 | "type": "application/json" 57 | }, 58 | { 59 | "rel": "root", 60 | "href": "../../catalog.json", 61 | "type": "application/json" 62 | }, 63 | { 64 | "rel": "parent", 65 | "href": "../collection.json", 66 | "type": "application/json" 67 | } 68 | ], 69 | "assets": { 70 | "image": { 71 | "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/076995/076995.tif", 72 | "type": "image/tiff; application=geotiff; profile=cloud-optimized", 73 | "title": "GeoTIFF" 74 | } 75 | }, 76 | "bbox": [ 77 | 39.34073844240503, 78 | -5.851576358919395, 79 | 39.36335800442592, 80 | -5.824424385662977 81 | ], 82 | "stac_extensions": [], 83 | "collection": "znz" 84 | } -------------------------------------------------------------------------------- /tests/data-files/training/znz/3b20d4-labels/3b20d4-labels.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Feature", 3 | "stac_version": "1.0.0", 4 | "id": "3b20d4-labels", 5 | "properties": { 6 | "label:description": "Geojson building labels for scene 3b20d4", 7 | "area": "znz", 8 | "label:type": "vector", 9 | "label:properties": [ 10 | "building" 11 | ], 12 | "label:overviews": [ 13 | { 14 | "property_key": "building", 15 | "counts": [ 16 | { 17 | "name": "yes", 18 | "count": 702 19 | } 20 | ] 21 | } 22 | ], 23 | "datetime": "2016-10-05T00:00:00Z", 24 | "label:classes": [ 25 | { 26 | "name": "building", 27 | "classes": [ 28 | "yes" 29 | ] 30 | } 31 | ] 32 | }, 33 | "geometry": { 34 | "type": "Polygon", 35 | "coordinates": [ 36 | [ 37 | [ 38 | 39.313582732137256, 39 | -5.824334109106769 40 | ], 41 | [ 42 | 39.34087084324396, 43 | -5.824386185654682 44 | ], 45 | [ 46 | 39.34092291979187, 47 | -5.8517263733093 48 | ], 49 | [ 50 | 39.31347857904143, 51 | -5.851778449857214 52 | ], 53 | [ 54 | 39.313582732137256, 55 | -5.824334109106769 56 | ] 57 | ] 58 | ] 59 | }, 60 | "links": [ 61 | { 62 | "rel": "collection", 63 | "href": "../collection.json", 64 | "type": "application/json" 65 | }, 66 | { 67 | "rel": "root", 68 | "href": "../../catalog.json", 69 | "type": "application/json" 70 | }, 71 | { 72 | "rel": "parent", 73 | "href": "../collection.json", 74 | "type": "application/json" 75 | } 76 | ], 77 | "assets": { 78 | "labels": { 79 | "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/3b20d4-labels/3b20d4.geojson", 80 | "type": "application/geo+json" 81 | } 82 | }, 83 | "bbox": [ 84 | 39.31347857904143, 85 | -5.851778449857214, 86 | 39.34092291979187, 87 | -5.824334109106769 88 | ], 89 | "stac_extensions": [ 90 | "https://stac-extensions.github.io/label/v1.0.0/schema.json" 91 | ], 92 | "collection": "znz" 93 | } -------------------------------------------------------------------------------- /tests/data-files/training/znz/3b20d4/3b20d4.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Feature", 3 | "stac_version": "1.0.0", 4 | "id": "3b20d4", 5 | "properties": { 6 | "area": "znz", 7 | "datetime": "2016-10-05T00:00:00Z" 8 | }, 9 | "geometry": { 10 | "type": "Polygon", 11 | "coordinates": [ 12 | [ 13 | [ 14 | 39.313582732137256, 15 | -5.824334109106769 16 | ], 17 | [ 18 | 39.34087084324396, 19 | -5.824386185654682 20 | ], 21 | [ 22 | 39.34092291979187, 23 | -5.8517263733093 24 | ], 25 | [ 26 | 39.31347857904143, 27 | -5.851778449857214 28 | ], 29 | [ 30 | 39.313582732137256, 31 | -5.824334109106769 32 | ] 33 | ] 34 | ] 35 | }, 36 | "links": [ 37 | { 38 | "rel": "collection", 39 | "href": "../collection.json", 40 | "type": "application/json" 41 | }, 42 | { 43 | "rel": "root", 44 | "href": "../../catalog.json", 45 | "type": "application/json" 46 | }, 47 | { 48 | "rel": "parent", 49 | "href": "../collection.json", 50 | "type": "application/json" 51 | } 52 | ], 53 | "assets": { 54 | "image": { 55 | "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/3b20d4/3b20d4.tif", 56 | "type": "image/tiff; application=geotiff; profile=cloud-optimized", 57 | "title": "GeoTIFF" 58 | } 59 | }, 60 | "bbox": [ 61 | 39.31347857904143, 62 | -5.851778449857214, 63 | 39.34092291979187, 64 | -5.824334109106769 65 | ], 66 | "stac_extensions": [], 67 | "collection": "znz" 68 | } -------------------------------------------------------------------------------- /tests/data-files/training/znz/3f8360-labels/3f8360-labels.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Feature", 3 | "stac_version": "1.0.0", 4 | "id": "3f8360-labels", 5 | "properties": { 6 | "label:description": "Geojson building labels for scene 3f8360", 7 | "area": "znz", 8 | "label:type": "vector", 9 | "label:properties": [ 10 | "building" 11 | ], 12 | "label:overviews": [ 13 | { 14 | "property_key": "building", 15 | "counts": [ 16 | { 17 | "name": "yes", 18 | "count": 1441 19 | } 20 | ] 21 | } 22 | ], 23 | "datetime": "2016-10-08T00:00:00Z", 24 | "label:classes": [ 25 | { 26 | "name": "building", 27 | "classes": [ 28 | "yes" 29 | ] 30 | } 31 | ] 32 | }, 33 | "geometry": { 34 | "coordinates": [ 35 | [ 36 | [ 37 | 39.36446538964943, 38 | -5.9307731675787885 39 | ], 40 | [ 41 | 39.36446684258708, 42 | -5.932986095454288 43 | ], 44 | [ 45 | 39.34081351509101, 46 | -5.933001162750248 47 | ], 48 | [ 49 | 39.34079687232617, 50 | -5.905835680371048 51 | ], 52 | [ 53 | 39.364449044832185, 54 | -5.905820682536527 55 | ], 56 | [ 57 | 39.36446538964943, 58 | -5.9307731675787885 59 | ] 60 | ] 61 | ], 62 | "type": "Polygon" 63 | }, 64 | "links": [ 65 | { 66 | "rel": "collection", 67 | "href": "../collection.json", 68 | "type": "application/json" 69 | }, 70 | { 71 | "rel": "root", 72 | "href": "../../catalog.json", 73 | "type": "application/json" 74 | }, 75 | { 76 | "rel": "parent", 77 | "href": "../collection.json", 78 | "type": "application/json" 79 | } 80 | ], 81 | "assets": { 82 | "labels": { 83 | "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/3f8360-labels/3f8360.geojson", 84 | "type": "application/geo+json" 85 | } 86 | }, 87 | "bbox": [ 88 | 39.34079687232617, 89 | -5.933001162750248, 90 | 39.36446684258708, 91 | -5.905820682536527 92 | ], 93 | "stac_extensions": [ 94 | "https://stac-extensions.github.io/label/v1.0.0/schema.json" 95 | ], 96 | "collection": "znz" 97 | } -------------------------------------------------------------------------------- /tests/data-files/training/znz/3f8360/3f8360.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Feature", 3 | "stac_version": "1.0.0", 4 | "id": "3f8360", 5 | "properties": { 6 | "area": "znz", 7 | "datetime": "2016-10-08T00:00:00Z" 8 | }, 9 | "geometry": { 10 | "coordinates": [ 11 | [ 12 | [ 13 | 39.36446538964943, 14 | -5.9307731675787885 15 | ], 16 | [ 17 | 39.36446684258708, 18 | -5.932986095454288 19 | ], 20 | [ 21 | 39.34081351509101, 22 | -5.933001162750248 23 | ], 24 | [ 25 | 39.34079687232617, 26 | -5.905835680371048 27 | ], 28 | [ 29 | 39.364449044832185, 30 | -5.905820682536527 31 | ], 32 | [ 33 | 39.36446538964943, 34 | -5.9307731675787885 35 | ] 36 | ] 37 | ], 38 | "type": "Polygon" 39 | }, 40 | "links": [ 41 | { 42 | "rel": "collection", 43 | "href": "../collection.json", 44 | "type": "application/json" 45 | }, 46 | { 47 | "rel": "root", 48 | "href": "../../catalog.json", 49 | "type": "application/json" 50 | }, 51 | { 52 | "rel": "parent", 53 | "href": "../collection.json", 54 | "type": "application/json" 55 | } 56 | ], 57 | "assets": { 58 | "image": { 59 | "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/3f8360/3f8360.tif", 60 | "type": "image/tiff; application=geotiff; profile=cloud-optimized", 61 | "title": "GeoTIFF" 62 | } 63 | }, 64 | "bbox": [ 65 | 39.34079687232617, 66 | -5.933001162750248, 67 | 39.36446684258708, 68 | -5.905820682536527 69 | ], 70 | "stac_extensions": [], 71 | "collection": "znz" 72 | } -------------------------------------------------------------------------------- /tests/data-files/training/znz/425403-labels/425403-labels.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Feature", 3 | "stac_version": "1.0.0", 4 | "id": "425403-labels", 5 | "properties": { 6 | "label:description": "Geojson building labels for scene 425403", 7 | "area": "znz", 8 | "label:type": "vector", 9 | "label:properties": [ 10 | "building" 11 | ], 12 | "label:overviews": [ 13 | { 14 | "property_key": "building", 15 | "counts": [ 16 | { 17 | "name": "yes", 18 | "count": 224 19 | } 20 | ] 21 | } 22 | ], 23 | "datetime": "2016-10-10T00:00:00Z", 24 | "label:classes": [ 25 | { 26 | "name": "building", 27 | "classes": [ 28 | "yes" 29 | ] 30 | } 31 | ] 32 | }, 33 | "geometry": { 34 | "coordinates": [ 35 | [ 36 | [ 37 | 39.34082996500427, 38 | -5.960158147553525 39 | ], 40 | [ 41 | 39.340813249870706, 42 | -5.933001378219889 43 | ], 44 | [ 45 | 39.31371005982263, 46 | -5.933017400605379 47 | ], 48 | [ 49 | 39.313725445739834, 50 | -5.960174243786799 51 | ], 52 | [ 53 | 39.34082996500427, 54 | -5.960158147553525 55 | ] 56 | ] 57 | ], 58 | "type": "Polygon" 59 | }, 60 | "links": [ 61 | { 62 | "rel": "collection", 63 | "href": "../collection.json", 64 | "type": "application/json" 65 | }, 66 | { 67 | "rel": "root", 68 | "href": "../../catalog.json", 69 | "type": "application/json" 70 | }, 71 | { 72 | "rel": "parent", 73 | "href": "../collection.json", 74 | "type": "application/json" 75 | } 76 | ], 77 | "assets": { 78 | "labels": { 79 | "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/425403-labels/425403.geojson", 80 | "type": "application/geo+json" 81 | } 82 | }, 83 | "bbox": [ 84 | 39.31371005982263, 85 | -5.960174243786799, 86 | 39.34082996500427, 87 | -5.933001378219889 88 | ], 89 | "stac_extensions": [ 90 | "https://stac-extensions.github.io/label/v1.0.0/schema.json" 91 | ], 92 | "collection": "znz" 93 | } -------------------------------------------------------------------------------- /tests/data-files/training/znz/425403/425403.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Feature", 3 | "stac_version": "1.0.0", 4 | "id": "425403", 5 | "properties": { 6 | "area": "znz", 7 | "datetime": "2016-10-10T00:00:00Z" 8 | }, 9 | "geometry": { 10 | "coordinates": [ 11 | [ 12 | [ 13 | 39.34082996500427, 14 | -5.960158147553525 15 | ], 16 | [ 17 | 39.340813249870706, 18 | -5.933001378219889 19 | ], 20 | [ 21 | 39.31371005982263, 22 | -5.933017400605379 23 | ], 24 | [ 25 | 39.313725445739834, 26 | -5.960174243786799 27 | ], 28 | [ 29 | 39.34082996500427, 30 | -5.960158147553525 31 | ] 32 | ] 33 | ], 34 | "type": "Polygon" 35 | }, 36 | "links": [ 37 | { 38 | "rel": "collection", 39 | "href": "../collection.json", 40 | "type": "application/json" 41 | }, 42 | { 43 | "rel": "root", 44 | "href": "../../catalog.json", 45 | "type": "application/json" 46 | }, 47 | { 48 | "rel": "parent", 49 | "href": "../collection.json", 50 | "type": "application/json" 51 | } 52 | ], 53 | "assets": { 54 | "image": { 55 | "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/425403/425403.tif", 56 | "type": "image/tiff; application=geotiff; profile=cloud-optimized", 57 | "title": "GeoTIFF" 58 | } 59 | }, 60 | "bbox": [ 61 | 39.31371005982263, 62 | -5.960174243786799, 63 | 39.34082996500427, 64 | -5.933001378219889 65 | ], 66 | "stac_extensions": [], 67 | "collection": "znz" 68 | } -------------------------------------------------------------------------------- /tests/data-files/training/znz/75cdfa-labels/75cdfa-labels.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Feature", 3 | "stac_version": "1.0.0", 4 | "id": "75cdfa-labels", 5 | "properties": { 6 | "label:description": "Geojson building labels for scene 75cdfa", 7 | "area": "znz", 8 | "label:type": "vector", 9 | "label:properties": [ 10 | "building" 11 | ], 12 | "label:overviews": [ 13 | { 14 | "property_key": "building", 15 | "counts": [ 16 | { 17 | "name": "yes", 18 | "count": 566 19 | } 20 | ] 21 | } 22 | ], 23 | "datetime": "2016-10-05T00:00:00Z", 24 | "label:classes": [ 25 | { 26 | "name": "building", 27 | "classes": [ 28 | "yes" 29 | ] 30 | } 31 | ] 32 | }, 33 | "geometry": { 34 | "coordinates": [ 35 | [ 36 | [ 37 | 39.31640547357606, 38 | -5.878738481386144 39 | ], 40 | [ 41 | 39.31367952288209, 42 | -5.8787400187081476 43 | ], 44 | [ 45 | 39.31366435148484, 46 | -5.851583330154158 47 | ], 48 | [ 49 | 39.34076386428035, 50 | -5.851567529006198 51 | ], 52 | [ 53 | 39.34078034637437, 54 | -5.878724143732914 55 | ], 56 | [ 57 | 39.31640547357606, 58 | -5.878738481386144 59 | ] 60 | ] 61 | ], 62 | "type": "Polygon" 63 | }, 64 | "links": [ 65 | { 66 | "rel": "collection", 67 | "href": "../collection.json", 68 | "type": "application/json" 69 | }, 70 | { 71 | "rel": "root", 72 | "href": "../../catalog.json", 73 | "type": "application/json" 74 | }, 75 | { 76 | "rel": "parent", 77 | "href": "../collection.json", 78 | "type": "application/json" 79 | } 80 | ], 81 | "assets": { 82 | "labels": { 83 | "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/75cdfa-labels/75cdfa.geojson", 84 | "type": "application/geo+json" 85 | } 86 | }, 87 | "bbox": [ 88 | 39.31366435148484, 89 | -5.8787400187081476, 90 | 39.34078034637437, 91 | -5.851567529006198 92 | ], 93 | "stac_extensions": [ 94 | "https://stac-extensions.github.io/label/v1.0.0/schema.json" 95 | ], 96 | "collection": "znz" 97 | } -------------------------------------------------------------------------------- /tests/data-files/training/znz/75cdfa/75cdfa.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Feature", 3 | "stac_version": "1.0.0", 4 | "id": "75cdfa", 5 | "properties": { 6 | "area": "znz", 7 | "datetime": "2016-10-05T00:00:00Z" 8 | }, 9 | "geometry": { 10 | "coordinates": [ 11 | [ 12 | [ 13 | 39.31640547357606, 14 | -5.878738481386144 15 | ], 16 | [ 17 | 39.31367952288209, 18 | -5.8787400187081476 19 | ], 20 | [ 21 | 39.31366435148484, 22 | -5.851583330154158 23 | ], 24 | [ 25 | 39.34076386428035, 26 | -5.851567529006198 27 | ], 28 | [ 29 | 39.34078034637437, 30 | -5.878724143732914 31 | ], 32 | [ 33 | 39.31640547357606, 34 | -5.878738481386144 35 | ] 36 | ] 37 | ], 38 | "type": "Polygon" 39 | }, 40 | "links": [ 41 | { 42 | "rel": "collection", 43 | "href": "../collection.json", 44 | "type": "application/json" 45 | }, 46 | { 47 | "rel": "root", 48 | "href": "../../catalog.json", 49 | "type": "application/json" 50 | }, 51 | { 52 | "rel": "parent", 53 | "href": "../collection.json", 54 | "type": "application/json" 55 | } 56 | ], 57 | "assets": { 58 | "image": { 59 | "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/75cdfa/75cdfa.tif", 60 | "type": "image/tiff; application=geotiff; profile=cloud-optimized", 61 | "title": "GeoTIFF" 62 | } 63 | }, 64 | "bbox": [ 65 | 39.31366435148484, 66 | -5.8787400187081476, 67 | 39.34078034637437, 68 | -5.851567529006198 69 | ], 70 | "stac_extensions": [], 71 | "collection": "znz" 72 | } -------------------------------------------------------------------------------- /tests/data-files/training/znz/aee7fd-labels/aee7fd-labels.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Feature", 3 | "stac_version": "1.0.0", 4 | "id": "aee7fd-labels", 5 | "properties": { 6 | "label:description": "Geojson building labels for scene aee7fd", 7 | "area": "znz", 8 | "label:type": "vector", 9 | "label:properties": [ 10 | "building" 11 | ], 12 | "label:overviews": [ 13 | { 14 | "property_key": "building", 15 | "counts": [ 16 | { 17 | "name": "yes", 18 | "count": 551 19 | } 20 | ] 21 | } 22 | ], 23 | "datetime": "2016-10-08T00:00:00Z", 24 | "label:classes": [ 25 | { 26 | "name": "building", 27 | "classes": [ 28 | "yes" 29 | ] 30 | } 31 | ] 32 | }, 33 | "geometry": { 34 | "coordinates": [ 35 | [ 36 | [ 37 | 39.31705255429268, 38 | -5.933015462962362 39 | ], 40 | [ 41 | 39.31371062447159, 42 | -5.933017366868187 43 | ], 44 | [ 45 | 39.31369530504979, 46 | -5.905851628735563 47 | ], 48 | [ 49 | 39.340797668473954, 50 | -5.905835679883141 51 | ], 52 | [ 53 | 39.340814311389366, 54 | -5.933001344149245 55 | ], 56 | [ 57 | 39.31705255429268, 58 | -5.933015462962362 59 | ] 60 | ] 61 | ], 62 | "type": "Polygon" 63 | }, 64 | "links": [ 65 | { 66 | "rel": "collection", 67 | "href": "../collection.json", 68 | "type": "application/json" 69 | }, 70 | { 71 | "rel": "root", 72 | "href": "../../catalog.json", 73 | "type": "application/json" 74 | }, 75 | { 76 | "rel": "parent", 77 | "href": "../collection.json", 78 | "type": "application/json" 79 | } 80 | ], 81 | "assets": { 82 | "labels": { 83 | "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/aee7fd-labels/aee7fd.geojson", 84 | "type": "application/geo+json" 85 | } 86 | }, 87 | "bbox": [ 88 | 39.31369530504979, 89 | -5.933017366868187, 90 | 39.340814311389366, 91 | -5.905835679883141 92 | ], 93 | "stac_extensions": [ 94 | "https://stac-extensions.github.io/label/v1.0.0/schema.json" 95 | ], 96 | "collection": "znz" 97 | } -------------------------------------------------------------------------------- /tests/data-files/training/znz/aee7fd/aee7fd.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Feature", 3 | "stac_version": "1.0.0", 4 | "id": "aee7fd", 5 | "properties": { 6 | "area": "znz", 7 | "datetime": "2016-10-08T00:00:00Z" 8 | }, 9 | "geometry": { 10 | "coordinates": [ 11 | [ 12 | [ 13 | 39.31705255429268, 14 | -5.933015462962362 15 | ], 16 | [ 17 | 39.31371062447159, 18 | -5.933017366868187 19 | ], 20 | [ 21 | 39.31369530504979, 22 | -5.905851628735563 23 | ], 24 | [ 25 | 39.340797668473954, 26 | -5.905835679883141 27 | ], 28 | [ 29 | 39.340814311389366, 30 | -5.933001344149245 31 | ], 32 | [ 33 | 39.31705255429268, 34 | -5.933015462962362 35 | ] 36 | ] 37 | ], 38 | "type": "Polygon" 39 | }, 40 | "links": [ 41 | { 42 | "rel": "collection", 43 | "href": "../collection.json", 44 | "type": "application/json" 45 | }, 46 | { 47 | "rel": "root", 48 | "href": "../../catalog.json", 49 | "type": "application/json" 50 | }, 51 | { 52 | "rel": "parent", 53 | "href": "../collection.json", 54 | "type": "application/json" 55 | } 56 | ], 57 | "assets": { 58 | "image": { 59 | "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/aee7fd/aee7fd.tif", 60 | "type": "image/tiff; application=geotiff; profile=cloud-optimized", 61 | "title": "GeoTIFF" 62 | } 63 | }, 64 | "bbox": [ 65 | 39.31369530504979, 66 | -5.933017366868187, 67 | 39.340814311389366, 68 | -5.905835679883141 69 | ], 70 | "stac_extensions": [], 71 | "collection": "znz" 72 | } -------------------------------------------------------------------------------- /tests/data-files/training/znz/bc32f1-labels/bc32f1-labels.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Feature", 3 | "stac_version": "1.0.0", 4 | "id": "bc32f1-labels", 5 | "properties": { 6 | "label:description": "Geojson building labels for scene bc32f1", 7 | "area": "znz", 8 | "label:type": "vector", 9 | "label:properties": [ 10 | "building" 11 | ], 12 | "label:overviews": [ 13 | { 14 | "property_key": "building", 15 | "counts": [ 16 | { 17 | "name": "yes", 18 | "count": 97 19 | } 20 | ] 21 | } 22 | ], 23 | "datetime": "2016-10-12T00:00:00Z", 24 | "label:classes": [ 25 | { 26 | "name": "building", 27 | "classes": [ 28 | "yes" 29 | ] 30 | } 31 | ] 32 | }, 33 | "geometry": { 34 | "coordinates": [ 35 | [ 36 | [ 37 | 39.344219970219626, 38 | -5.987276061137261 39 | ], 40 | [ 41 | 39.340847000464755, 42 | -5.987278166971163 43 | ], 44 | [ 45 | 39.34083023028068, 46 | -5.960158002925742 47 | ], 48 | [ 49 | 39.36793404669621, 50 | -5.960140574104503 51 | ], 52 | [ 53 | 39.36795215042373, 54 | -5.987260658288568 55 | ], 56 | [ 57 | 39.344219970219626, 58 | -5.987276061137261 59 | ] 60 | ] 61 | ], 62 | "type": "Polygon" 63 | }, 64 | "links": [ 65 | { 66 | "rel": "collection", 67 | "href": "../collection.json", 68 | "type": "application/json" 69 | }, 70 | { 71 | "rel": "root", 72 | "href": "../../catalog.json", 73 | "type": "application/json" 74 | }, 75 | { 76 | "rel": "parent", 77 | "href": "../collection.json", 78 | "type": "application/json" 79 | } 80 | ], 81 | "assets": { 82 | "labels": { 83 | "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/bc32f1-labels/bc32f1.geojson", 84 | "type": "application/geo+json" 85 | } 86 | }, 87 | "bbox": [ 88 | 39.34083023028068, 89 | -5.987278166971163, 90 | 39.36795215042373, 91 | -5.960140574104503 92 | ], 93 | "stac_extensions": [ 94 | "https://stac-extensions.github.io/label/v1.0.0/schema.json" 95 | ], 96 | "collection": "znz" 97 | } -------------------------------------------------------------------------------- /tests/data-files/training/znz/bc32f1/bc32f1.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Feature", 3 | "stac_version": "1.0.0", 4 | "id": "bc32f1", 5 | "properties": { 6 | "area": "znz", 7 | "datetime": "2016-10-12T00:00:00Z" 8 | }, 9 | "geometry": { 10 | "coordinates": [ 11 | [ 12 | [ 13 | 39.344219970219626, 14 | -5.987276061137261 15 | ], 16 | [ 17 | 39.340847000464755, 18 | -5.987278166971163 19 | ], 20 | [ 21 | 39.34083023028068, 22 | -5.960158002925742 23 | ], 24 | [ 25 | 39.36793404669621, 26 | -5.960140574104503 27 | ], 28 | [ 29 | 39.36795215042373, 30 | -5.987260658288568 31 | ], 32 | [ 33 | 39.344219970219626, 34 | -5.987276061137261 35 | ] 36 | ] 37 | ], 38 | "type": "Polygon" 39 | }, 40 | "links": [ 41 | { 42 | "rel": "collection", 43 | "href": "../collection.json", 44 | "type": "application/json" 45 | }, 46 | { 47 | "rel": "root", 48 | "href": "../../catalog.json", 49 | "type": "application/json" 50 | }, 51 | { 52 | "rel": "parent", 53 | "href": "../collection.json", 54 | "type": "application/json" 55 | } 56 | ], 57 | "assets": { 58 | "image": { 59 | "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/bc32f1/bc32f1.tif", 60 | "type": "image/tiff; application=geotiff; profile=cloud-optimized", 61 | "title": "GeoTIFF" 62 | } 63 | }, 64 | "bbox": [ 65 | 39.34083023028068, 66 | -5.987278166971163, 67 | 39.36795215042373, 68 | -5.960140574104503 69 | ], 70 | "stac_extensions": [], 71 | "collection": "znz" 72 | } -------------------------------------------------------------------------------- /tests/data-files/training/znz/bd5c14-labels/bd5c14-labels.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Feature", 3 | "stac_version": "1.0.0", 4 | "id": "bd5c14-labels", 5 | "properties": { 6 | "label:description": "Geojson building labels for scene bd5c14", 7 | "area": "znz", 8 | "label:type": "vector", 9 | "label:properties": [ 10 | "building" 11 | ], 12 | "label:overviews": [ 13 | { 14 | "property_key": "building", 15 | "counts": [ 16 | { 17 | "name": "yes", 18 | "count": 781 19 | } 20 | ] 21 | } 22 | ], 23 | "datetime": "2016-10-11T00:00:00Z", 24 | "label:classes": [ 25 | { 26 | "name": "building", 27 | "classes": [ 28 | "yes" 29 | ] 30 | } 31 | ] 32 | }, 33 | "geometry": { 34 | "coordinates": [ 35 | [ 36 | [ 37 | 39.367932205551796, 38 | -5.957816165919622 39 | ], 40 | [ 41 | 39.367933753210345, 42 | -5.960140452755652 43 | ], 44 | [ 45 | 39.3408296655117, 46 | -5.960157881729879 47 | ], 48 | [ 49 | 39.34081295055692, 50 | -5.9330013784041595 51 | ], 52 | [ 53 | 39.36791570908837, 54 | -5.932984029391401 55 | ], 56 | [ 57 | 39.367932205551796, 58 | -5.957816165919622 59 | ] 60 | ] 61 | ], 62 | "type": "Polygon" 63 | }, 64 | "links": [ 65 | { 66 | "rel": "collection", 67 | "href": "../collection.json", 68 | "type": "application/json" 69 | }, 70 | { 71 | "rel": "root", 72 | "href": "../../catalog.json", 73 | "type": "application/json" 74 | }, 75 | { 76 | "rel": "parent", 77 | "href": "../collection.json", 78 | "type": "application/json" 79 | } 80 | ], 81 | "assets": { 82 | "labels": { 83 | "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/bd5c14-labels/bd5c14.geojson", 84 | "type": "application/geo+json" 85 | } 86 | }, 87 | "bbox": [ 88 | 39.34081295055692, 89 | -5.960157881729879, 90 | 39.367933753210345, 91 | -5.932984029391401 92 | ], 93 | "stac_extensions": [ 94 | "https://stac-extensions.github.io/label/v1.0.0/schema.json" 95 | ], 96 | "collection": "znz" 97 | } -------------------------------------------------------------------------------- /tests/data-files/training/znz/bd5c14/bd5c14.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Feature", 3 | "stac_version": "1.0.0", 4 | "id": "bd5c14", 5 | "properties": { 6 | "area": "znz", 7 | "datetime": "2016-10-11T00:00:00Z" 8 | }, 9 | "geometry": { 10 | "coordinates": [ 11 | [ 12 | [ 13 | 39.367932205551796, 14 | -5.957816165919622 15 | ], 16 | [ 17 | 39.367933753210345, 18 | -5.960140452755652 19 | ], 20 | [ 21 | 39.3408296655117, 22 | -5.960157881729879 23 | ], 24 | [ 25 | 39.34081295055692, 26 | -5.9330013784041595 27 | ], 28 | [ 29 | 39.36791570908837, 30 | -5.932984029391401 31 | ], 32 | [ 33 | 39.367932205551796, 34 | -5.957816165919622 35 | ] 36 | ] 37 | ], 38 | "type": "Polygon" 39 | }, 40 | "links": [ 41 | { 42 | "rel": "collection", 43 | "href": "../collection.json", 44 | "type": "application/json" 45 | }, 46 | { 47 | "rel": "root", 48 | "href": "../../catalog.json", 49 | "type": "application/json" 50 | }, 51 | { 52 | "rel": "parent", 53 | "href": "../collection.json", 54 | "type": "application/json" 55 | } 56 | ], 57 | "assets": { 58 | "image": { 59 | "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/bd5c14/bd5c14.tif", 60 | "type": "image/tiff; application=geotiff; profile=cloud-optimized", 61 | "title": "GeoTIFF" 62 | } 63 | }, 64 | "bbox": [ 65 | 39.34081295055692, 66 | -5.960157881729879, 67 | 39.367933753210345, 68 | -5.932984029391401 69 | ], 70 | "stac_extensions": [], 71 | "collection": "znz" 72 | } -------------------------------------------------------------------------------- /tests/data-files/training/znz/c7415c-labels/c7415c-labels.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Feature", 3 | "stac_version": "1.0.0", 4 | "id": "c7415c-labels", 5 | "properties": { 6 | "label:description": "Geojson building labels for scene c7415c", 7 | "area": "znz", 8 | "label:type": "vector", 9 | "label:properties": [ 10 | "building" 11 | ], 12 | "label:overviews": [ 13 | { 14 | "property_key": "building", 15 | "counts": [ 16 | { 17 | "name": "yes", 18 | "count": 949 19 | } 20 | ] 21 | } 22 | ], 23 | "datetime": "2016-09-21T00:00:00Z", 24 | "label:classes": [ 25 | { 26 | "name": "building", 27 | "classes": [ 28 | "yes" 29 | ] 30 | } 31 | ] 32 | }, 33 | "geometry": { 34 | "coordinates": [ 35 | [ 36 | [ 37 | 39.36029029677782, 38 | -5.904972600767203 39 | ], 40 | [ 41 | 39.360290846530575, 42 | -5.9058234437561135 43 | ], 44 | [ 45 | 39.34079687235772, 46 | -5.9058357319970805 47 | ], 48 | [ 49 | 39.340780340171506, 50 | -5.878724233360191 51 | ], 52 | [ 53 | 39.36027336873274, 54 | -5.878712001912929 55 | ], 56 | [ 57 | 39.36029029677782, 58 | -5.904972600767203 59 | ] 60 | ] 61 | ], 62 | "type": "Polygon" 63 | }, 64 | "links": [ 65 | { 66 | "rel": "collection", 67 | "href": "../collection.json", 68 | "type": "application/json" 69 | }, 70 | { 71 | "rel": "root", 72 | "href": "../../catalog.json", 73 | "type": "application/json" 74 | }, 75 | { 76 | "rel": "parent", 77 | "href": "../collection.json", 78 | "type": "application/json" 79 | } 80 | ], 81 | "assets": { 82 | "labels": { 83 | "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/c7415c-labels/c7415c.geojson", 84 | "type": "application/geo+json" 85 | } 86 | }, 87 | "bbox": [ 88 | 39.340780340171506, 89 | -5.9058357319970805, 90 | 39.360290846530575, 91 | -5.878712001912929 92 | ], 93 | "stac_extensions": [ 94 | "https://stac-extensions.github.io/label/v1.0.0/schema.json" 95 | ], 96 | "collection": "znz" 97 | } -------------------------------------------------------------------------------- /tests/data-files/training/znz/c7415c/c7415c.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Feature", 3 | "stac_version": "1.0.0", 4 | "id": "c7415c", 5 | "properties": { 6 | "area": "znz", 7 | "datetime": "2016-09-21T00:00:00Z" 8 | }, 9 | "geometry": { 10 | "coordinates": [ 11 | [ 12 | [ 13 | 39.36029029677782, 14 | -5.904972600767203 15 | ], 16 | [ 17 | 39.360290846530575, 18 | -5.9058234437561135 19 | ], 20 | [ 21 | 39.34079687235772, 22 | -5.9058357319970805 23 | ], 24 | [ 25 | 39.340780340171506, 26 | -5.878724233360191 27 | ], 28 | [ 29 | 39.36027336873274, 30 | -5.878712001912929 31 | ], 32 | [ 33 | 39.36029029677782, 34 | -5.904972600767203 35 | ] 36 | ] 37 | ], 38 | "type": "Polygon" 39 | }, 40 | "links": [ 41 | { 42 | "rel": "collection", 43 | "href": "../collection.json", 44 | "type": "application/json" 45 | }, 46 | { 47 | "rel": "root", 48 | "href": "../../catalog.json", 49 | "type": "application/json" 50 | }, 51 | { 52 | "rel": "parent", 53 | "href": "../collection.json", 54 | "type": "application/json" 55 | } 56 | ], 57 | "assets": { 58 | "image": { 59 | "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/c7415c/c7415c.tif", 60 | "type": "image/tiff; application=geotiff; profile=cloud-optimized", 61 | "title": "GeoTIFF" 62 | } 63 | }, 64 | "bbox": [ 65 | 39.340780340171506, 66 | -5.9058357319970805, 67 | 39.360290846530575, 68 | -5.878712001912929 69 | ], 70 | "stac_extensions": [], 71 | "collection": "znz" 72 | } -------------------------------------------------------------------------------- /tests/data-files/training/znz/e52478-labels/e52478-labels.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Feature", 3 | "stac_version": "1.0.0", 4 | "id": "e52478-labels", 5 | "properties": { 6 | "label:description": "Geojson building labels for scene e52478", 7 | "area": "znz", 8 | "label:type": "vector", 9 | "label:properties": [ 10 | "building" 11 | ], 12 | "label:overviews": [ 13 | { 14 | "property_key": "building", 15 | "counts": [ 16 | { 17 | "name": "yes", 18 | "count": 21 19 | } 20 | ] 21 | } 22 | ], 23 | "datetime": "2016-11-05T00:00:00Z", 24 | "label:classes": [ 25 | { 26 | "name": "building", 27 | "classes": [ 28 | "yes" 29 | ] 30 | } 31 | ] 32 | }, 33 | "geometry": { 34 | "coordinates": [ 35 | [ 36 | [ 37 | 39.37891355673581, 38 | -5.959065689521422 39 | ], 40 | [ 41 | 39.378914288970435, 42 | -5.960133384034927 43 | ], 44 | [ 45 | 39.367933808083876, 46 | -5.9601408243123455 47 | ], 48 | [ 49 | 39.36791576371174, 50 | -5.932984029355098 51 | ], 52 | [ 53 | 39.37889570611965, 54 | -5.9329766232129995 55 | ], 56 | [ 57 | 39.37891355673581, 58 | -5.959065689521422 59 | ] 60 | ] 61 | ], 62 | "type": "Polygon" 63 | }, 64 | "links": [ 65 | { 66 | "rel": "collection", 67 | "href": "../collection.json", 68 | "type": "application/json" 69 | }, 70 | { 71 | "rel": "root", 72 | "href": "../../catalog.json", 73 | "type": "application/json" 74 | }, 75 | { 76 | "rel": "parent", 77 | "href": "../collection.json", 78 | "type": "application/json" 79 | } 80 | ], 81 | "assets": { 82 | "labels": { 83 | "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/e52478-labels/e52478.geojson", 84 | "type": "application/geo+json" 85 | } 86 | }, 87 | "bbox": [ 88 | 39.36791576371174, 89 | -5.9601408243123455, 90 | 39.378914288970435, 91 | -5.9329766232129995 92 | ], 93 | "stac_extensions": [ 94 | "https://stac-extensions.github.io/label/v1.0.0/schema.json" 95 | ], 96 | "collection": "znz" 97 | } -------------------------------------------------------------------------------- /tests/data-files/training/znz/e52478/e52478.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Feature", 3 | "stac_version": "1.0.0", 4 | "id": "e52478", 5 | "properties": { 6 | "area": "znz", 7 | "datetime": "2016-11-05T00:00:00Z" 8 | }, 9 | "geometry": { 10 | "coordinates": [ 11 | [ 12 | [ 13 | 39.37891355673581, 14 | -5.959065689521422 15 | ], 16 | [ 17 | 39.378914288970435, 18 | -5.960133384034927 19 | ], 20 | [ 21 | 39.367933808083876, 22 | -5.9601408243123455 23 | ], 24 | [ 25 | 39.36791576371174, 26 | -5.932984029355098 27 | ], 28 | [ 29 | 39.37889570611965, 30 | -5.9329766232129995 31 | ], 32 | [ 33 | 39.37891355673581, 34 | -5.959065689521422 35 | ] 36 | ] 37 | ], 38 | "type": "Polygon" 39 | }, 40 | "links": [ 41 | { 42 | "rel": "collection", 43 | "href": "../collection.json", 44 | "type": "application/json" 45 | }, 46 | { 47 | "rel": "root", 48 | "href": "../../catalog.json", 49 | "type": "application/json" 50 | }, 51 | { 52 | "rel": "parent", 53 | "href": "../collection.json", 54 | "type": "application/json" 55 | } 56 | ], 57 | "assets": { 58 | "image": { 59 | "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/e52478/e52478.tif", 60 | "type": "image/tiff; application=geotiff; profile=cloud-optimized", 61 | "title": "GeoTIFF" 62 | } 63 | }, 64 | "bbox": [ 65 | 39.36791576371174, 66 | -5.9601408243123455, 67 | 39.378914288970435, 68 | -5.9329766232129995 69 | ], 70 | "stac_extensions": [], 71 | "collection": "znz" 72 | } -------------------------------------------------------------------------------- /tests/testing/__init__.py: -------------------------------------------------------------------------------- 1 | from stactools.testing import TestData 2 | 3 | test_data = TestData( 4 | __file__, 5 | { 6 | "item.json": { 7 | "url": "https://raw.githubusercontent.com/radiantearth/" 8 | "stac-spec/v1.0.0/examples/simple-item.json", 9 | "compress": False, 10 | }, 11 | "AW3D30_global.vrt": { 12 | "url": "s3://raster/AW3D30/AW3D30_global.vrt", 13 | "s3": { 14 | "anon": True, 15 | "client_kwargs": {"endpoint_url": "https://opentopography.s3.sdsc.edu"}, 16 | }, 17 | }, 18 | "manifest.safe": { 19 | "url": ( 20 | "https://sentinel2l2a01.blob.core.windows.net/" 21 | "sentinel2-l2/03/K/TV/" 22 | "2020/05/23/" 23 | "S2A_MSIL2A_20200523T213041_N0212_R100_T03KTV_20200910T164427.SAFE/" 24 | "manifest.safe" 25 | ), 26 | "planetary_computer": True, 27 | }, 28 | }, 29 | ) 30 | -------------------------------------------------------------------------------- /tests/testing/test_test_data.py: -------------------------------------------------------------------------------- 1 | import pystac 2 | import pytest 3 | 4 | from tests.testing import test_data 5 | 6 | 7 | def test_external_data_https(): 8 | path = test_data.get_external_data("item.json") 9 | item = pystac.read_file(path) 10 | assert "20201211_223832_CS2" == item.id 11 | 12 | 13 | def test_external_data_s3(): 14 | pytest.importorskip("s3fs") 15 | path = test_data.get_external_data("AW3D30_global.vrt") 16 | with open(path) as f: 17 | xml = f.read() 18 | assert ( 19 | xml.find("ALPSMLC30_N041W106_DSM") != -1 20 | ), "Could not find 'ALPSMLC30_N041W106_DSM' in the ALOS VRT" 21 | 22 | 23 | def test_external_pc_data(): 24 | path = test_data.get_external_data("manifest.safe") 25 | with open(path) as f: 26 | xml = f.read() 27 | assert xml is not None 28 | --------------------------------------------------------------------------------