From 1b3b7b482bf4c5d96f90b2e0a4756eb817a33bfb Mon Sep 17 00:00:00 2001 From: eeintech Date: Wed, 21 Jul 2021 15:51:15 -0400 Subject: [PATCH 1/2] Started proof of concept for wrapper class and CLI --- config_template.yaml | 4 ++ inventree_cli.py | 132 +++++++++++++++++++++++++++++++++++++++++++ requirements.txt | 4 +- setup.py | 12 +++- tasks.py | 2 +- 5 files changed, 150 insertions(+), 4 deletions(-) create mode 100644 config_template.yaml create mode 100644 inventree_cli.py diff --git a/config_template.yaml b/config_template.yaml new file mode 100644 index 00000000..93250a18 --- /dev/null +++ b/config_template.yaml @@ -0,0 +1,4 @@ +# Fill out API credentials below +server: +username: +password: \ No newline at end of file diff --git a/inventree_cli.py b/inventree_cli.py new file mode 100644 index 00000000..f083809c --- /dev/null +++ b/inventree_cli.py @@ -0,0 +1,132 @@ +import click +import yaml + +from inventree.api import InvenTreeAPI +from inventree.part import Part + + +def load_file(file_path: str): + ''' Safe load YAML file ''' + + try: + with open(file_path, 'r') as file: + try: + data = yaml.safe_load(file) + except yaml.YAMLError as exc: + print(exc) + return None + except FileNotFoundError: + return None + + return data + + +class InvenTreeCLI: + """ InvenTree CLI Class """ + + operations = { + 'part': ['get', 'create', 'update', 'delete'], + } + + def __init__(self, config_file): + self.api = None + + # Extract configuration data from file + config_data = load_file(config_file) + server = config_data.get('server', None) + username = config_data.get('username', None) + password = config_data.get('password', None) + + if server and username and password: + print('Connecting... ', end='') + try: + self.api = InvenTreeAPI(server, username=username, password=password) + except ConnectionRefusedError: + print('Error: check server configuration!') + return + + if self.api.token: + print('Connected.') + else: + print('Error: Token does not exist!') + + def check_operation(self, table, operation): + if not operation: + return False + + operations = self.list_operations(table) + if operation.upper() in operations: + return True + + return False + + def list_operations(self, table): + return [operation.upper() for operation in self.operations.get(table, [])] + + def part(self, _function, category=None, id=None, name=None, description=None, revision=None, type=None): + if _function.lower() == 'get': + if not name and not id: + print('Error: Missing part name or ID!') + else: + part = None + + # Check with ID + if id: + part_by_id = Part(self.api, pk=id) + if part_by_id.pk: + part = part_by_id + else: + # Download all parts from database + db_parts = Part.list(self.api) + + for db_part in db_parts: + if db_part.name == name: + part = db_part + break + + if part: + print(f'{part.IPN} | {part.name} | {part.revision}') + else: + if id: + print(f'Error: Part with {id=} does not exist!') + else: + print(f'Error: Part with {name=} does not exist!') + + +@click.command() +@click.option('--config', required=True, help='Configuration File') +@click.argument('table', required=False) +@click.option('--op', required=False) +@click.option('--list', required=False, is_flag=True) +@click.option('--id', required=False) +@click.option('--name', required=False) +def main(config, table, op, list, id, name): + if config: + inventree_api = InvenTreeCLI(config) + + if inventree_api.api: + if table: + if list: + print(f'[TABLE] {table.upper()} : ', end='') + print(inventree_api.list_operations(table)) + exit(0) + + if op: + print(f'[TABLE/OP] {table.upper()}', end='') + if list: + print(inventree_api.list_operations(table)) + + if inventree_api.check_operation(table, op): + print(f' : {op.upper()}') + if table == 'part': + inventree_api.part(_function=op, id=id, name=name) + else: + print(f' - Operation "{op}" not allowed!') + else: + print('Missing operation!') + else: + return + + +if __name__ == '__main__': + main() diff --git a/requirements.txt b/requirements.txt index f79875f8..c58f02ca 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,5 @@ -requests==2.21.0 # Python HTTP for humans +Click>=8.0.1 # Command-Line Parser flake8==3.8.4 # PEP checking +pyyaml>=5.4.1 # YAML package +requests==2.21.0 # Python HTTP for humans wheel>=0.34.2 # Building package \ No newline at end of file diff --git a/setup.py b/setup.py index 9ecc268e..89361a9d 100644 --- a/setup.py +++ b/setup.py @@ -32,12 +32,20 @@ packages=setuptools.find_packages(), install_requires=[ - "requests" + "Click", + "pyyaml", + "requests", ], setup_requires=[ "wheel", ], - python_requires=">=3.6" + python_requires=">=3.6", + + entry_points={ + 'console_scripts': [ + 'inventree = inventree_cli:main', + ], + }, ) diff --git a/tasks.py b/tasks.py index 646261ca..73bd0dd2 100644 --- a/tasks.py +++ b/tasks.py @@ -15,7 +15,7 @@ def style(c): """ print("Running PEP code style checks...") - c.run('flake8 .') + c.run('flake8 inventree_cli.py inventree/ scripts/ test/') @task From b6399910ed59e11d776f6ead67f371ebfb6b1b5b Mon Sep 17 00:00:00 2001 From: eeintech Date: Wed, 21 Jul 2021 16:21:03 -0400 Subject: [PATCH 2/2] Fixed some issues and moved most printing out of class --- inventree_cli.py | 83 ++++++++++++++++++++++++++++-------------------- 1 file changed, 48 insertions(+), 35 deletions(-) diff --git a/inventree_cli.py b/inventree_cli.py index f083809c..614e033e 100644 --- a/inventree_cli.py +++ b/inventree_cli.py @@ -31,24 +31,30 @@ class InvenTreeCLI: def __init__(self, config_file): self.api = None + print('Connecting... ', end='') + # Extract configuration data from file config_data = load_file(config_file) - server = config_data.get('server', None) - username = config_data.get('username', None) - password = config_data.get('password', None) - if server and username and password: - print('Connecting... ', end='') - try: - self.api = InvenTreeAPI(server, username=username, password=password) - except ConnectionRefusedError: - print('Error: check server configuration!') - return + if config_data: + server = config_data.get('server', None) + username = config_data.get('username', None) + password = config_data.get('password', None) + + if server and username and password: + try: + self.api = InvenTreeAPI(server, username=username, password=password) + except ConnectionRefusedError: + print('Error: check server configuration!') + return + else: + print('Error loading configuration file!') + return - if self.api.token: + if self.api: print('Connected.') else: - print('Error: Token does not exist!') + print('Error creating API!') def check_operation(self, table, operation): if not operation: @@ -65,32 +71,28 @@ def list_operations(self, table): def part(self, _function, category=None, id=None, name=None, description=None, revision=None, type=None): if _function.lower() == 'get': - if not name and not id: - print('Error: Missing part name or ID!') - else: - part = None + part = None - # Check with ID - if id: - part_by_id = Part(self.api, pk=id) + # Check with ID + if id: + part_by_id = Part(self.api, pk=id) + try: if part_by_id.pk: part = part_by_id - else: - # Download all parts from database - db_parts = Part.list(self.api) - - for db_part in db_parts: - if db_part.name == name: - part = db_part - break + except AttributeError: + pass + else: + # Download all parts from database + db_parts = Part.list(self.api) - if part: - print(f'{part.IPN} | {part.name} | {part.revision}') - else: - if id: - print(f'Error: Part with {id=} does not exist!') - else: - print(f'Error: Part with {name=} does not exist!') + for db_part in db_parts: + if db_part.name == name: + part = db_part + break + + return part + + return None @click.command() @@ -119,7 +121,18 @@ def main(config, table, op, list, id, name): if inventree_api.check_operation(table, op): print(f' : {op.upper()}') if table == 'part': - inventree_api.part(_function=op, id=id, name=name) + if not name and not id: + print('Error: Missing part name or ID!') + else: + part = inventree_api.part(_function=op, id=id, name=name) + + if part: + print(f'{part.IPN} | {part.name} | {part.revision}') + else: + if id: + print(f'Error: Part with ID={id} does not exist!') + else: + print(f'Error: Part with name={name} does not exist!') else: print(f' - Operation "{op}" not allowed!') else: