From c30857da4af13ef001d6057344c5d96e3513e01a Mon Sep 17 00:00:00 2001 From: jonhealy1 Date: Sun, 27 Nov 2022 11:12:53 +0300 Subject: [PATCH 01/11] add --item_collection --- stac_check/cli.py | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/stac_check/cli.py b/stac_check/cli.py index 7a0b3ab..92dd8a3 100644 --- a/stac_check/cli.py +++ b/stac_check/cli.py @@ -10,6 +10,16 @@ def link_asset_message(link_list:list, type: str, format: str): else: click.secho(f"No {type.upper()} {format} errors!", fg="green") +def api_collection(linter): + # print("item collection") + data = linter.data + # print(data) + if data["type"] == "FeatureCollection": + for item in data["items"]: + print(item) + else: + click.secho("The response is not a proper item collection.", fg="red") + def recursive_message(linter): click.secho() click.secho(f"Recursive: Validate all assets in a collection or catalog", bold=True) @@ -117,7 +127,13 @@ def cli_message(linter): "--recursive", "-r", is_flag=True, - help="Recursively validate all related stac objects.", + help="Recursively lint and validate all related stac objects.", +) +@click.option( + "--item_collection", + "-i", + is_flag=True, + help="Lint and validate a stac api item collection response.", ) @click.option( "--max-depth", @@ -134,10 +150,19 @@ def cli_message(linter): @click.command() @click.argument('file') @click.version_option(version=pkg_resources.require("stac-check")[0].version) -def main(file, recursive, max_depth, assets, links): - linter = Linter(file, assets=assets, links=links, recursive=recursive, max_depth=max_depth) +def main(file, recursive, item_collection, max_depth, assets, links): + linter = Linter( + item=file, + assets=assets, + links=links, + recursive=recursive, + item_collection=item_collection, + max_depth=max_depth + ) intro_message(linter) if recursive > 0: recursive_message(linter) + elif item_collection > 0: + api_collection(linter) else: cli_message(linter) \ No newline at end of file From d9d3cb4e940b1a06b7cddec94b7a578608ffdddf Mon Sep 17 00:00:00 2001 From: jonhealy1 Date: Sun, 27 Nov 2022 11:22:35 +0300 Subject: [PATCH 02/11] create item collection --- sample_files/1.0.0/item_collection.json | 234 ++++++++++++++++++++++++ 1 file changed, 234 insertions(+) create mode 100644 sample_files/1.0.0/item_collection.json diff --git a/sample_files/1.0.0/item_collection.json b/sample_files/1.0.0/item_collection.json new file mode 100644 index 0000000..9d6d9dd --- /dev/null +++ b/sample_files/1.0.0/item_collection.json @@ -0,0 +1,234 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "stac_version": "1.0.0", + "stac_extensions": [], + "type": "Feature", + "id": "20201211_223832_CS2_A", + "bbox": [ + 172.91173669923782, + 1.3438851951615003, + 172.95469614953714, + 1.3690476620161975 + ], + "geometry": { + "type": "Polygon", + "coordinates": [[ + [172.91173669923782, 1.3438851951615003], + [172.95469614953714, 1.3438851951615003], + [172.95469614953714, 1.3690476620161975], + [172.91173669923782, 1.3690476620161975], + [172.91173669923782, 1.3438851951615003] + ]] + }, + "properties": { + "title": "Core Item", + "description": "A sample STAC Item that includes examples of all common metadata", + "datetime": null, + "start_datetime": "2020-12-11T22:38:32.125Z", + "end_datetime": "2020-12-11T22:38:32.327Z", + "created": "2020-12-12T01:48:13.725Z", + "updated": "2020-12-12T01:48:13.725Z", + "platform": "cool_sat1", + "instruments": [ + "cool_sensor_v1" + ], + "constellation": "ion", + "mission": "collection 5624", + "gsd": 0.512 + }, + "collection": "simple-collection", + "links": [ + { + "rel": "collection", + "href": "./collection.json", + "type": "application/json", + "title": "Simple Example Collection" + }, + { + "rel": "root", + "href": "./collection.json", + "type": "application/json", + "title": "Simple Example Collection" + }, + { + "rel": "parent", + "href": "./collection.json", + "type": "application/json", + "title": "Simple Example Collection" + }, + { + "rel": "alternate", + "type": "text/html", + "href": "http://remotedata.io/catalog/20201211_223832_CS2/index.html", + "title": "HTML version of this STAC Item" + } + ], + "assets": { + "analytic": { + "href": "https://storage.googleapis.com/open-cogs/stac-examples/20201211_223832_CS2_analytic.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "4-Band Analytic", + "roles": [ + "data" + ] + }, + "thumbnail": { + "href": "https://storage.googleapis.com/open-cogs/stac-examples/20201211_223832_CS2.jpg", + "title": "Thumbnail", + "type": "image/png", + "roles": [ + "thumbnail" + ] + }, + "visual": { + "href": "https://storage.googleapis.com/open-cogs/stac-examples/20201211_223832_CS2.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "3-Band Visual", + "roles": [ + "visual" + ] + }, + "udm": { + "href": "https://storage.googleapis.com/open-cogs/stac-examples/20201211_223832_CS2_analytic_udm.tif", + "title": "Unusable Data Mask", + "type": "image/tiff; application=geotiff;" + }, + "json-metadata": { + "href": "http://remotedata.io/catalog/20201211_223832_CS2/extended-metadata.json", + "title": "Extended Metadata", + "type": "application/json", + "roles": [ + "metadata" + ] + }, + "ephemeris": { + "href": "http://cool-sat.com/catalog/20201211_223832_CS2/20201211_223832_CS2.EPH", + "title": "Satellite Ephemeris Metadata" + } + } + }, + { + "stac_version": "1.0.0", + "stac_extensions": [], + "type": "Feature", + "id": "20201211_223832_CS2_B", + "bbox": [ + 172.91173669923782, + 1.3438851951615003, + 172.95469614953714, + 1.3690476620161975 + ], + "geometry": { + "type": "Polygon", + "coordinates": [[ + [172.91173669923782, 1.3438851951615003], + [172.95469614953714, 1.3438851951615003], + [172.95469614953714, 1.3690476620161975], + [172.91173669923782, 1.3690476620161975], + [172.91173669923782, 1.3438851951615003] + ]] + }, + "properties": { + "title": "Core Item", + "description": "A sample STAC Item that includes examples of all common metadata", + "datetime": null, + "start_datetime": "2020-12-11T22:38:32.125Z", + "end_datetime": "2020-12-11T22:38:32.327Z", + "created": "2020-12-12T01:48:13.725Z", + "updated": "2020-12-12T01:48:13.725Z", + "platform": "cool_sat1", + "instruments": [ + "cool_sensor_v1" + ], + "constellation": "ion", + "mission": "collection 5624", + "gsd": 0.512 + }, + "collection": "simple-collection", + "links": [ + { + "rel": "collection", + "href": "./collection.json", + "type": "application/json", + "title": "Simple Example Collection" + }, + { + "rel": "root", + "href": "./collection.json", + "type": "application/json", + "title": "Simple Example Collection" + }, + { + "rel": "parent", + "href": "./collection.json", + "type": "application/json", + "title": "Simple Example Collection" + }, + { + "rel": "alternate", + "type": "text/html", + "href": "http://remotedata.io/catalog/20201211_223832_CS2/index.html", + "title": "HTML version of this STAC Item" + } + ], + "assets": { + "analytic": { + "href": "https://storage.googleapis.com/open-cogs/stac-examples/20201211_223832_CS2_analytic.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "4-Band Analytic", + "roles": [ + "data" + ] + }, + "thumbnail": { + "href": "https://storage.googleapis.com/open-cogs/stac-examples/20201211_223832_CS2.jpg", + "title": "Thumbnail", + "type": "image/png", + "roles": [ + "thumbnail" + ] + }, + "visual": { + "href": "https://storage.googleapis.com/open-cogs/stac-examples/20201211_223832_CS2.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "3-Band Visual", + "roles": [ + "visual" + ] + }, + "udm": { + "href": "https://storage.googleapis.com/open-cogs/stac-examples/20201211_223832_CS2_analytic_udm.tif", + "title": "Unusable Data Mask", + "type": "image/tiff; application=geotiff;" + }, + "json-metadata": { + "href": "http://remotedata.io/catalog/20201211_223832_CS2/extended-metadata.json", + "title": "Extended Metadata", + "type": "application/json", + "roles": [ + "metadata" + ] + }, + "ephemeris": { + "href": "http://cool-sat.com/catalog/20201211_223832_CS2/20201211_223832_CS2.EPH", + "title": "Satellite Ephemeris Metadata" + } + } + } + ], + "links": [ + { + "rel": "next", + "href": "https://stac-api.example.com/search?page=3", + "type": "application/geo+json" + + }, + { + "rel": "prev", + "href": "https://stac-api.example.com/search?page=1", + "type": "application/geo+json" + } + ] +} From ee12d5712863521a2595a3b3478e2144f5347c8d Mon Sep 17 00:00:00 2001 From: jonhealy1 Date: Sun, 27 Nov 2022 11:35:10 +0300 Subject: [PATCH 03/11] add item collection to init --- stac_check/lint.py | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/stac_check/lint.py b/stac_check/lint.py index cd273e5..1a2b0ee 100644 --- a/stac_check/lint.py +++ b/stac_check/lint.py @@ -19,6 +19,7 @@ class Linter: assets: bool = False links: bool = False recursive: bool = False + item_collection: bool = False max_depth: Optional[int] = None def __post_init__(self): @@ -38,7 +39,7 @@ def __post_init__(self): self.invalid_link_request = self.check_links_assets(10, "links", "request") if self.links else None self.schema = self.message["schema"] if "schema" in self.message else [] self.object_id = self.data["id"] if "id" in self.data else "" - self.file_name = os.path.basename(self.item).split('.')[0] + self.file_name = self.get_asset_name(self.data) self.best_practices_msg = self.create_best_practices_msg() @staticmethod @@ -57,14 +58,24 @@ def parse_config(config_file): return default_config + def get_asset_name(self, file): + if self.item_collection is False: + if isinstance(file, str): + return os.path.basename(file).split('.')[0] + else: + return file["id"] + def load_data(self, file): - if is_valid_url(file): - resp = requests.get(file) - data = resp.json() + if isinstance(file, str): + if is_valid_url(file): + resp = requests.get(file) + data = resp.json() + else: + with open(file) as json_file: + data = json.load(json_file) + return data else: - with open(file) as json_file: - data = json.load(json_file) - return data + return file def validate_file(self, file): stac = StacValidate(file, links=self.links, assets=self.assets) From 1b298fdba4d5673eecd60689560fdb9e8ca5e06c Mon Sep 17 00:00:00 2001 From: jonhealy1 Date: Sun, 27 Nov 2022 11:35:39 +0300 Subject: [PATCH 04/11] traverse features --- stac_check/cli.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/stac_check/cli.py b/stac_check/cli.py index 92dd8a3..48b96af 100644 --- a/stac_check/cli.py +++ b/stac_check/cli.py @@ -15,8 +15,9 @@ def api_collection(linter): data = linter.data # print(data) if data["type"] == "FeatureCollection": - for item in data["items"]: - print(item) + for item in data["features"]: + lint = Linter(item=item) + print(lint.message) else: click.secho("The response is not a proper item collection.", fg="red") From 3c2ced2699da359a9de378259d35ff6cca4c7b1c Mon Sep 17 00:00:00 2001 From: jonhealy1 Date: Sun, 27 Nov 2022 16:06:01 +0300 Subject: [PATCH 05/11] validate --- stac_check/lint.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/stac_check/lint.py b/stac_check/lint.py index 1a2b0ee..6565202 100644 --- a/stac_check/lint.py +++ b/stac_check/lint.py @@ -6,7 +6,7 @@ import os from dataclasses import dataclass import requests -from typing import Optional +from typing import Optional, Union from dotenv import load_dotenv import pkg_resources @@ -14,7 +14,7 @@ @dataclass class Linter: - item: str + item: Union[str,dict] config_file: Optional[str] = None assets: bool = False links: bool = False @@ -78,8 +78,12 @@ def load_data(self, file): return file def validate_file(self, file): - stac = StacValidate(file, links=self.links, assets=self.assets) - stac.run() + if isinstance(file, str): + stac = StacValidate(file, links=self.links, assets=self.assets) + stac.run() + else: + stac = StacValidate() + stac.validate_dict(file) return stac.message[0] def recursive_validation(self, file): From 550468e5f1ba6f43bb93991d7f49bee7209e25cb Mon Sep 17 00:00:00 2001 From: jonhealy1 Date: Sun, 27 Nov 2022 16:35:30 +0300 Subject: [PATCH 06/11] create cli output --- stac_check/cli.py | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/stac_check/cli.py b/stac_check/cli.py index 48b96af..a8c10a5 100644 --- a/stac_check/cli.py +++ b/stac_check/cli.py @@ -11,15 +11,25 @@ def link_asset_message(link_list:list, type: str, format: str): click.secho(f"No {type.upper()} {format} errors!", fg="green") def api_collection(linter): - # print("item collection") + counter = 0 data = linter.data - # print(data) if data["type"] == "FeatureCollection": for item in data["features"]: lint = Linter(item=item) - print(lint.message) + cli_message(lint) + if lint.version == "1.0.0": + click.secho(lint.set_update_message(), fg='green') + else: + click.secho(lint.set_update_message(), fg='red') + click.secho() + counter = counter + 1 + click.secho("----------------------------------") + click.secho(f"item collection: {counter} items analyzed!", fg="blue", bold=True) + click.secho("----------------------------------") else: + click.secho("-------------------------") click.secho("The response is not a proper item collection.", fg="red") + click.secho("-------------------------") def recursive_message(linter): click.secho() @@ -41,7 +51,7 @@ def recursive_message(linter): click.secho(f"Error Message: {msg['error_message']}", fg='red') click.secho("-------------------------") -def intro_message(linter): +def intro_message(linter, skip_version): click.secho(""" ____ ____ __ ___ ___ _ _ ____ ___ __ _ / ___)(_ _)/ _\ / __)___ / __)/ )( \( __)/ __)( / ) @@ -53,10 +63,11 @@ def intro_message(linter): click.secho() - if linter.version == "1.0.0": - click.secho(linter.set_update_message(), fg='green') - else: - click.secho(linter.set_update_message(), fg='red') + if not skip_version: + if linter.version == "1.0.0": + click.secho(linter.set_update_message(), fg='green') + else: + click.secho(linter.set_update_message(), fg='red') click.secho() @@ -65,6 +76,8 @@ def intro_message(linter): click.secho() def cli_message(linter): + click.secho(f"------------ ID: {linter.object_id} ------------", bold=True) + click.secho() ''' valid stac object message - true or false ''' if linter.valid_stac == True: click.secho(f"Valid {linter.asset_type}: {linter.valid_stac}", fg='green') @@ -160,7 +173,7 @@ def main(file, recursive, item_collection, max_depth, assets, links): item_collection=item_collection, max_depth=max_depth ) - intro_message(linter) + intro_message(linter, skip_version=item_collection) if recursive > 0: recursive_message(linter) elif item_collection > 0: From 989decdf004de42cb2c925f7be73bf36157ee69b Mon Sep 17 00:00:00 2001 From: jonhealy1 Date: Sun, 27 Nov 2022 18:48:29 +0300 Subject: [PATCH 07/11] update readme --- README.md | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index a5f7d5d..3a07ad5 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,8 @@ Options: -m, --max-depth INTEGER Maximum depth to traverse when recursing. Omit this argument to get full recursion. Ignored if `recursive == False`. + -i, --item_collection Lint and validate a stac api item collection + response. -r, --recursive Recursively validate all related stac objects. --help Show this message and exit. Show this message and exit. ``` @@ -34,9 +36,15 @@ $ make build $ make shell ``` --- -### Examples +### Item Collection Example + +``` +$ stac-check https://earth-search.aws.element84.com/v0/collections/sentinel-s2-l2a/items --item_collection +``` +--- +### CLI Example Output -``` stac-check https://raw.githubusercontent.com/stac-utils/pystac/main/tests/data-files/examples/0.9.0/collection-spec/examples/landsat-collection.json --recursive ``` +``` $ stac-check https://raw.githubusercontent.com/stac-utils/pystac/main/tests/data-files/examples/0.9.0/collection-spec/examples/landsat-collection.json --recursive ``` ``` ____ ____ __ ___ ___ _ _ ____ ___ __ _ / ___)(_ _)/ _\ / __)___ / __)/ )( \( __)/ __)( / ) @@ -81,7 +89,7 @@ Error Message: Expecting value: line 1 column 1 (char 0) ------------------------- ``` -``` stac-check sample_files/0.9.0/landsat8-sample.json``` +``` $ stac-check sample_files/0.9.0/landsat8-sample.json```
stac-check: STAC spec validaton and linting tool
 
@@ -144,7 +152,7 @@ This object has 4 links
 
 
    
-``` stac-check sample_files/1.0.0/core-item-bad-links.json --links --assets```    
+``` $ stac-check sample_files/1.0.0/core-item-bad-links.json --links --assets```    
 
 stac-check: STAC spec validaton and linting tool
 
@@ -186,7 +194,7 @@ LINK request errors:
 This object has 4 links
 
-``` stac-check sample_files/0.9.0/bad-item.json``` +``` $ stac-check sample_files/0.9.0/bad-item.json```
 stac-check: STAC spec validaton and linting tool
 

From 51c9bd9c2844c47ec91b363e9282c6f51db9f5c8 Mon Sep 17 00:00:00 2001
From: jonhealy1 
Date: Sun, 27 Nov 2022 23:04:52 +0300
Subject: [PATCH 08/11] revert linter

---
 stac_check/lint.py | 21 ++++++++++++---------
 1 file changed, 12 insertions(+), 9 deletions(-)

diff --git a/stac_check/lint.py b/stac_check/lint.py
index 6565202..1691bf8 100644
--- a/stac_check/lint.py
+++ b/stac_check/lint.py
@@ -14,7 +14,7 @@
 
 @dataclass
 class Linter:
-    item: Union[str,dict]
+    item: Union[str, dict] # url, file name, or dictionary
     config_file: Optional[str] = None
     assets: bool = False
     links: bool = False
@@ -39,7 +39,7 @@ def __post_init__(self):
         self.invalid_link_request = self.check_links_assets(10, "links", "request") if self.links else None
         self.schema = self.message["schema"] if "schema" in self.message else []
         self.object_id = self.data["id"] if "id" in self.data else ""
-        self.file_name = self.get_asset_name(self.data)
+        self.file_name = self.get_asset_name(self.item)
         self.best_practices_msg = self.create_best_practices_msg()
 
     @staticmethod
@@ -59,11 +59,10 @@ def parse_config(config_file):
         return default_config
 
     def get_asset_name(self, file):
-        if self.item_collection is False:
-            if isinstance(file, str):
-                return os.path.basename(file).split('.')[0]
-            else:
-                return file["id"]
+        if isinstance(file, str):
+            return os.path.basename(file).split('.')[0]
+        else:
+            return file["id"]
 
     def load_data(self, file):
         if isinstance(file, str):
@@ -88,8 +87,12 @@ def validate_file(self, file):
 
     def recursive_validation(self, file):
         if self.recursive:
-            stac = StacValidate(file, recursive=True, max_depth=self.max_depth)
-            stac.run()
+            if isinstance(file, str):
+                stac = StacValidate(file, recursive=True, max_depth=self.max_depth)
+                stac.run()
+            else:
+                stac = StacValidate(recursive=True, max_depth=self.max_depth)
+                stac.validate_dict(file)
             return stac.message
 
     def set_update_message(self):

