11"""
2+ Define the command line interface for openSAMPL.
3+
24The openSAMPL CLI package is a click based command line interface for the openSAMPL package. It provides a way to
35interact with the database and load data into it.
46"""
57
68import json
79import sys
810from pathlib import Path
9- from typing import Dict , List , Union
11+ from typing import Optional , Union
1012
1113import click
1214import yaml
1921from opensampl .load_data import create_new_tables , write_to_table
2022from opensampl .vendors .constants import VENDOR_MAP , get_vendor_parser
2123
22- BANNER = r"""
24+ BANNER = r"""
2325
2426 ____ _ __ __ ____ _
2527 ___ _ __ ___ _ __ / ___| / \ | \/ | _ \| |
3537level = ENV_VARS .LOG_LEVEL .get_value ()
3638logger .configure (handlers = [{"sink" : sys .stderr , "level" : level .upper ()}])
3739
40+
3841class CaseInsensitiveGroup (click .Group ):
3942 """Defines Click group options as case-insensitive. By default, click groups are case-sensitive."""
4043
41- def get_command (self , ctx , cmd_name ):
44+ def get_command (self , ctx , cmd_name : str ) -> Optional [ click . Command ]: # noqa: ARG002,ANN001
4245 """Normalize command name to lower case"""
4346 cmd_name = cmd_name .lower ()
4447 # Match against lowercased command names
@@ -47,6 +50,7 @@ def get_command(self, ctx, cmd_name):
4750 return cmd
4851 return None
4952
53+
5054def get_table_names ():
5155 """Get all table names from the ORM in opensampl.db.orm"""
5256 return [table .name for table in Base .metadata .sorted_tables ]
@@ -73,6 +77,7 @@ def init():
7377def config ():
7478 """View and manage environment variables used by openSAMPL"""
7579
80+
7681@config .command ()
7782def file ():
7883 """Show the path to the env file used by openSAMPL"""
@@ -123,7 +128,7 @@ def show(explain: bool, var: str):
123128@config .command ("set" )
124129@click .argument ("name" )
125130@click .argument ("value" )
126- def config_set (name : str , value : str , temp : bool = None ):
131+ def config_set (name : str , value : str , temp : Optional [ bool ] = None ):
127132 """
128133 Set the value of an environment variable.
129134
@@ -137,25 +142,25 @@ def config_set(name: str, value: str, temp: bool = None):
137142 """
138143 set_env (name = name , value = value , temp = temp )
139144
145+
140146@cli .group (cls = CaseInsensitiveGroup )
141147def load ():
142148 """Load data into database"""
143149
144150
145- for probe_name , vendor_type in VENDOR_MAP . items () :
151+ for probe_name in VENDOR_MAP :
146152 load .add_command (get_vendor_parser (probe_name ).get_cli_command (), name = probe_name )
147153
148154
149- def path_or_string (value ) :
155+ def path_or_string (value : str ) -> Union [ dict , list ] :
150156 """Get content from a file or use the string directly"""
151157 # Get content - either from file or use the string directly
152158 content = value
153159 try :
154160 path = Path (value )
155161 if path .exists () and path .is_file ():
156- with open (path , "r" ) as f :
157- content = f .read ()
158- except Exception :
162+ content = path .read_text ()
163+ except Exception : # noqa: S110
159164 # If any error occurs during path handling, treat as raw string
160165 pass
161166
@@ -169,8 +174,8 @@ def path_or_string(value):
169174 except json .JSONDecodeError as json_err :
170175 # If both parsing attempts fail, raise an error
171176 raise click .BadParameter (
172- f"Could not parse input as YAML or JSON.\n " f"YAML error: { yaml_err } \n " f"JSON error: { json_err } "
173- )
177+ f"Could not parse input as YAML or JSON.\n YAML error: { yaml_err } \n JSON error: { json_err } "
178+ ) from json_err
174179
175180
176181@load .command ("table" )
@@ -183,8 +188,10 @@ def path_or_string(value):
183188)
184189@click .argument ("table_name" , type = click .Choice (get_table_names ()))
185190@click .argument ("filepath" , type = path_or_string )
186- def table_load (filepath : Union [Dict , List ], table_name : str , if_exists : str ):
191+ def table_load (filepath : Union [dict , list ], table_name : str , if_exists : str ):
187192 r"""
193+ Perform a Table load into the database.
194+
188195 Load data directly into a database table. Format can be yaml or json. Can be a list of dictionaries or a single
189196 dictionary.
190197
@@ -208,8 +215,8 @@ def table_load(filepath: Union[Dict, List], table_name: str, if_exists: str):
208215 write_to_table (table_name , filepath , if_exists = if_exists )
209216 click .echo (f"Successfully wrote data to table { table_name } " )
210217 except Exception as e :
211- click .echo (f"Error writing to table: { str ( e ) } " , err = True )
212- raise click .Abort ()
218+ click .echo (f"Error writing to table: { e !s } " , err = True )
219+ raise click .Abort () # noqa: RSE102,B904
213220
214221
215222@cli .command (name = "create" )
@@ -221,10 +228,7 @@ def table_load(filepath: Union[Dict, List], table_name: str, if_exists: str):
221228 help = "Update the database with the new probe type" ,
222229)
223230def create_probe_command (config_path : Path , update_db : bool ):
224- """
225- ** beta **
226- Create a new probe type with scaffolding, based on a config file.
227- """
231+ """Create a new probe type with scaffolding, based on a config file."""
228232 from opensampl .helpers .create_vendor import VendorConfig
229233
230234 vendor_config = VendorConfig .from_config_file (config_path )
0 commit comments