diff --git a/CHANGELOG.md b/CHANGELOG.md index ca9638caf..7db691654 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ - Serialization error when using `pystac.extensions.file.MappingObject` ([#700](https://github.com/stac-utils/pystac/pull/700)) - Use `PropertiesExtension._get_property` to properly set return type in `TableExtension` ([#712](https://github.com/stac-utils/pystac/pull/712)) - `DatacubeExtension.variables` now has a setter ([#699](https://github.com/stac-utils/pystac/pull/699)]) +- Landsat STAC tutorial is now up-to-date with all package changes ([#692](https://github.com/stac-utils/pystac/pull/674)) ### Deprecated diff --git a/docs/tutorials/creating-a-landsat-stac.ipynb b/docs/tutorials/creating-a-landsat-stac.ipynb index db98581c3..478908d78 100644 --- a/docs/tutorials/creating-a-landsat-stac.ipynb +++ b/docs/tutorials/creating-a-landsat-stac.ipynb @@ -25,7 +25,13 @@ "metadata": {}, "outputs": [], "source": [ - "import pystac" + "from typing import Any, Dict, List, Optional, cast\n", + "from typing_extensions import TypedDict\n", + "\n", + "import pystac\n", + "from pystac.extensions.eo import EOExtension\n", + "from pystac.extensions.projection import ProjectionExtension\n", + "from pystac.extensions.view import ViewExtension" ] }, { @@ -44,10 +50,28 @@ "outputs": [], "source": [ "import csv\n", + "from datetime import datetime\n", "import gzip\n", "from io import StringIO\n", "from urllib.request import urlopen\n", "\n", + "# Here we use a TypedDict to define the structure of the Landsat scene dictionaries\n", + "# we will be working with. You can read more about the TypedDict class here:\n", + "# https://docs.python.org/3/library/typing.html#typing.TypedDict\n", + "class Scene(TypedDict):\n", + " productId: str\n", + " entityId: str\n", + " acquisitionDate: str\n", + " cloudCover: str\n", + " processingLevel: str\n", + " path: str\n", + " row: str\n", + " min_lat: str\n", + " min_lon: str\n", + " max_lat: str\n", + " max_lon: str\n", + " download_url: str\n", + "\n", "# Collection 1 data\n", "url = 'https://landsat-pds.s3.amazonaws.com/c1/L8/scene_list.gz'\n", "\n", @@ -57,7 +81,7 @@ "content = gunzip_response.read()\n", "\n", "# Read the scenes in as dictionaries\n", - "scenes = list(csv.DictReader(StringIO(content.decode(\"utf-8\"))))" + "scenes: List[Scene] = list(map(lambda s: cast(Scene, s), csv.DictReader(StringIO(content.decode(\"utf-8\")))))" ] }, { @@ -68,7 +92,7 @@ { "data": { "text/plain": [ - "2073901" + "2390885" ] }, "execution_count": 3, @@ -97,19 +121,18 @@ { "data": { "text/plain": [ - "OrderedDict([('productId', 'LC08_L1TP_149039_20170411_20170415_01_T1'),\n", - " ('entityId', 'LC81490392017101LGN00'),\n", - " ('acquisitionDate', '2017-04-11 05:36:29.349932'),\n", - " ('cloudCover', '0.0'),\n", - " ('processingLevel', 'L1TP'),\n", - " ('path', '149'),\n", - " ('row', '39'),\n", - " ('min_lat', '29.22165'),\n", - " ('min_lon', '72.41205'),\n", - " ('max_lat', '31.34742'),\n", - " ('max_lon', '74.84666'),\n", - " ('download_url',\n", - " 'https://s3-us-west-2.amazonaws.com/landsat-pds/c1/L8/149/039/LC08_L1TP_149039_20170411_20170415_01_T1/index.html')])" + "{'productId': 'LC08_L1TP_149039_20170411_20170415_01_T1',\n", + " 'entityId': 'LC81490392017101LGN00',\n", + " 'acquisitionDate': '2017-04-11 05:36:29.349932',\n", + " 'cloudCover': '0.0',\n", + " 'processingLevel': 'L1TP',\n", + " 'path': '149',\n", + " 'row': '39',\n", + " 'min_lat': '29.22165',\n", + " 'min_lon': '72.41205',\n", + " 'max_lat': '31.34742',\n", + " 'max_lon': '74.84666',\n", + " 'download_url': 'https://s3-us-west-2.amazonaws.com/landsat-pds/c1/L8/149/039/LC08_L1TP_149039_20170411_20170415_01_T1/index.html'}" ] }, "execution_count": 4, @@ -161,7 +184,7 @@ "metadata": {}, "outputs": [], "source": [ - "def keep_scene(scene):\n", + "def keep_scene(scene: Scene) -> bool:\n", " contains_location = float(scene['min_lat']) < lat and float(scene['max_lat']) > lat and \\\n", " float(scene['min_lon']) < lon and float(scene['max_lon']) > lon\n", " is_correct_year = '{}-'.format(filter_year) in scene['acquisitionDate']\n", @@ -185,7 +208,7 @@ { "data": { "text/plain": [ - "52" + "77" ] }, "execution_count": 7, @@ -212,19 +235,18 @@ { "data": { "text/plain": [ - "OrderedDict([('productId', 'LC08_L1GT_015032_20200103_20200103_01_RT'),\n", - " ('entityId', 'LC80150322020003LGN00'),\n", - " ('acquisitionDate', '2020-01-03 15:46:15.625235'),\n", - " ('cloudCover', '100.0'),\n", - " ('processingLevel', 'L1GT'),\n", - " ('path', '15'),\n", - " ('row', '32'),\n", - " ('min_lat', '39.23189'),\n", - " ('min_lon', '-77.83282'),\n", - " ('max_lat', '41.37536'),\n", - " ('max_lon', '-75.02666'),\n", - " ('download_url',\n", - " 'https://s3-us-west-2.amazonaws.com/landsat-pds/c1/L8/015/032/LC08_L1GT_015032_20200103_20200103_01_RT/index.html')])" + "{'productId': 'LC08_L1GT_015032_20200103_20200103_01_RT',\n", + " 'entityId': 'LC80150322020003LGN00',\n", + " 'acquisitionDate': '2020-01-03 15:46:15.625235',\n", + " 'cloudCover': '100.0',\n", + " 'processingLevel': 'L1GT',\n", + " 'path': '15',\n", + " 'row': '32',\n", + " 'min_lat': '39.23189',\n", + " 'min_lon': '-77.83282',\n", + " 'max_lat': '41.37536',\n", + " 'max_lon': '-75.02666',\n", + " 'download_url': 'https://s3-us-west-2.amazonaws.com/landsat-pds/c1/L8/015/032/LC08_L1GT_015032_20200103_20200103_01_RT/index.html'}" ] }, "execution_count": 8, @@ -254,7 +276,7 @@ "metadata": {}, "outputs": [], "source": [ - "def get_asset_url(scene, suffix):\n", + "def get_asset_url(scene: Scene, suffix: str) -> str:\n", " product_id = scene['productId']\n", " download_url = scene['download_url'] \n", " asset_filename = '{}_{}'.format(product_id, suffix)\n", @@ -500,8 +522,9 @@ } ], "source": [ + "stac_io = pystac.StacIO.default()\n", "mtl_url = get_asset_url(scene, 'MTL.txt')\n", - "print(pystac.STAC_IO.read_text(mtl_url))" + "print(stac_io.read_text(mtl_url))" ] }, { @@ -517,10 +540,10 @@ "metadata": {}, "outputs": [], "source": [ - "def get_metadata(url):\n", + "def get_metadata(url: str) -> Dict[str, Any]:\n", " \"\"\" Convert Landsat MTL file to dictionary of metadata values \"\"\"\n", " mtl = {}\n", - " mtl_text = pystac.STAC_IO.read_text(url)\n", + " mtl_text = stac_io.read_text(url)\n", " for line in mtl_text.split('\\n'):\n", " meta = line.replace('\\\"', \"\").strip().split('=')\n", " if len(meta) > 1:\n", @@ -770,7 +793,7 @@ "text": [ "Help on function __init__ in module pystac.item:\n", "\n", - "__init__(self, id, geometry, bbox, datetime, properties, stac_extensions=None, href=None, collection=None, extra_fields=None)\n", + "__init__(self, id: str, geometry: Union[Dict[str, Any], NoneType], bbox: Union[List[float], NoneType], datetime: Union[datetime.datetime, NoneType], properties: Dict[str, Any], stac_extensions: Union[List[str], NoneType] = None, href: Union[str, NoneType] = None, collection: Union[str, pystac.collection.Collection, NoneType] = None, extra_fields: Union[Dict[str, Any], NoneType] = None)\n", " Initialize self. See help(type(self)) for accurate signature.\n", "\n" ] @@ -802,8 +825,8 @@ "metadata": {}, "outputs": [], "source": [ - "def get_item_id(metadata):\n", - " return metadata['LANDSAT_SCENE_ID'][:-5]" + "def get_item_id(metadata: Dict[str, Any]) -> str:\n", + " return cast(str, metadata['LANDSAT_SCENE_ID'][:-5])" ] }, { @@ -844,7 +867,7 @@ "source": [ "from dateutil.parser import parse\n", "\n", - "def get_datetime(metadata):\n", + "def get_datetime(metadata: Dict[str, Any]) -> datetime:\n", " return parse('%sT%s' % (metadata['DATE_ACQUIRED'], metadata['SCENE_CENTER_TIME']))" ] }, @@ -884,7 +907,7 @@ "metadata": {}, "outputs": [], "source": [ - "def get_bbox(metadata):\n", + "def get_bbox(metadata: Dict[str, Any]) -> List[float]:\n", " coords = [[\n", " [float(metadata['CORNER_UL_LON_PRODUCT']), float(metadata['CORNER_UL_LAT_PRODUCT'])],\n", " [float(metadata['CORNER_UR_LON_PRODUCT']), float(metadata['CORNER_UR_LAT_PRODUCT'])],\n", @@ -935,11 +958,11 @@ "metadata": {}, "outputs": [], "source": [ - "def get_geometry(scene, bbox):\n", + "def get_geometry(scene: Scene, bbox: List[float]) -> Dict[str, Any]:\n", " url = get_asset_url(scene, 'ANG.txt')\n", " sz = []\n", " coords = []\n", - " ang_text = pystac.STAC_IO.read_text(url)\n", + " ang_text = stac_io.read_text(url)\n", " for line in ang_text.split('\\n'):\n", " if 'BAND01_NUM_L1T_LINES' in line or 'BAND01_NUM_L1T_SAMPS' in line:\n", " sz.append(float(line.split('=')[1]))\n", @@ -1069,7 +1092,18 @@ "cell_type": "code", "execution_count": 24, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "['https://schemas.stacspec.org/v1.0.0/item-spec/json-schema/item.json']" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "item.validate()" ] @@ -1109,7 +1143,7 @@ "metadata": {}, "outputs": [], "source": [ - "item.ext.enable('eo')" + "eo_ext = EOExtension.ext(item, add_if_missing=True)" ] }, { @@ -1127,7 +1161,7 @@ "metadata": {}, "outputs": [], "source": [ - "def get_cloud_cover(metadata):\n", + "def get_cloud_cover(metadata: Dict[str, Any]) -> float:\n", " return float(metadata['CLOUD_COVER'])" ] }, @@ -1148,8 +1182,8 @@ } ], "source": [ - "item.ext.eo.cloud_cover = get_cloud_cover(metadata)\n", - "item.ext.eo.cloud_cover" + "eo_ext.cloud_cover = get_cloud_cover(metadata)\n", + "eo_ext.cloud_cover" ] }, { @@ -1171,7 +1205,12 @@ "source": [ "from pystac.extensions.eo import Band\n", "\n", - "landsat_band_info = {\n", + "class BandInfo(TypedDict):\n", + " band: Band\n", + " gsd: float\n", + "\n", + "\n", + "landsat_band_info: Dict[str, BandInfo] = {\n", " 'B1': {\n", " 'band': Band.create(name=\"B1\", common_name=\"coastal\", center_wavelength=0.48, full_width_half_max=0.02),\n", " 'gsd': 30.0\n", @@ -1232,7 +1271,7 @@ "metadata": {}, "outputs": [], "source": [ - "def get_other_assets(scene):\n", + "def get_other_assets(scene: Scene) -> Dict[str, Dict[str, Any]]:\n", " return {\n", " 'thumbnail': {\n", " 'href': get_asset_url(scene, 'thumb_large.jpg'),\n", @@ -1270,18 +1309,19 @@ "metadata": {}, "outputs": [], "source": [ - "def add_assets(item, scene):\n", + "def add_assets(item: pystac.Item, scene: Scene) -> None:\n", " # Add bands\n", " for band_id, band_info in landsat_band_info.items():\n", " band_url = get_asset_url(scene, '{}.TIF'.format(band_id))\n", " asset = pystac.Asset(href=band_url, media_type=pystac.MediaType.COG)\n", " bands = [band_info['band']]\n", - " item.ext.eo.set_bands(bands, asset)\n", + " asset_eo_ext = EOExtension.ext(asset)\n", + " asset_eo_ext.bands = bands\n", " item.add_asset(band_id, asset)\n", " \n", " # If this asset has a different GSD than the item, set it on the asset\n", " if band_info['gsd'] != item.common_metadata.gsd:\n", - " item.common_metadata.set_gsd(band_info['gsd'], asset)\n", + " asset.common_metadata.gsd = band_info[\"gsd\"]\n", " \n", " # Add other assets\n", " for asset_id, asset_info in get_other_assets(scene).items():\n", @@ -1315,7 +1355,7 @@ "data": { "text/plain": [ "{'href': 'https://s3-us-west-2.amazonaws.com/landsat-pds/c1/L8/015/032/LC08_L1GT_015032_20200103_20200103_01_RT/LC08_L1GT_015032_20200103_20200103_01_RT_B10.TIF',\n", - " 'type': 'image/tiff; application=geotiff; profile=cloud-optimized',\n", + " 'type': ,\n", " 'eo:bands': [{'name': 'B10',\n", " 'common_name': 'lwir11',\n", " 'center_wavelength': 10.9,\n", @@ -1341,7 +1381,7 @@ "data": { "text/plain": [ "{'href': 'https://s3-us-west-2.amazonaws.com/landsat-pds/c1/L8/015/032/LC08_L1GT_015032_20200103_20200103_01_RT/LC08_L1GT_015032_20200103_20200103_01_RT_B3.TIF',\n", - " 'type': 'image/tiff; application=geotiff; profile=cloud-optimized',\n", + " 'type': ,\n", " 'eo:bands': [{'name': 'B3',\n", " 'common_name': 'green',\n", " 'center_wavelength': 0.56,\n", @@ -1373,7 +1413,7 @@ "data": { "text/plain": [ "{'href': 'https://s3-us-west-2.amazonaws.com/landsat-pds/c1/L8/015/032/LC08_L1GT_015032_20200103_20200103_01_RT/LC08_L1GT_015032_20200103_20200103_01_RT_thumb_large.jpg',\n", - " 'type': 'image/jpeg'}" + " 'type': }" ] }, "execution_count": 35, @@ -1400,7 +1440,7 @@ "metadata": {}, "outputs": [], "source": [ - "def get_epsg(metadata, min_lat, max_lat):\n", + "def get_epsg(metadata: Dict[str, Any], min_lat: float, max_lat: float) -> Optional[int]:\n", " if 'UTM_ZONE' in metadata:\n", " center_lat = (min_lat + max_lat)/2.0\n", " return int(('326' if center_lat > 0 else '327') + metadata['UTM_ZONE'])\n", @@ -1410,24 +1450,14 @@ }, { "cell_type": "code", - "execution_count": 37, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "32618" - ] - }, - "execution_count": 37, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ - "item.ext.enable('projection')\n", - "item.ext.projection.epsg = get_epsg(metadata, item.bbox[1], item.bbox[3]) \n", - "item.ext.projection.epsg" + "proj_ext = ProjectionExtension.ext(item, add_if_missing=True)\n", + "assert item.bbox is not None\n", + "proj_ext.epsg = get_epsg(metadata, item.bbox[1], item.bbox[3]) \n", + "proj_ext.epsg" ] }, { @@ -1441,18 +1471,18 @@ }, { "cell_type": "code", - "execution_count": 38, + "execution_count": 37, "metadata": {}, "outputs": [], "source": [ - "def get_view_info(metadata):\n", + "def get_view_info(metadata: Dict[str, Any]) -> Dict[str, float]:\n", " return { 'sun_azimuth': float(metadata['SUN_AZIMUTH']),\n", " 'sun_elevation': float(metadata['SUN_ELEVATION']) }" ] }, { "cell_type": "code", - "execution_count": 39, + "execution_count": 38, "metadata": {}, "outputs": [ { @@ -1461,21 +1491,20 @@ "{'datetime': '2020-01-03T15:46:15.625235Z',\n", " 'gsd': 30.0,\n", " 'eo:cloud_cover': 100.0,\n", - " 'proj:epsg': 32618,\n", " 'view:sun_azimuth': 158.89720783,\n", " 'view:sun_elevation': 23.89789093}" ] }, - "execution_count": 39, + "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "item.ext.enable('view')\n", + "view_ext = ViewExtension.ext(item, add_if_missing=True)\n", "view_info = get_view_info(metadata)\n", - "item.ext.view.sun_azimuth = view_info['sun_azimuth']\n", - "item.ext.view.sun_elevation = view_info['sun_elevation']\n", + "view_ext.sun_azimuth = view_info['sun_azimuth']\n", + "view_ext.sun_elevation = view_info['sun_elevation']\n", "item.properties" ] }, @@ -1488,9 +1517,22 @@ }, { "cell_type": "code", - "execution_count": 40, + "execution_count": 39, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "['https://schemas.stacspec.org/v1.0.0/item-spec/json-schema/item.json',\n", + " 'https://stac-extensions.github.io/eo/v1.0.0/schema.json',\n", + " 'https://stac-extensions.github.io/view/v1.0.0/schema.json']" + ] + }, + "execution_count": 39, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "item.validate()" ] @@ -1508,7 +1550,7 @@ }, { "cell_type": "code", - "execution_count": 41, + "execution_count": 40, "metadata": {}, "outputs": [ { @@ -1517,7 +1559,7 @@ "text": [ "Help on function __init__ in module pystac.collection:\n", "\n", - "__init__(self, id, description, extent, title=None, stac_extensions=None, href=None, extra_fields=None, license='proprietary', keywords=None, providers=None, properties=None, summaries=None)\n", + "__init__(self, id: str, description: str, extent: pystac.collection.Extent, title: Union[str, NoneType] = None, stac_extensions: Union[List[str], NoneType] = None, href: Union[str, NoneType] = None, extra_fields: Union[Dict[str, Any], NoneType] = None, catalog_type: Union[pystac.catalog.CatalogType, NoneType] = None, license: str = 'proprietary', keywords: Union[List[str], NoneType] = None, providers: Union[List[ForwardRef('Provider_Type')], NoneType] = None, summaries: Union[pystac.summaries.Summaries, NoneType] = None)\n", " Initialize self. See help(type(self)) for accurate signature.\n", "\n" ] @@ -1538,7 +1580,7 @@ }, { "cell_type": "code", - "execution_count": 42, + "execution_count": 41, "metadata": {}, "outputs": [ { @@ -1547,7 +1589,7 @@ "'Philly-landsat-8'" ] }, - "execution_count": 42, + "execution_count": 41, "metadata": {}, "output_type": "execute_result" } @@ -1568,7 +1610,7 @@ }, { "cell_type": "code", - "execution_count": 43, + "execution_count": 42, "metadata": {}, "outputs": [ { @@ -1577,7 +1619,7 @@ "'2020 Landsat 8 images over Philly'" ] }, - "execution_count": 43, + "execution_count": 42, "metadata": {}, "output_type": "execute_result" } @@ -1600,7 +1642,7 @@ }, { "cell_type": "code", - "execution_count": 44, + "execution_count": 43, "metadata": {}, "outputs": [ { @@ -1635,20 +1677,20 @@ }, { "cell_type": "code", - "execution_count": 45, + "execution_count": 44, "metadata": {}, "outputs": [], "source": [ "from datetime import datetime\n", "\n", - "spatial_extent = pystac.SpatialExtent([[-180, -90, 180, 90]])\n", + "spatial_extent = pystac.SpatialExtent([[-180., -90., 180., 90.]])\n", "temporal_extent = pystac.TemporalExtent([[datetime(2013, 6, 1), None]])\n", "collection_extent = pystac.Extent(spatial_extent, temporal_extent)" ] }, { "cell_type": "code", - "execution_count": 46, + "execution_count": 45, "metadata": {}, "outputs": [], "source": [ @@ -1667,23 +1709,28 @@ }, { "cell_type": "code", - "execution_count": 47, + "execution_count": 46, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "{'id': 'Philly-landsat-8',\n", - " 'stac_version': '1.0.0-beta.2',\n", + "{'type': 'Collection',\n", + " 'id': 'Philly-landsat-8',\n", + " 'stac_version': '1.0.0',\n", " 'description': '### Philly Landsat 8\\n\\nA collection of Landsat 8 scenes around Philly in 2020.\\n',\n", - " 'links': [{'rel': 'root', 'href': None, 'type': 'application/json'}],\n", + " 'links': [{'rel': ,\n", + " 'href': None,\n", + " 'type': ,\n", + " 'title': '2020 Landsat 8 images over Philly'}],\n", + " 'stac_extensions': [],\n", " 'title': '2020 Landsat 8 images over Philly',\n", " 'extent': {'spatial': {'bbox': [[-180, -90, 180, 90]]},\n", " 'temporal': {'interval': [['2013-06-01T00:00:00Z', None]]}},\n", " 'license': 'proprietary'}" ] }, - "execution_count": 47, + "execution_count": 46, "metadata": {}, "output_type": "execute_result" } @@ -1703,7 +1750,7 @@ }, { "cell_type": "code", - "execution_count": 48, + "execution_count": 47, "metadata": {}, "outputs": [], "source": [ @@ -1721,14 +1768,14 @@ }, { "cell_type": "code", - "execution_count": 49, + "execution_count": 48, "metadata": {}, "outputs": [], "source": [ "collection.providers = [\n", - " pystac.Provider(name='USGS', roles=['producer'], url='https://landsat.usgs.gov/'),\n", - " pystac.Provider(name='Planet Labs', roles=['processor'], url='https://github.com/landsat-pds/landsat_ingestor'),\n", - " pystac.Provider(name='AWS', roles=['host'], url='https://landsatonaws.com/')\n", + " pystac.Provider(name='USGS', roles=[pystac.ProviderRole.PRODUCER], url='https://landsat.usgs.gov/'),\n", + " pystac.Provider(name='Planet Labs', roles=[pystac.ProviderRole.PROCESSOR], url='https://github.com/landsat-pds/landsat_ingestor'),\n", + " pystac.Provider(name='AWS', roles=[pystac.ProviderRole.HOST], url='https://landsatonaws.com/')\n", "]" ] }, @@ -1743,11 +1790,11 @@ }, { "cell_type": "code", - "execution_count": 50, + "execution_count": 49, "metadata": {}, "outputs": [], "source": [ - "def item_from_scene(scene):\n", + "def item_from_scene(scene: Scene) -> pystac.Item:\n", " mtl_url = get_asset_url(scene, 'MTL.txt')\n", " metadata = get_metadata(mtl_url)\n", " \n", @@ -1760,18 +1807,19 @@ " \n", " item.common_metadata.gsd = 30.0\n", " \n", - " item.ext.enable('eo')\n", - " item.ext.eo.cloud_cover = get_cloud_cover(metadata)\n", + " item_eo_ext = EOExtension.ext(item, add_if_missing=True)\n", + " item_eo_ext.cloud_cover = get_cloud_cover(metadata)\n", " \n", " add_assets(item, scene)\n", " \n", - " item.ext.enable('projection')\n", - " item.ext.projection.epsg = get_epsg(metadata, item.bbox[1], item.bbox[3]) \n", + " item_proj_ext = ProjectionExtension.ext(item, add_if_missing=True)\n", + " assert item.bbox is not None\n", + " item_proj_ext.epsg = get_epsg(metadata, item.bbox[1], item.bbox[3]) \n", "\n", - " item.ext.enable('view')\n", + " item_view_ext = ViewExtension.ext(item, add_if_missing=True)\n", " view_info = get_view_info(metadata)\n", - " item.ext.view.sun_azimuth = view_info['sun_azimuth']\n", - " item.ext.view.sun_elevation = view_info['sun_elevation']\n", + " item_view_ext.sun_azimuth = view_info['sun_azimuth']\n", + " item_view_ext.sun_elevation = view_info['sun_elevation']\n", "\n", " item.validate()\n", " \n", @@ -1788,7 +1836,7 @@ }, { "cell_type": "code", - "execution_count": 51, + "execution_count": 50, "metadata": {}, "outputs": [], "source": [ @@ -1808,7 +1856,7 @@ }, { "cell_type": "code", - "execution_count": 52, + "execution_count": 51, "metadata": {}, "outputs": [ { @@ -1816,10 +1864,10 @@ "text/plain": [ "{'spatial': {'bbox': [[-77.88298, 39.23073, -73.46322, 41.41025]]},\n", " 'temporal': {'interval': [['2020-01-03T15:46:15.625235Z',\n", - " '2020-08-30T15:46:11.765407Z']]}}" + " '2020-12-29T15:40:09.950514Z']]}}" ] }, - "execution_count": 52, + "execution_count": 51, "metadata": {}, "output_type": "execute_result" } @@ -1844,20 +1892,9 @@ }, { "cell_type": "code", - "execution_count": 53, + "execution_count": 52, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 53, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "from pathlib import Path\n", "\n", @@ -1875,7 +1912,7 @@ }, { "cell_type": "code", - "execution_count": 54, + "execution_count": 53, "metadata": {}, "outputs": [], "source": [ @@ -1895,7 +1932,7 @@ }, { "cell_type": "code", - "execution_count": 55, + "execution_count": 54, "metadata": {}, "outputs": [], "source": [ @@ -1911,7 +1948,7 @@ }, { "cell_type": "code", - "execution_count": 56, + "execution_count": 55, "metadata": {}, "outputs": [ { @@ -1970,7 +2007,32 @@ " * \n", " * \n", " * \n", - " * \n" + " * \n", + " * \n", + " * \n", + " * \n", + " * \n", + " * \n", + " * \n", + " * \n", + " * \n", + " * \n", + " * \n", + " * \n", + " * \n", + " * \n", + " * \n", + " * \n", + " * \n", + " * \n", + " * \n", + " * \n", + " * \n", + " * \n", + " * \n", + " * \n", + " * \n", + " * \n" ] } ], @@ -1987,181 +2049,259 @@ }, { "cell_type": "code", - "execution_count": 57, + "execution_count": 56, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "{'id': 'Philly-landsat-8',\n", - " 'stac_version': '1.0.0-beta.2',\n", + "{'type': 'Collection',\n", + " 'id': 'Philly-landsat-8',\n", + " 'stac_version': '1.0.0',\n", " 'description': '### Philly Landsat 8\\n\\nA collection of Landsat 8 scenes around Philly in 2020.\\n',\n", - " 'links': [{'rel': 'root',\n", + " 'links': [{'rel': ,\n", " 'href': './collection.json',\n", - " 'type': 'application/json'},\n", - " {'rel': 'item',\n", + " 'type': ,\n", + " 'title': '2020 Landsat 8 images over Philly'},\n", + " {'rel': ,\n", " 'href': './LC80150322020003/LC80150322020003.json',\n", - " 'type': 'application/json'},\n", - " {'rel': 'item',\n", + " 'type': },\n", + " {'rel': ,\n", " 'href': './LC80140322020012/LC80140322020012.json',\n", - " 'type': 'application/json'},\n", - " {'rel': 'item',\n", + " 'type': },\n", + " {'rel': ,\n", " 'href': './LC80150322020019/LC80150322020019.json',\n", - " 'type': 'application/json'},\n", - " {'rel': 'item',\n", + " 'type': },\n", + " {'rel': ,\n", " 'href': './LC80140322020012/LC80140322020012.json',\n", - " 'type': 'application/json'},\n", - " {'rel': 'item',\n", + " 'type': },\n", + " {'rel': ,\n", " 'href': './LC80150322020019/LC80150322020019.json',\n", - " 'type': 'application/json'},\n", - " {'rel': 'item',\n", + " 'type': },\n", + " {'rel': ,\n", " 'href': './LC80140322020028/LC80140322020028.json',\n", - " 'type': 'application/json'},\n", - " {'rel': 'item',\n", + " 'type': },\n", + " {'rel': ,\n", " 'href': './LC80150322020035/LC80150322020035.json',\n", - " 'type': 'application/json'},\n", - " {'rel': 'item',\n", + " 'type': },\n", + " {'rel': ,\n", " 'href': './LC80140322020028/LC80140322020028.json',\n", - " 'type': 'application/json'},\n", - " {'rel': 'item',\n", + " 'type': },\n", + " {'rel': ,\n", " 'href': './LC80140322020044/LC80140322020044.json',\n", - " 'type': 'application/json'},\n", - " {'rel': 'item',\n", + " 'type': },\n", + " {'rel': ,\n", " 'href': './LC80150322020051/LC80150322020051.json',\n", - " 'type': 'application/json'},\n", - " {'rel': 'item',\n", + " 'type': },\n", + " {'rel': ,\n", " 'href': './LC80150322020051/LC80150322020051.json',\n", - " 'type': 'application/json'},\n", - " {'rel': 'item',\n", + " 'type': },\n", + " {'rel': ,\n", " 'href': './LC80150322020051/LC80150322020051.json',\n", - " 'type': 'application/json'},\n", - " {'rel': 'item',\n", + " 'type': },\n", + " {'rel': ,\n", " 'href': './LC80150322020051/LC80150322020051.json',\n", - " 'type': 'application/json'},\n", - " {'rel': 'item',\n", + " 'type': },\n", + " {'rel': ,\n", " 'href': './LC80140322020060/LC80140322020060.json',\n", - " 'type': 'application/json'},\n", - " {'rel': 'item',\n", + " 'type': },\n", + " {'rel': ,\n", " 'href': './LC80150322020067/LC80150322020067.json',\n", - " 'type': 'application/json'},\n", - " {'rel': 'item',\n", + " 'type': },\n", + " {'rel': ,\n", " 'href': './LC80140322020060/LC80140322020060.json',\n", - " 'type': 'application/json'},\n", - " {'rel': 'item',\n", + " 'type': },\n", + " {'rel': ,\n", " 'href': './LC80150322020067/LC80150322020067.json',\n", - " 'type': 'application/json'},\n", - " {'rel': 'item',\n", + " 'type': },\n", + " {'rel': ,\n", " 'href': './LC80140322020076/LC80140322020076.json',\n", - " 'type': 'application/json'},\n", - " {'rel': 'item',\n", + " 'type': },\n", + " {'rel': ,\n", " 'href': './LC80150322020083/LC80150322020083.json',\n", - " 'type': 'application/json'},\n", - " {'rel': 'item',\n", + " 'type': },\n", + " {'rel': ,\n", " 'href': './LC80140322020076/LC80140322020076.json',\n", - " 'type': 'application/json'},\n", - " {'rel': 'item',\n", + " 'type': },\n", + " {'rel': ,\n", " 'href': './LC80140322020092/LC80140322020092.json',\n", - " 'type': 'application/json'},\n", - " {'rel': 'item',\n", + " 'type': },\n", + " {'rel': ,\n", " 'href': './LC80150322020099/LC80150322020099.json',\n", - " 'type': 'application/json'},\n", - " {'rel': 'item',\n", + " 'type': },\n", + " {'rel': ,\n", " 'href': './LC80140322020092/LC80140322020092.json',\n", - " 'type': 'application/json'},\n", - " {'rel': 'item',\n", + " 'type': },\n", + " {'rel': ,\n", " 'href': './LC80140322020108/LC80140322020108.json',\n", - " 'type': 'application/json'},\n", - " {'rel': 'item',\n", + " 'type': },\n", + " {'rel': ,\n", " 'href': './LC80140322020108/LC80140322020108.json',\n", - " 'type': 'application/json'},\n", - " {'rel': 'item',\n", + " 'type': },\n", + " {'rel': ,\n", " 'href': './LC80150322020115/LC80150322020115.json',\n", - " 'type': 'application/json'},\n", - " {'rel': 'item',\n", + " 'type': },\n", + " {'rel': ,\n", " 'href': './LC80150322020099/LC80150322020099.json',\n", - " 'type': 'application/json'},\n", - " {'rel': 'item',\n", + " 'type': },\n", + " {'rel': ,\n", " 'href': './LC80140322020124/LC80140322020124.json',\n", - " 'type': 'application/json'},\n", - " {'rel': 'item',\n", + " 'type': },\n", + " {'rel': ,\n", " 'href': './LC80150322020131/LC80150322020131.json',\n", - " 'type': 'application/json'},\n", - " {'rel': 'item',\n", + " 'type': },\n", + " {'rel': ,\n", " 'href': './LC80140322020124/LC80140322020124.json',\n", - " 'type': 'application/json'},\n", - " {'rel': 'item',\n", + " 'type': },\n", + " {'rel': ,\n", " 'href': './LC80140322020140/LC80140322020140.json',\n", - " 'type': 'application/json'},\n", - " {'rel': 'item',\n", + " 'type': },\n", + " {'rel': ,\n", " 'href': './LC80150322020147/LC80150322020147.json',\n", - " 'type': 'application/json'},\n", - " {'rel': 'item',\n", + " 'type': },\n", + " {'rel': ,\n", " 'href': './LC80150322020131/LC80150322020131.json',\n", - " 'type': 'application/json'},\n", - " {'rel': 'item',\n", + " 'type': },\n", + " {'rel': ,\n", " 'href': './LC80140322020140/LC80140322020140.json',\n", - " 'type': 'application/json'},\n", - " {'rel': 'item',\n", + " 'type': },\n", + " {'rel': ,\n", " 'href': './LC80140322020156/LC80140322020156.json',\n", - " 'type': 'application/json'},\n", - " {'rel': 'item',\n", + " 'type': },\n", + " {'rel': ,\n", " 'href': './LC80150322020147/LC80150322020147.json',\n", - " 'type': 'application/json'},\n", - " {'rel': 'item',\n", + " 'type': },\n", + " {'rel': ,\n", " 'href': './LC80140322020156/LC80140322020156.json',\n", - " 'type': 'application/json'},\n", - " {'rel': 'item',\n", + " 'type': },\n", + " {'rel': ,\n", " 'href': './LC80150322020163/LC80150322020163.json',\n", - " 'type': 'application/json'},\n", - " {'rel': 'item',\n", + " 'type': },\n", + " {'rel': ,\n", " 'href': './LC80140322020172/LC80140322020172.json',\n", - " 'type': 'application/json'},\n", - " {'rel': 'item',\n", + " 'type': },\n", + " {'rel': ,\n", " 'href': './LC80150322020179/LC80150322020179.json',\n", - " 'type': 'application/json'},\n", - " {'rel': 'item',\n", + " 'type': },\n", + " {'rel': ,\n", " 'href': './LC80150322020163/LC80150322020163.json',\n", - " 'type': 'application/json'},\n", - " {'rel': 'item',\n", + " 'type': },\n", + " {'rel': ,\n", " 'href': './LC80140322020188/LC80140322020188.json',\n", - " 'type': 'application/json'},\n", - " {'rel': 'item',\n", + " 'type': },\n", + " {'rel': ,\n", " 'href': './LC80140322020172/LC80140322020172.json',\n", - " 'type': 'application/json'},\n", - " {'rel': 'item',\n", + " 'type': },\n", + " {'rel': ,\n", " 'href': './LC80150322020179/LC80150322020179.json',\n", - " 'type': 'application/json'},\n", - " {'rel': 'item',\n", + " 'type': },\n", + " {'rel': ,\n", " 'href': './LC80150322020195/LC80150322020195.json',\n", - " 'type': 'application/json'},\n", - " {'rel': 'item',\n", + " 'type': },\n", + " {'rel': ,\n", " 'href': './LC80150322020211/LC80150322020211.json',\n", - " 'type': 'application/json'},\n", - " {'rel': 'item',\n", + " 'type': },\n", + " {'rel': ,\n", " 'href': './LC80150322020195/LC80150322020195.json',\n", - " 'type': 'application/json'},\n", - " {'rel': 'item',\n", + " 'type': },\n", + " {'rel': ,\n", " 'href': './LC80140322020188/LC80140322020188.json',\n", - " 'type': 'application/json'},\n", - " {'rel': 'item',\n", + " 'type': },\n", + " {'rel': ,\n", " 'href': './LC80140322020204/LC80140322020204.json',\n", - " 'type': 'application/json'},\n", - " {'rel': 'item',\n", + " 'type': },\n", + " {'rel': ,\n", " 'href': './LC80150322020227/LC80150322020227.json',\n", - " 'type': 'application/json'},\n", - " {'rel': 'item',\n", + " 'type': },\n", + " {'rel': ,\n", " 'href': './LC80140322020220/LC80140322020220.json',\n", - " 'type': 'application/json'},\n", - " {'rel': 'item',\n", + " 'type': },\n", + " {'rel': ,\n", " 'href': './LC80150322020243/LC80150322020243.json',\n", - " 'type': 'application/json'},\n", - " {'rel': 'self',\n", - " 'href': '/Users/rob/Philly-landsat-stac/collection.json',\n", - " 'type': 'application/json'}],\n", + " 'type': },\n", + " {'rel': ,\n", + " 'href': './LC80140322020236/LC80140322020236.json',\n", + " 'type': },\n", + " {'rel': ,\n", + " 'href': './LC80140322020252/LC80140322020252.json',\n", + " 'type': },\n", + " {'rel': ,\n", + " 'href': './LC80150322020243/LC80150322020243.json',\n", + " 'type': },\n", + " {'rel': ,\n", + " 'href': './LC80150322020243/LC80150322020243.json',\n", + " 'type': },\n", + " {'rel': ,\n", + " 'href': './LC80140322020236/LC80140322020236.json',\n", + " 'type': },\n", + " {'rel': ,\n", + " 'href': './LC80150322020259/LC80150322020259.json',\n", + " 'type': },\n", + " {'rel': ,\n", + " 'href': './LC80150322020259/LC80150322020259.json',\n", + " 'type': },\n", + " {'rel': ,\n", + " 'href': './LC80140322020252/LC80140322020252.json',\n", + " 'type': },\n", + " {'rel': ,\n", + " 'href': './LC80140322020268/LC80140322020268.json',\n", + " 'type': },\n", + " {'rel': ,\n", + " 'href': './LC80150322020275/LC80150322020275.json',\n", + " 'type': },\n", + " {'rel': ,\n", + " 'href': './LC80150322020275/LC80150322020275.json',\n", + " 'type': },\n", + " {'rel': ,\n", + " 'href': './LC80140322020268/LC80140322020268.json',\n", + " 'type': },\n", + " {'rel': ,\n", + " 'href': './LC80140322020284/LC80140322020284.json',\n", + " 'type': },\n", + " {'rel': ,\n", + " 'href': './LC80140322020284/LC80140322020284.json',\n", + " 'type': },\n", + " {'rel': ,\n", + " 'href': './LC80150322020291/LC80150322020291.json',\n", + " 'type': },\n", + " {'rel': ,\n", + " 'href': './LC80140322020300/LC80140322020300.json',\n", + " 'type': },\n", + " {'rel': ,\n", + " 'href': './LC80140322020332/LC80140322020332.json',\n", + " 'type': },\n", + " {'rel': ,\n", + " 'href': './LC80150322020339/LC80150322020339.json',\n", + " 'type': },\n", + " {'rel': ,\n", + " 'href': './LC80150322020323/LC80150322020323.json',\n", + " 'type': },\n", + " {'rel': ,\n", + " 'href': './LC80140322020332/LC80140322020332.json',\n", + " 'type': },\n", + " {'rel': ,\n", + " 'href': './LC80140322020348/LC80140322020348.json',\n", + " 'type': },\n", + " {'rel': ,\n", + " 'href': './LC80150322020339/LC80150322020339.json',\n", + " 'type': },\n", + " {'rel': ,\n", + " 'href': './LC80140322020348/LC80140322020348.json',\n", + " 'type': },\n", + " {'rel': ,\n", + " 'href': './LC80150322020355/LC80150322020355.json',\n", + " 'type': },\n", + " {'rel': ,\n", + " 'href': './LC80140322020364/LC80140322020364.json',\n", + " 'type': },\n", + " {'rel': ,\n", + " 'href': '/Users/jduckworth/Philly-landsat-stac/collection.json',\n", + " 'type': }],\n", + " 'stac_extensions': [],\n", " 'title': '2020 Landsat 8 images over Philly',\n", " 'extent': {'spatial': {'bbox': [[-77.88298, 39.23073, -73.46322, 41.41025]]},\n", " 'temporal': {'interval': [['2020-01-03T15:46:15.625235Z',\n", - " '2020-08-30T15:46:11.765407Z']]}},\n", + " '2020-12-29T15:40:09.950514Z']]}},\n", " 'license': 'proprietary',\n", " 'providers': [{'name': 'USGS',\n", " 'roles': ['producer'],\n", @@ -2172,7 +2312,7 @@ " {'name': 'AWS', 'roles': ['host'], 'url': 'https://landsatonaws.com/'}]}" ] }, - "execution_count": 57, + "execution_count": 56, "metadata": {}, "output_type": "execute_result" } @@ -2192,7 +2332,7 @@ }, { "cell_type": "code", - "execution_count": 58, + "execution_count": 57, "metadata": {}, "outputs": [ { @@ -2202,9 +2342,9 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 13\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 14\u001b[0m \u001b[0;32mwith\u001b[0m \u001b[0mHTTPServer\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'localhost'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m5555\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mCORSRequestHandler\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0mhttpd\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 15\u001b[0;31m \u001b[0mhttpd\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mserve_forever\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;32m~/anaconda/lib/python3.6/socketserver.py\u001b[0m in \u001b[0;36mserve_forever\u001b[0;34m(self, poll_interval)\u001b[0m\n\u001b[1;32m 234\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 235\u001b[0m \u001b[0;32mwhile\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__shutdown_request\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 236\u001b[0;31m \u001b[0mready\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mselector\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mselect\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpoll_interval\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 237\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mready\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 238\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_handle_request_noblock\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/anaconda/lib/python3.6/selectors.py\u001b[0m in \u001b[0;36mselect\u001b[0;34m(self, timeout)\u001b[0m\n\u001b[1;32m 374\u001b[0m \u001b[0mready\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 375\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 376\u001b[0;31m \u001b[0mfd_event_list\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_poll\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpoll\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtimeout\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 377\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mInterruptedError\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 378\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mready\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/var/folders/td/xzlhhvqn6gn7_zmrjc0zfb6c0000gn/T/ipykernel_13162/2713200350.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 13\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 14\u001b[0m \u001b[0;32mwith\u001b[0m \u001b[0mHTTPServer\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'localhost'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m5555\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mCORSRequestHandler\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0mhttpd\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 15\u001b[0;31m \u001b[0mhttpd\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mserve_forever\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m~/.pyenv/versions/3.8.9/lib/python3.8/socketserver.py\u001b[0m in \u001b[0;36mserve_forever\u001b[0;34m(self, poll_interval)\u001b[0m\n\u001b[1;32m 230\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 231\u001b[0m \u001b[0;32mwhile\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__shutdown_request\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 232\u001b[0;31m \u001b[0mready\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mselector\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mselect\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpoll_interval\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 233\u001b[0m \u001b[0;31m# bpo-35017: shutdown() called during select(), exit immediately.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 234\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__shutdown_request\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/.pyenv/versions/3.8.9/lib/python3.8/selectors.py\u001b[0m in \u001b[0;36mselect\u001b[0;34m(self, timeout)\u001b[0m\n\u001b[1;32m 413\u001b[0m \u001b[0mready\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 414\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 415\u001b[0;31m \u001b[0mfd_event_list\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_selector\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpoll\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtimeout\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 416\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mInterruptedError\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 417\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mready\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mKeyboardInterrupt\u001b[0m: " ] } @@ -2216,7 +2356,7 @@ "os.chdir(root_path)\n", "\n", "class CORSRequestHandler(SimpleHTTPRequestHandler):\n", - " def end_headers(self):\n", + " def end_headers(self) -> None:\n", " self.send_header('Access-Control-Allow-Origin', '*')\n", " self.send_header('Access-Control-Allow-Methods', 'GET')\n", " self.send_header('Cache-Control', 'no-store, no-cache, must-revalidate')\n", @@ -2262,7 +2402,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.6.5" + "version": "3.8.9" } }, "nbformat": 4,