[![Documentation Status](https://readthedocs.org/projects/sutools/badge/?version=latest)](https://sutools.readthedocs.io/en/latest/?badge=latest)
[![codecov](https://codecov.io/gh/aastopher/sutools/branch/master/graph/badge.svg?token=ZB0AX8D6JI)](https://codecov.io/gh/aastopher/sutools)
[![PyPI version](https://badge.fury.io/py/sutools.svg)](https://badge.fury.io/py/sutools)
[![DeepSource](https://deepsource.io/gh/aastopher/sutools.svg/?label=active+issues&show_trend=true&token=RVDa2T7M-E-YSg2DVFbr1ro-)](https://deepsource.io/gh/aastopher/sutools/?ref=repository-badge)
## Description
**su (Super User) tools**
Per module utilities, designed to be lightweight, easy to configure, and reduce boilerplate code.
**info**
This 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.
***
## Quick Start:
## Register Functions with sutools
</br>
Using 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.
```python
import sutools as su
@su.register
def add(x : int, y : int):
'''add two integers'''
return x + y
```
You can also register async functions, these will be executed using `asyncio.run()` given a valid coroutine function
```python
import sutools as su
import asyncio
@su.register
async def delay_add(x : int, y : int):
'''add two integers after 1 sec'''
await asyncio.sleep(1)
return x + y
```
**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.
</br>
***
## CLI Usage Example
</br>
```python
"""This module does random stuff."""
import sutools as su
@su.register
def meet(name : str, greeting : str = 'hello', farewell : str = 'goodbye') -> str:
'''meet a person'''
output = f'\n{greeting} {name}\n{farewell} {name}'
su.log().meeting.info(output)
return output
su.logger() # optional
# module level function calls...
if __name__ == '__main__':
# main code (will run even when using cli commands)...
su.cli(desc = __doc__)
# main code (will NOT run when using cli commands)...
```
</br>
**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.
**command usage:**
```
python module.py meet foo
```
**output**
```
hello foo
goodbye foo
```
**module help output:**
```
usage: module [-h] {meet} ...
This module does random stuff.
options:
-h, --help show this help message and exit
commands:
{meet}
meet meet a person
```
**command help output:**
```
usage: dev meet [-gr <class 'str'>] [-fa <class 'str'>] [-h] name
meet(name: str, greeting: str = 'hello', farewell: str = 'goodbye') -> str
positional arguments:
name <class 'str'>
options:
-gr <class 'str'>, --greeting <class 'str'>
default: hello
-fa <class 'str'>, --farewell <class 'str'>
default: goodbye
-h, --help Show this help message and exit.
```
## CLI Using Variadic Functions
Variadic 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.
**NOTE:** since input is from `stdin` it will always be of type `<string>`, sutools will _not_ infer the data type you must infer your needed type within the function.
```python
"""This module does random stuff."""
import sutools as su
@su.register
def variadic(*args, **kwargs):
print("Positional arguments:")
for arg in args:
print(arg)
print("Keyword arguments:")
for key, value in kwargs.items():
print(f"{key} = {value}")
su.logger() # optional
# module level function calls...
if __name__ == '__main__':
# main code (will run even when using cli commands)...
su.cli(desc = __doc__)
# main code (will NOT run when using cli commands)...
```
**command usage:**
```
python module.py variadic 1 2 3 foo=1 bar=2
```
**output:**
```
Positional arguments:
1
2
3
Keyword arguments:
foo = 1
bar = 2
```
## Logger Usage Examples
</br>
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.
</br>
**using registered function names**
```python
import sutools as su
@su.register
def add(x : int, y : int):
'''add two integers'''
su.log().add.info(f'{x} + {y} = {x+y}')
return x + y
@su.register
def minus(x : int, y : int):
'''subtract two integers'''
su.log().minus.info(f'{x} - {y} = {x-y}')
return x - y
su.logger()
# module level function calls
add(1,2)
minus(1,2)
if __name__ == '__main__':
# main code (will run even when using cli commands)...
su.cli() # optional
# main code (will NOT run when using cli commands)...
```
</br>
**log output**
```
16:16:34, 961 add INFO 1 + 2 = 3
16:16:34, 961 minus INFO 1 - 2 = -1
```
</br>
**using custom logger names**
```python
import sutools as su
@su.register
def add(x : int, y : int):
'''add two integers'''
su.log().logger1.info(f'{x} + {y} = {x+y}')
return x + y
@su.register
def minus(x : int, y : int):
'''subtract two integers'''
su.log().logger2.info(f'{x} - {y} = {x-y}')
return x - y
su.logger(loggers=['logger1','logger2'])
# module level function calls
add(1,2)
minus(1,2)
if __name__ == '__main__':
# main code (will run even when using cli commands)...
su.cli() # optional
# main code (will NOT run when using cli commands)...
```
</br>
**log output**
```
16:16:34, 961 logger1 INFO 1 + 2 = 3
16:16:34, 961 logger2 INFO 1 - 2 = -1
```
***
</br>
## Benchy Usage Example
</br>
The `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.
```python
import sutools as su
@su.benchy
@su.register
def add(x : int, y : int):
'''add two integers'''
return x + y
@su.register
@su.benchy
def subtract(x : int, y : int):
'''subtract two integers'''
return x - y
@su.benchy
@su.register
def calc(x : int, y : int, atype : str = '+') -> int:
'''calculates a thing'''
if atype == '+':
res = x + y
elif atype == '-':
res = x - y
return res
add(1,2)
add(2,2)
subtract(1,2)
calc(2,3, atype='-')
```
After the functions have been executed, the benchmark report can be accessed with `su.benchy.report`.
```python
# print the benchmark report
print(su.benchy.report)
```
**Example output**
```
{'add': [{'args': [{'type': 'int', 'value': 1}, {'type': 'int', 'value': 2}],
'benchmark': 0.00015466799959540367,
'kwargs': None,
'result': {'type': 'int', 'value': 3}},
{'args': [{'type': 'int', 'value': 2}, {'type': 'int', 'value': 2}],
'benchmark': 6.068096263334155e-05,
'kwargs': None,
'result': {'type': 'int', 'value': 4}}],
'calc': [{'args': [{'type': 'int', 'value': 2}, {'type': 'int', 'value': 3}],
'benchmark': 4.855601582676172e-05,
'kwargs': {'atype': {'length': 1, 'type': 'str'}},
'result': {'type': 'int', 'value': 5}}],
'subtract': [{'args': [{'type': 'int', 'value': 1}, {'type': 'int', 'value': 2}],
'benchmark': 5.205394700169563e-05,
'kwargs': None,
'result': {'type': 'int', 'value': -1}}]}
```
The output of the benchmark report will adhere to the following format: `function > call records`. Call records consist of `{args, kwargs, result, benchmark}` there will be a record for each call of a given function.
**NOTE:** given an iterable for `arg`, `kwarg`, or `result` the object will be summarized in terms of vector length.
```
{'function_name': [{'args': [{'type': 'arg_type', 'value': int}]
'benchmark': float,
'kwargs': {'kwarg_name': {'type': 'arg_type', 'length': int, }}
'result': {'type': 'arg_type', 'value': float}}]}
```
Raw data
{
"_id": null,
"home_page": "https://github.com/aastopher/sutools",
"name": "sutools",
"maintainer": "",
"docs_url": null,
"requires_python": ">=3.6",
"maintainer_email": "",
"keywords": "logs,logger,logging,cli,utils,performance counter,benchmark",
"author": "Aaron Stopher",
"author_email": "",
"download_url": "https://files.pythonhosted.org/packages/c3/e3/a95a1f5943d1d3974fa482de0309ae26600aa09afedec404d58c3d9730be/sutools-0.2.4.tar.gz",
"platform": null,
"description": "[![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&show_trend=true&token=RVDa2T7M-E-YSg2DVFbr1ro-)](https://deepsource.io/gh/aastopher/sutools/?ref=repository-badge)\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</br>\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</br>\n\n***\n\n## CLI Usage Example\n\n</br>\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') -> 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</br>\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 <class 'str'>] [-fa <class 'str'>] [-h] name\n\n meet(name: str, greeting: str = 'hello', farewell: str = 'goodbye') -> str\n\n positional arguments:\n name <class 'str'>\n\n options:\n -gr <class 'str'>, --greeting <class 'str'>\n default: hello\n -fa <class 'str'>, --farewell <class 'str'>\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 `<string>`, 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</br>\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</br>\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</br>\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</br>\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</br>\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</br>\n\n## Benchy Usage Example\n\n</br>\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 = '+') -> 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 > 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```\n",
"bugtrack_url": null,
"license": "",
"summary": "su (Super User) tools; per module utilities, designed to be lightweight, easy to configure, and reduce boilerplate code.",
"version": "0.2.4",
"project_urls": {
"Bug Tracker": "https://github.com/aastopher/sutools/issues",
"Documentation": "https://sutools.readthedocs.io",
"Homepage": "https://github.com/aastopher/sutools"
},
"split_keywords": [
"logs",
"logger",
"logging",
"cli",
"utils",
"performance counter",
"benchmark"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "591d2c9af19715ef589b00865d1986e9bab3b0d283a946fb068c98138cafa548",
"md5": "d6806b259745f93e28aa09cc4b755f55",
"sha256": "925d88d8aa7f6c81ff96d1e0d945278f8c8f7d426eefca0d308c2fb579406889"
},
"downloads": -1,
"filename": "sutools-0.2.4-py3-none-any.whl",
"has_sig": false,
"md5_digest": "d6806b259745f93e28aa09cc4b755f55",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.6",
"size": 12142,
"upload_time": "2023-06-29T17:09:56",
"upload_time_iso_8601": "2023-06-29T17:09:56.102546Z",
"url": "https://files.pythonhosted.org/packages/59/1d/2c9af19715ef589b00865d1986e9bab3b0d283a946fb068c98138cafa548/sutools-0.2.4-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "c3e3a95a1f5943d1d3974fa482de0309ae26600aa09afedec404d58c3d9730be",
"md5": "b49a2462beb97a9f494b0b5a80f75c2e",
"sha256": "794b462794102871c371d0239cd5b77b70888ae2d418d8cf8a3e67c2180666ec"
},
"downloads": -1,
"filename": "sutools-0.2.4.tar.gz",
"has_sig": false,
"md5_digest": "b49a2462beb97a9f494b0b5a80f75c2e",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.6",
"size": 19430,
"upload_time": "2023-06-29T17:09:57",
"upload_time_iso_8601": "2023-06-29T17:09:57.540731Z",
"url": "https://files.pythonhosted.org/packages/c3/e3/a95a1f5943d1d3974fa482de0309ae26600aa09afedec404d58c3d9730be/sutools-0.2.4.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-06-29 17:09:57",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "aastopher",
"github_project": "sutools",
"github_fetch_exception": true,
"lcname": "sutools"
}