From 643fe584c7278f2eab0bd1531c452cf63cde271c Mon Sep 17 00:00:00 2001
From: jonhealy1 
Date: Tue, 14 Feb 2023 18:52:40 +0300
Subject: [PATCH 09/11] create examples folder

---
 examples/lint_dict.py | 141 ++++++++++++++++++++++++++++++++++++++++++
 test_dict.py          | 141 ------------------------------------------
 2 files changed, 141 insertions(+), 141 deletions(-)
 create mode 100644 examples/lint_dict.py
 delete mode 100644 test_dict.py

diff --git a/examples/lint_dict.py b/examples/lint_dict.py
new file mode 100644
index 0000000..35d2603
--- /dev/null
+++ b/examples/lint_dict.py
@@ -0,0 +1,141 @@
+from stac_check.lint import Linter
+
+file = {
+    "stac_version": "1.0.0",
+    "stac_extensions": [],
+    "type": "Feature",
+    "id": "20201211_223832_CS2",
+    "bbox": [
+        172.91173669923782,
+        1.3438851951615003,
+        172.95469614953714,
+        1.3690476620161975
+    ],
+    "geometry": {
+        "type": "Polygon",
+        "coordinates": [
+        [
+            [
+            172.91173669923782,
+            1.3438851951615003
+            ],
+            [
+            172.95469614953714,
+            1.3438851951615003
+            ],
+            [
+            172.95469614953714,
+            1.3690476620161975
+            ],
+            [
+            172.91173669923782,
+            1.3690476620161975
+            ],
+            [
+            172.91173669923782,
+            1.3438851951615003
+            ]
+        ]
+        ]
+    },
+    "properties": {
+        "title": "Core Item",
+        "description": "A sample STAC Item that includes examples of all common metadata",
+        "datetime": None,
+        "start_datetime": "2020-12-11T22:38:32.125Z",
+        "end_datetime": "2020-12-11T22:38:32.327Z",
+        "created": "2020-12-12T01:48:13.725Z",
+        "updated": "2020-12-12T01:48:13.725Z",
+        "platform": "cool_sat1",
+        "instruments": [
+        "cool_sensor_v1"
+        ],
+        "constellation": "ion",
+        "mission": "collection 5624",
+        "gsd": 0.512
+    },
+    "collection": "simple-collection",
+    "links": [
+        {
+        "rel": "collection",
+        "href": "./collection.json",
+        "type": "application/json",
+        "title": "Simple Example Collection"
+        },
+        {
+        "rel": "root",
+        "href": "./collection.json",
+        "type": "application/json",
+        "title": "Simple Example Collection"
+        },
+        {
+        "rel": "parent",
+        "href": "./collection.json",
+        "type": "application/json",
+        "title": "Simple Example Collection"
+        },
+        {
+        "rel": "alternate",
+        "type": "text/html",
+        "href": "http://remotedata.io/catalog/20201211_223832_CS2/index.html",
+        "title": "HTML version of this STAC Item"
+        }
+    ],
+    "assets": {
+        "analytic": {
+        "href": "https://storage.googleapis.com/open-cogs/stac-examples/20201211_223832_CS2_analytic.tif",
+        "type": "image/tiff; application=geotiff; profile=cloud-optimized",
+        "title": "4-Band Analytic",
+        "roles": [
+            "data"
+        ]
+        },
+        "thumbnail": {
+        "href": "https://storage.googleapis.com/open-cogs/stac-examples/20201211_223832_CS2.jpg",
+        "title": "Thumbnail",
+        "type": "image/png",
+        "roles": [
+            "thumbnail"
+        ]
+        },
+        "visual": {
+        "href": "https://storage.googleapis.com/open-cogs/stac-examples/20201211_223832_CS2.tif",
+        "type": "image/tiff; application=geotiff; profile=cloud-optimized",
+        "title": "3-Band Visual",
+        "roles": [
+            "visual"
+        ]
+        },
+        "udm": {
+        "href": "https://storage.googleapis.com/open-cogs/stac-examples/20201211_223832_CS2_analytic_udm.tif",
+        "title": "Unusable Data Mask",
+        "type": "image/tiff; application=geotiff;"
+        },
+        "json-metadata": {
+        "href": "http://remotedata.io/catalog/20201211_223832_CS2/extended-metadata.json",
+        "title": "Extended Metadata",
+        "type": "application/json",
+        "roles": [
+            "metadata"
+        ]
+        },
+        "ephemeris": {
+        "href": "http://cool-sat.com/catalog/20201211_223832_CS2/20201211_223832_CS2.EPH",
+        "title": "Satellite Ephemeris Metadata"
+        }
+    }
+}
+linter = Linter(file, assets=True)
+
+print(linter.valid_stac)
+
+print(linter.error_type)
+
+print(linter.error_msg)
+
+for k,v in linter.create_best_practices_dict().items():
+    print(k,":",v)
+
+print(linter.schema)
+
+print(linter.file_name)
\ No newline at end of file
diff --git a/test_dict.py b/test_dict.py
deleted file mode 100644
index 900a855..0000000
--- a/test_dict.py
+++ /dev/null
@@ -1,141 +0,0 @@
-# from stac_check.lint import Linter
-
-# file = {
-#     "stac_version": "1.0.0",
-#     "stac_extensions": [],
-#     "type": "Feature",
-#     "id": "20201211_223832_CS2",
-#     "bbox": [
-#         172.91173669923782,
-#         1.3438851951615003,
-#         172.95469614953714,
-#         1.3690476620161975
-#     ],
-#     "geometry": {
-#         "type": "Polygon",
-#         "coordinates": [
-#         [
-#             [
-#             172.91173669923782,
-#             1.3438851951615003
-#             ],
-#             [
-#             172.95469614953714,
-#             1.3438851951615003
-#             ],
-#             [
-#             172.95469614953714,
-#             1.3690476620161975
-#             ],
-#             [
-#             172.91173669923782,
-#             1.3690476620161975
-#             ],
-#             [
-#             172.91173669923782,
-#             1.3438851951615003
-#             ]
-#         ]
-#         ]
-#     },
-#     "properties": {
-#         "title": "Core Item",
-#         "description": "A sample STAC Item that includes examples of all common metadata",
-#         "datetime": None,
-#         "start_datetime": "2020-12-11T22:38:32.125Z",
-#         "end_datetime": "2020-12-11T22:38:32.327Z",
-#         "created": "2020-12-12T01:48:13.725Z",
-#         "updated": "2020-12-12T01:48:13.725Z",
-#         "platform": "cool_sat1",
-#         "instruments": [
-#         "cool_sensor_v1"
-#         ],
-#         "constellation": "ion",
-#         "mission": "collection 5624",
-#         "gsd": 0.512
-#     },
-#     "collection": "simple-collection",
-#     "links": [
-#         {
-#         "rel": "collection",
-#         "href": "./collection.json",
-#         "type": "application/json",
-#         "title": "Simple Example Collection"
-#         },
-#         {
-#         "rel": "root",
-#         "href": "./collection.json",
-#         "type": "application/json",
-#         "title": "Simple Example Collection"
-#         },
-#         {
-#         "rel": "parent",
-#         "href": "./collection.json",
-#         "type": "application/json",
-#         "title": "Simple Example Collection"
-#         },
-#         {
-#         "rel": "alternate",
-#         "type": "text/html",
-#         "href": "http://remotedata.io/catalog/20201211_223832_CS2/index.html",
-#         "title": "HTML version of this STAC Item"
-#         }
-#     ],
-#     "assets": {
-#         "analytic": {
-#         "href": "https://storage.googleapis.com/open-cogs/stac-examples/20201211_223832_CS2_analytic.tif",
-#         "type": "image/tiff; application=geotiff; profile=cloud-optimized",
-#         "title": "4-Band Analytic",
-#         "roles": [
-#             "data"
-#         ]
-#         },
-#         "thumbnail": {
-#         "href": "https://storage.googleapis.com/open-cogs/stac-examples/20201211_223832_CS2.jpg",
-#         "title": "Thumbnail",
-#         "type": "image/png",
-#         "roles": [
-#             "thumbnail"
-#         ]
-#         },
-#         "visual": {
-#         "href": "https://storage.googleapis.com/open-cogs/stac-examples/20201211_223832_CS2.tif",
-#         "type": "image/tiff; application=geotiff; profile=cloud-optimized",
-#         "title": "3-Band Visual",
-#         "roles": [
-#             "visual"
-#         ]
-#         },
-#         "udm": {
-#         "href": "https://storage.googleapis.com/open-cogs/stac-examples/20201211_223832_CS2_analytic_udm.tif",
-#         "title": "Unusable Data Mask",
-#         "type": "image/tiff; application=geotiff;"
-#         },
-#         "json-metadata": {
-#         "href": "http://remotedata.io/catalog/20201211_223832_CS2/extended-metadata.json",
-#         "title": "Extended Metadata",
-#         "type": "application/json",
-#         "roles": [
-#             "metadata"
-#         ]
-#         },
-#         "ephemeris": {
-#         "href": "http://cool-sat.com/catalog/20201211_223832_CS2/20201211_223832_CS2.EPH",
-#         "title": "Satellite Ephemeris Metadata"
-#         }
-#     }
-# }
-# linter = Linter(file, assets=True)
-
-# print(linter.valid_stac)
-
-# print(linter.error_type)
-
-# print(linter.error_msg)
-
-# for k,v in linter.create_best_practices_dict().items():
-#     print(k,":",v)
-
-# print(linter.schema)
-
-# print(linter.file_name)
\ No newline at end of file

From bad6873f73d46b0fd35ea3dee49c944f29479550 Mon Sep 17 00:00:00 2001
From: jonhealy1 
Date: Tue, 14 Feb 2023 18:53:26 +0300
Subject: [PATCH 10/11] add dict example to readme

---
 README.md | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/README.md b/README.md
index ac5c6c3..2e25cb7 100644
--- a/README.md
+++ b/README.md
@@ -49,6 +49,23 @@ from stac_check.lint import Linter
 
 linter = Linter('')
 
+for k, v in linter.create_best_practices_dict().items():
+    print(k, ":", v)
+```
+---
+### Lint in-memory dictionary
+
+```
+from stac_check.lint import Linter
+
+stac_item = {
+    "stac_version": "1.0.0",
+    "stac_extensions": [],
+    "type": "Feature",
+}
+
+linter = Linter(stac_item, assets=True)
+
 for k, v in linter.create_best_practices_dict().items():
     print(k, ":", v)
 ```

From cc329f2fd9f82abe41c78965d2761346991328c3 Mon Sep 17 00:00:00 2001
From: jonhealy1 
Date: Tue, 14 Feb 2023 19:02:05 +0300
Subject: [PATCH 11/11] use f string

---
 examples/lint_dict.py | 16 ++++++----------
 1 file changed, 6 insertions(+), 10 deletions(-)

diff --git a/examples/lint_dict.py b/examples/lint_dict.py
index 35d2603..d28ca00 100644
--- a/examples/lint_dict.py
+++ b/examples/lint_dict.py
@@ -127,15 +127,11 @@
 }
 linter = Linter(file, assets=True)
 
-print(linter.valid_stac)
-
-print(linter.error_type)
-
-print(linter.error_msg)
-
+print(f"valid: {linter.valid_stac}")
+print(f"error_type: {linter.error_type}")
+print(f"error_msg: {linter.error_msg}")
+print(f"schema: {linter.schema}")
+print(f"file_name: {linter.file_name}")
+print("------")
 for k,v in linter.create_best_practices_dict().items():
     print(k,":",v)
-
-print(linter.schema)
-
-print(linter.file_name)
\ No newline at end of file