{"id":25982529,"url":"https://github.com/aastopher/stakk","last_synced_at":"2026-04-23T03:33:02.403Z","repository":{"id":188544505,"uuid":"678936547","full_name":"aastopher/stakk","owner":"aastopher","description":"Register functions to a stack, each stack can be linked to modular utilities. The stack pattern is intended to facilitate a lower barrier for entry to configure command line interfaces, benchmark tasks, and interact with threaded agents.","archived":false,"fork":false,"pushed_at":"2023-08-15T21:27:13.000Z","size":58,"stargazers_count":1,"open_issues_count":4,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-11-27T23:37:26.746Z","etag":null,"topics":["agent","benchmark","cli","performance-counter","threading","utils","worker"],"latest_commit_sha":null,"homepage":"https://stakk.readthedocs.io","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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-08-15T18:20:14.000Z","updated_at":"2025-04-06T02:38:13.000Z","dependencies_parsed_at":null,"dependency_job_id":"d86410b7-3ce2-4382-a23e-3c33e4a496b6","html_url":"https://github.com/aastopher/stakk","commit_stats":null,"previous_names":["aastopher/stakk"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/aastopher/stakk","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aastopher%2Fstakk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aastopher%2Fstakk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aastopher%2Fstakk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aastopher%2Fstakk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/aastopher","download_url":"https://codeload.github.com/aastopher/stakk/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aastopher%2Fstakk/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32165047,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-23T02:19:40.750Z","status":"ssl_error","status_checked_at":"2026-04-23T02:17:55.737Z","response_time":53,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["agent","benchmark","cli","performance-counter","threading","utils","worker"],"created_at":"2025-03-05T09:32:40.516Z","updated_at":"2026-04-23T03:33:02.389Z","avatar_url":"https://github.com/aastopher.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Documentation Status](https://readthedocs.org/projects/stakk/badge/?version=latest)](https://stakk.readthedocs.io/en/latest/?badge=latest)\n[![codecov](https://codecov.io/gh/aastopher/stakk/graph/badge.svg?token=3RSWSCO72X)](https://codecov.io/gh/aastopher/stakk)\n[![PyPI version](https://badge.fury.io/py/stakk.svg)](https://badge.fury.io/py/stakk)\n[![DeepSource](https://app.deepsource.com/gh/aastopher/stakk.svg/?label=active+issues\u0026show_trend=true\u0026token=QdzCwtyocLG_4fymZUbw1WX5)](https://app.deepsource.com/gh/aastopher/stakk/?ref=repository-badge)\n\n## Description\n\nRegister functions to a stack, each stack can be linked to modular utilities. The stakk pattern is intended to facilitate a lower barrier for entry to configure command line interfaces, benchmark tasks, and interact with threaded agents.\n\n***\n\n## Quick Start:\n\n## register functions with stakk\n\nUsing the register decorator `@stakk.register('stack_id')` on your functions will register it with a stack in `meta_handler.Stack`. Functions in a stack are available for utilities to register and create a link to the stack.\n\n```python\nimport stakk\n\n@stakk.register('stack_id')\ndef add(x : int, y : int):\n    '''add two integers'''\n    return x + y\n```\n\nYou can also register async functions, these will be executed using `asyncio.run()` given a valid coroutine function.\n\n```python\nimport stakk\nimport asyncio\n\n@stakk.register('stack_id')\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## cli - initialization standard\n\nIt is suggested to define the command line interface after `if __name__ == '__main__'`. Any code before the cli will run even if a cli command is used; code after the cli definition will not run when passing a cli command. The cli initialization will require 1 argument a stack_id, optionally you can provide a description it is suggested to use doc strings for this and init as shown.\n\n```python\nimport stakk\n\n# registered functions...\n\n# module level function calls...\n\nif __name__ == '__main__':\n    # main code (will run even when using cli commands)...\n    stakk.cli(stack_id = 'stack_id', desc = __doc__) # desc is optional\n    # main code (will NOT run when using cli commands)...\n```\n\n## cli - args and optional args\n\nAdding a default value will create an optional arg for the command. The keyword and default value will be displayed in the help docs along with the type if one is given.\n\n```python\n\"\"\"This module does random stuff.\"\"\"\nimport stakk\n\n@stakk.register('cli')\ndef meet(name : str, greeting : str = 'hello', farewell : str = 'goodbye') -\u003e str:\n    '''meet a person'''\n    return f'\\n{greeting} {name}\\n{farewell} {name}'\n\n# module level function calls...\n\nif __name__ == '__main__':\n    # main code (will run even when using cli commands)...\n    stakk.cli(stack_id = 'cli', desc = __doc__)\n    # main code (will NOT run when using cli commands)...\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 that 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```\nusage: module [-h] {meet} ...\n\nThis module does random stuff.\n\noptions:\n-h, --help  show this help message and exit\n\ncommands:\n{meet}\n    meet      meet a person\n```\n\n**Command help output:**\n\n```\nusage: module meet [-gr GREETING] [-fa FAREWELL] [-h] name\n\nmeet(name: str, greeting: str = 'hello', farewell: str = 'goodbye') -\u003e str\n\npositional arguments:\nname                  type: str\n\noptions:\n-gr GREETING, --greeting GREETING\n                        type: str, default: hello\n-fa FAREWELL, --farewell FAREWELL\n                        type: str, default: goodbye\n-h, --help            Show this help message and exit.\n```\n\n## cli - choice arguments\n\nAdding an iterable as the type annotation will define a choices argument. A custom type checker is defined based on the option types in the iterable provided. This will allow you to define mixed types in your choices lists.\n\n```python\n\"\"\"This module does random stuff.\"\"\"\nimport stakk\n\nfoo_choices = ['foo', 'fooo','foooo']\nbar_choices = ('bar', 1, 'baar', 2)\n\n@stakk.register('cli')\ndef foo_choices(foo: foo_choices, bar: bar_choices = 2) -\u003e tuple:\n    '''foo bar'''\n    return foo, bar\n\n# module level function calls...\n\nif __name__ == '__main__':\n    # main code (will run even when using cli commands)...\n    stakk.cli(stack_id = 'cli', desc = __doc__)\n    # main code (will NOT run when using cli commands)...\n```\n\n**Command usage:**\n\n```\npython module.py foo_choices fooo --bar 1\n```\n\n**Output:**\n\n```\n('fooo', 1)\n```\n\n**Command help output:**\n\n```\nusage: module foo_choices [-ba BAR] [-h] foo\n\nfoo_choices(foo: choice_type, bar: choice_type = 2) -\u003e tuple\n\npositional arguments:\nfoo                 choices: (foo, fooo, foooo)\n\noptions:\n-ba BAR, --bar BAR  choices: (bar, 1, baar, 2), default: 2\n-h, --help          Show this help message and exit.\n```\n\n## cli - list annotation\n\nUsing list as a type annotation has special context. This will prompt the cli to define a custom list type which returns `re.split(r'[;,| ]', value)`. This allows you to specify string with delimiters which are converted to lists before being passed to the function. You are welcome to create and pass your own type functions but lists are built in for ease of use.\n\n```python\n\"\"\"This module does random stuff.\"\"\"\nimport stakk\n\n@stakk.register('cli')\ndef foo_lists(foo : list, bar : list = ['foo','bar']) -\u003e tuple:\n        return foo, bar\n\n# module level function calls...\n\nif __name__ == '__main__':\n    # main code (will run even when using cli commands)...\n    stakk.cli(stack_id = 'cli', desc = __doc__)\n    # main code (will NOT run when using cli commands)...\n```\n\n**Command usage:**\n\n```\npython module.py foo_lists 'foo,bar;foo|bar foo'\n```\n\n**Output:**\n\n```\n(['foo', 'bar', 'foo', 'bar', 'foo'], ['foo', 'bar'])\n```\n\n**Command help output:**\n\n```\nusage: module foo_lists [-ba BAR] [-h] foo\n\nfoo_lists(foo: type_list, bar: type_list = ['foo', 'bar']) -\u003e tuple\n\npositional arguments:\nfoo                 type: list\n\noptions:\n-ba BAR, --bar BAR  type: list, default: ['foo', 'bar']\n-h, --help          Show this help message and exit.\n```\n\n## cli - variadic functions\n\nVariadic functions are compatible with stakk 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:** providing type annotations will enforce type, however this will apply to all `*args` or `**kwargs`, if custom logic is needed you can create and pass a custom type function.\n\n```python\n\"\"\"This module does random stuff.\"\"\"\nimport stakk\n\n@stakk.register('cli')\ndef variadic(*args: str, **kwargs: int):\n    \n    print(\"Positional arguments:\")\n\n\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# module level function calls...\n\nif __name__ == '__main__':\n    # main code (will run even when using cli commands)...\n    stakk.cli(stack_id = 'cli', desc = __doc__)\n    # main code (will NOT run when using cli commands)...\n```\n\n**Command usage:**\n\n```\npython module.py variadic foo bar foo foo=1 bar=2\n```\n\n**Output:**\n\n```\nPositional arguments:\nfoo\nbar\nfoo\n\nKeyword arguments:\nfoo = 1\nbar = 2\n```\n\n**Command help output:**\n\n```\nusage: dev variadic [-h] [*args ...] [**kwargs ...]\n\nvariadic(args, kwargs)\n\npositional arguments:\n*args       ex: command arg1 arg2\n**kwargs    ex: command key=value\n\noptions:\n-h, --help  Show this help message and exit.\n```\n\n## benchy - usage example\n\nThe `benchy` decorator is designed to collect performance timing and call info for selected functions. This can be used in combination with `@stakk.register`, the decorators are order independent.\n\n```python\nimport stakk\nimport asyncio\n\n@stakk.benchy\n@stakk.register('test_stack')\ndef add(x : int, y : int):\n    '''add two integers'''\n    return x + y\n\n@stakk.register('test_stack')\n@stakk.benchy\ndef subtract(x : int, y : int):\n    '''subtract two integers'''\n    return x - y\n\n@stakk.benchy\n@stakk.register('test_stack')\ndef calc(x : int, y : int, atype : str = '+') -\u003e int:\n    '''calculates a thing'''\n    if atype == '+':\n        res = add(x, y)\n    elif atype == '-':\n        res = subtract(x, y)\n    return res\n\n@stakk.register('test_stack')\n@stakk.benchy\nasync def async_example():\n    '''An example async function'''\n    await asyncio.sleep(1)\n    print(\"Async function completed.\")\n\nadd(1,2)\nadd(2,2)\nsubtract(1,2)\ncalc(2,3, atype='-')\nasyncio.get_event_loop().run_until_complete(async_example())\n```\n\nAfter the functions have been executed, the benchmark report can be accessed with `stakk.benchy.report`.\n\n```python\n# print the benchmark report\nprint(stakk.benchy.report)\n```\n\nExample output:\n\n```\n{\n    'add': [\n        {\n            'args': [{'type': 'int', 'value': 1}, {'type': 'int', 'value': 2}],\n            'benchmark': 0.00015466799959540367,\n            'kwargs': None,\n            'result': {'type': 'int', 'value': 3}\n        },\n        {\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        }\n    ],\n    'calc': [\n        {\n            '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        }\n    ],\n    'subtract': [\n        {\n            '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    ],\n    'async_example': [\n        {\n            'args': None,\n            'benchmark': 1.001522845996078,\n            'kwargs': None,\n            'result': {'type': 'NoneType', 'value': None}\n        }\n    ]\n}\n```\n\nThe output of the benchmark report will adhere to the following format. `function : call report`. Call reports 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{\n    'function_name': [\n        {\n            '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    ]\n}\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faastopher%2Fstakk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faastopher%2Fstakk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faastopher%2Fstakk/lists"}