{"id":25982528,"url":"https://github.com/aastopher/sutools","last_synced_at":"2025-03-05T09:32:41.098Z","repository":{"id":65416096,"uuid":"583182183","full_name":"aastopher/sutools","owner":"aastopher","description":"su (Super User) tools -  per module utilities, designed to be lightweight, easy to configure, and reduce boilerplate code.","archived":false,"fork":false,"pushed_at":"2023-08-15T22:11:09.000Z","size":2948,"stargazers_count":5,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-02-04T09:19:03.530Z","etag":null,"topics":["argparse","boilerplate","cli","logging","python","toolset"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/aastopher.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-12-29T02:25:15.000Z","updated_at":"2023-08-14T08:19:07.000Z","dependencies_parsed_at":"2023-02-12T16:00:55.905Z","dependency_job_id":null,"html_url":"https://github.com/aastopher/sutools","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aastopher%2Fsutools","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aastopher%2Fsutools/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aastopher%2Fsutools/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aastopher%2Fsutools/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/aastopher","download_url":"https://codeload.github.com/aastopher/sutools/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241945530,"owners_count":20046870,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["argparse","boilerplate","cli","logging","python","toolset"],"created_at":"2025-03-05T09:32:40.365Z","updated_at":"2025-03-05T09:32:41.055Z","avatar_url":"https://github.com/aastopher.png","language":"Python","readme":"[![Documentation Status](https://readthedocs.org/projects/sutools/badge/?version=latest)](https://sutools.readthedocs.io/en/latest/?badge=latest)\n[![codecov](https://codecov.io/gh/aastopher/sutools/branch/master/graph/badge.svg?token=ZB0AX8D6JI)](https://codecov.io/gh/aastopher/sutools)\n[![PyPI version](https://badge.fury.io/py/sutools.svg)](https://badge.fury.io/py/sutools)\n[![DeepSource](https://deepsource.io/gh/aastopher/sutools.svg/?label=active+issues\u0026show_trend=true\u0026token=RVDa2T7M-E-YSg2DVFbr1ro-)](https://deepsource.io/gh/aastopher/sutools/?ref=repository-badge)\n\n\n## **Important Notice: deprecating sutools for [`stakk`](https://github.com/aastopher/stakk)**\n\nI'm excited to announce that the development focus has shifted from `sutools` to my new library, [`stakk`](https://github.com/aastopher/stakk). This new library builds upon the foundation of `sutools`, with a more refined approach and a shifted focus to a stack pattern and down the line some agent focused utilities. As a result, `sutools` will no longer receive updates or support. `stakk` is designed to provide a more robust and feature-rich experience. Thank you for your understanding!\n\n\n## Description\n\n**su (Super User) tools**\n\nPer module utilities, designed to be lightweight, easy to configure, and reduce boilerplate code.\n\n\n**info**\n\nThis package is intended to create an lower barrier for entry for logging and module level cli with sensible defaults; sutools is not intended to replace click, argparse, logging or other utility libraries. If your project requires a more flexible configuration please use the appropriate tooling.\n***\n\n## Quick Start:\n\n## Register Functions with sutools\n\n\u003c/br\u003e\n\nUsing the register decorator `@su.register` on your functions will register it with sutools `meta_handler`. Stored functions are available across tools. This registry is intended to be used by logger and cli utilities.\n\n```python\nimport sutools as su\n\n@su.register\ndef add(x : int, y : int):\n    '''add two integers'''\n    return x + y\n\n```\n\nYou can also register async functions, these will be executed using `asyncio.run()` given a valid coroutine function\n\n```python\nimport sutools as su\nimport asyncio\n\n@su.register\nasync def delay_add(x : int, y : int):\n    '''add two integers after 1 sec'''\n    await asyncio.sleep(1)\n    return x + y\n    \n```\n\n**NOTE:** Adding type hinting to your functions enforces types in the cli and adds positional arg class identifiers in the help docs for the command.\n\n\u003c/br\u003e\n\n***\n\n## CLI Usage Example\n\n\u003c/br\u003e\n\n```python\n\"\"\"This module does random stuff.\"\"\"\nimport sutools as su\n\n@su.register\ndef meet(name : str, greeting : str = 'hello', farewell : str = 'goodbye') -\u003e str:\n        '''meet a person'''\n        output = f'\\n{greeting} {name}\\n{farewell} {name}'\n        su.log().meeting.info(output)\n        return output\n\nsu.logger() # optional\n\n# module level function calls...\n\nif __name__ == '__main__':\n    # main code (will run even when using cli commands)...\n    su.cli(desc = __doc__)\n    # main code (will NOT run when using cli commands)...\n```\n\n\u003c/br\u003e\n\n**NOTE:** Adding type hinting to your functions enforces types in the cli and adds positional arg class identifiers in the help docs for the command.\n\n**command usage:**\n\n```\npython module.py meet foo\n```\n\n**output**\n\n```\nhello foo\ngoodbye foo\n```\n\n**module help output:**\n\n```\n    usage: module [-h] {meet} ...\n\n    This module does random stuff.\n\n    options:\n    -h, --help  show this help message and exit\n\n    commands:\n    {meet}\n        meet      meet a person\n```\n\n**command help output:**\n\n```\n    usage: dev meet [-gr \u003cclass 'str'\u003e] [-fa \u003cclass 'str'\u003e] [-h] name\n\n    meet(name: str, greeting: str = 'hello', farewell: str = 'goodbye') -\u003e str\n\n    positional arguments:\n    name                  \u003cclass 'str'\u003e\n\n    options:\n    -gr \u003cclass 'str'\u003e, --greeting \u003cclass 'str'\u003e\n                            default: hello\n    -fa \u003cclass 'str'\u003e, --farewell \u003cclass 'str'\u003e\n                            default: goodbye\n    -h, --help            Show this help message and exit.\n```\n\n## CLI Using Variadic Functions\n\nVariadic functions are compatible with sutools cli utility. When calling kwargs from the cli; `key=value` should be used instead of `--` and `-`, these are reserved for default arguments.\n\n**NOTE:** since input is from `stdin` it will always be of type `\u003cstring\u003e`, sutools will _not_ infer the data type you must infer your needed type within the function.\n\n```python\n\"\"\"This module does random stuff.\"\"\"\nimport sutools as su\n\n@su.register\ndef variadic(*args, **kwargs):\n    \n    print(\"Positional arguments:\")\n    for arg in args:\n        print(arg)\n\n    print(\"Keyword arguments:\")\n    for key, value in kwargs.items():\n        print(f\"{key} = {value}\")\n\n    su.logger() # optional\n\n# module level function calls...\n\nif __name__ == '__main__':\n    # main code (will run even when using cli commands)...\n    su.cli(desc = __doc__)\n    # main code (will NOT run when using cli commands)...\n```\n\n**command usage:**\n\n```\npython module.py variadic 1 2 3 foo=1 bar=2\n```\n\n**output:**\n\n```\nPositional arguments:\n1\n2\n3\nKeyword arguments:\nfoo = 1\nbar = 2\n```\n\n\n## Logger Usage Examples\n\n\u003c/br\u003e\n \n accessing defined loggers is done with a `log()` helper function. Note the use of `su.log()` in the below functions to access a specified logger before defining the log level and message.\n\n\u003c/br\u003e\n\n**using registered function names**\n\n\n```python\nimport sutools as su\n\n@su.register\ndef add(x : int, y : int):\n    '''add two integers'''\n    su.log().add.info(f'{x} + {y} = {x+y}')\n    return x + y\n\n@su.register\ndef minus(x : int, y : int):\n    '''subtract two integers'''\n    su.log().minus.info(f'{x} - {y} = {x-y}')\n    return x - y\n\nsu.logger()\n\n# module level function calls\nadd(1,2)\nminus(1,2)\n\nif __name__ == '__main__':\n    # main code (will run even when using cli commands)...\n    su.cli() # optional\n    # main code (will NOT run when using cli commands)...\n```\n\n\u003c/br\u003e\n\n**log output**\n```\n16:16:34, 961 add INFO 1 + 2 = 3\n16:16:34, 961 minus INFO 1 - 2 = -1\n```\n\n\u003c/br\u003e\n\n**using custom logger names**\n\n\n```python\nimport sutools as su\n\n@su.register\ndef add(x : int, y : int):\n    '''add two integers'''\n    su.log().logger1.info(f'{x} + {y} = {x+y}')\n    return x + y\n\n@su.register\ndef minus(x : int, y : int):\n    '''subtract two integers'''\n    su.log().logger2.info(f'{x} - {y} = {x-y}')\n    return x - y\n\nsu.logger(loggers=['logger1','logger2'])\n\n# module level function calls\nadd(1,2)\nminus(1,2)\n\nif __name__ == '__main__':\n    # main code (will run even when using cli commands)...\n    su.cli() # optional\n    # main code (will NOT run when using cli commands)...\n```\n\n\u003c/br\u003e\n\n**log output**\n```\n16:16:34, 961 logger1 INFO 1 + 2 = 3\n16:16:34, 961 logger2 INFO 1 - 2 = -1\n```\n\n***\n\u003c/br\u003e\n\n## Benchy Usage Example\n\n\u003c/br\u003e\n\nThe `benchy` decorator is designed to collect performance timing and call info for selected functions. This can be used in combination with `@su.register`, the decorators are order independent.\n\n```python\nimport sutools as su\n\n@su.benchy\n@su.register\ndef add(x : int, y : int):\n    '''add two integers'''\n    return x + y\n\n@su.register\n@su.benchy\ndef subtract(x : int, y : int):\n    '''subtract two integers'''\n    return x - y\n\n@su.benchy\n@su.register\ndef calc(x : int, y : int, atype : str = '+') -\u003e int:\n    '''calculates a thing'''\n    if atype == '+':\n        res = x + y\n    elif atype == '-':\n        res = x - y\n    return res\n\nadd(1,2)\nadd(2,2)\nsubtract(1,2)\ncalc(2,3, atype='-')\n\n```\n\nAfter the functions have been executed, the benchmark report can be accessed with `su.benchy.report`.\n\n```python\n# print the benchmark report\nprint(su.benchy.report)\n```\n\n**Example output**\n\n```\n{'add': [{'args': [{'type': 'int', 'value': 1}, {'type': 'int', 'value': 2}],\n        'benchmark': 0.00015466799959540367,\n        'kwargs': None,\n        'result': {'type': 'int', 'value': 3}},\n        {'args': [{'type': 'int', 'value': 2}, {'type': 'int', 'value': 2}],\n        'benchmark': 6.068096263334155e-05,\n        'kwargs': None,\n        'result': {'type': 'int', 'value': 4}}],\n'calc': [{'args': [{'type': 'int', 'value': 2}, {'type': 'int', 'value': 3}],\n        'benchmark': 4.855601582676172e-05,\n        'kwargs': {'atype': {'length': 1, 'type': 'str'}},\n        'result': {'type': 'int', 'value': 5}}],\n'subtract': [{'args': [{'type': 'int', 'value': 1}, {'type': 'int', 'value': 2}],\n        'benchmark': 5.205394700169563e-05,\n        'kwargs': None,\n        'result': {'type': 'int', 'value': -1}}]}\n```\n\nThe output of the benchmark report will adhere to the following format: `function \u003e call records`. Call records consist of `{args, kwargs, result, benchmark}` there will be a record for each call of a given function.\n\n**NOTE:** given an iterable for `arg`, `kwarg`, or `result` the object will be summarized in terms of vector length.\n\n```\n{'function_name': [{'args': [{'type': 'arg_type', 'value': int}]\n                    'benchmark': float,\n                    'kwargs': {'kwarg_name': {'type': 'arg_type', 'length': int, }}\n                    'result': {'type': 'arg_type', 'value': float}}]}\n```","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faastopher%2Fsutools","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faastopher%2Fsutools","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faastopher%2Fsutools/lists"}