33import importlib
44import sys
55import warnings
6- from types import ModuleType
6+ from pathlib import Path
77from typing import get_args
88
99import pystac
1010import requests
1111
12- from STACpopulator import __version__ , implementations
13- from STACpopulator .collection_update import UpdateModes , UpdateModesOptional , update_api_collection
12+ import STACpopulator .implementations
13+ from STACpopulator import __version__
14+ from STACpopulator .collection_update import UpdateModes , update_api_collection
1415from STACpopulator .exceptions import STACPopulatorError
1516from STACpopulator .export import export_catalog
1617from STACpopulator .log import add_logging_options , setup_logging
18+ from STACpopulator .populators import STACpopulatorBase
1719from STACpopulator .request_utils import add_request_options , apply_request_options
1820
1921
20- def _extra_parser_argument (arg : str ) -> tuple [str , str ]:
21- if "=" in arg :
22- return tuple (a .strip () for a in arg .split ("=" , 1 ))
23- raise argparse .ArgumentTypeError ("--extra-parser-arguments must be in the form 'key=value'" )
24-
25-
2622def add_parser_args (parser : argparse .ArgumentParser ) -> None :
2723 """Add parser arguments to the argument parser."""
2824 parser .add_argument (
@@ -48,52 +44,10 @@ def add_parser_args(parser: argparse.ArgumentParser) -> None:
4844 populators_subparser = run_parser .add_subparsers (
4945 title = "populator" , dest = "populator" , description = "Implementation to run."
5046 )
51- for implementation_module_name , module in implementation_modules ().items ():
52- implementation_parser = populators_subparser .add_parser (implementation_module_name )
53- module .add_parser_args (implementation_parser )
54- implementation_parser .add_argument (
55- "-x" ,
56- "--extra-item-parsers" ,
57- action = "append" ,
58- help = "Functions that may modify items before upload. "
59- "Should be specified in the form 'module:function_name' "
60- "and have the signature function(item: dict, **kw)" ,
61- )
62- implementation_parser .add_argument (
63- "-X" ,
64- "--extra-collection-parsers" ,
65- action = "append" ,
66- help = "Functions that may modify collections before upload. "
67- "Should be specified in the form 'module:function_name' or "
68- "path/to/python/file.py:function_name. Functions should "
69- "have the signature function(collection: dict, **kw) -> None "
70- "and should modify the collection dict in place." ,
71- )
72- implementation_parser .add_argument (
73- "-a" ,
74- "--extra-parser-arguments" ,
75- action = "append" ,
76- type = _extra_parser_argument ,
77- help = "Extra keyword arguments that should be passed to extra "
78- "item and collection function as "
79- "keyword arguments. "
80- "Should be specified in the form 'key=value'" ,
81- )
82- implementation_parser .add_argument (
83- "--update-collection-mode" ,
84- dest = "update_collection" ,
85- choices = get_args (UpdateModesOptional ),
86- default = "none" ,
87- help = "Update collection information based on new items created or updated by this populator. "
88- "Only applies if --update is also set." ,
89- )
90- implementation_parser .add_argument (
91- "--exclude-summary" ,
92- nargs = "*" ,
93- action = "extend" ,
94- default = [],
95- help = "Exclude these properties when updating collection summaries. " ,
96- )
47+ for name , populator in populators ().items ():
48+ implementation_parser = populators_subparser .add_parser (name )
49+ implementation_parser .description = getattr (populator , "description" , name )
50+ populator .update_parser_args (implementation_parser )
9751 update_parser = commands_subparser .add_parser (
9852 "update-collection" , description = "Update collection information based on items in the collection"
9953 )
@@ -123,21 +77,24 @@ def add_parser_args(parser: argparse.ArgumentParser) -> None:
12377
12478
12579@functools .cache
126- def implementation_modules () -> dict [str , ModuleType ]:
80+ def populators () -> dict [str , STACpopulatorBase ]:
12781 """
12882 Try to load implementations.
12983
13084 If one fails (i.e. due to missing dependencies) continue loading others.
13185 """
132- modules = {}
133- for implementation_module_name in implementations .__all__ :
134- try :
135- modules [implementation_module_name ] = importlib .import_module (
136- f".{ implementation_module_name } " , implementations .__package__
137- )
138- except STACPopulatorError as e :
139- warnings .warn (f"Could not load extension { implementation_module_name } because of error { e } " )
140- return modules
86+ impl_path = Path (STACpopulator .implementations .__path__ [0 ])
87+ for path in impl_path .glob ("**/*.py" ):
88+ if path .name == "__init__.py" :
89+ path = path .parent
90+ rel_path = path .relative_to (impl_path )
91+ if str (rel_path ) != "." :
92+ module_path = str (rel_path .with_suffix ("" )).replace ("/" , "." ).replace ("-" , "_" )
93+ try :
94+ importlib .import_module (f"STACpopulator.implementations.{ module_path } " )
95+ except STACPopulatorError as e :
96+ warnings .warn (f"Could not load extension { rel_path } because of error { e } " )
97+ return {getattr (klass , "name" , klass .__name__ ): klass for klass in STACpopulatorBase .concrete_subclasses ()}
14198
14299
143100def run (ns : argparse .Namespace ) -> int :
@@ -148,7 +105,7 @@ def run(ns: argparse.Namespace) -> int:
148105 if ns .command == "run" :
149106 if ns .stac_version :
150107 pystac .set_stac_version (ns .stac_version )
151- return implementation_modules ()[ns .populator ].runner (ns , session ) or 0
108+ return populators ()[ns .populator ].run (ns , session ) or 0
152109 elif ns .command == "update_collection" :
153110 return update_api_collection (ns .mode , ns .stac_collection_uri , ns .exclude_summary ) or 0
154111 else :
0 commit comments