{"id":34680536,"url":"https://github.com/oir/startle","last_synced_at":"2025-12-24T21:06:26.918Z","repository":{"id":256675907,"uuid":"850420149","full_name":"oir/startle","owner":"oir","description":"Instantly start a CLI from a function, functions, or a class","archived":false,"fork":false,"pushed_at":"2025-11-06T00:44:24.000Z","size":446,"stargazers_count":11,"open_issues_count":8,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-11-27T23:58:11.542Z","etag":null,"topics":["argparse","argument-parser","cli","command-line","python","shell","typehints"],"latest_commit_sha":null,"homepage":"https://oir.github.io/startle/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/oir.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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-08-31T18:07:41.000Z","updated_at":"2025-11-06T00:36:21.000Z","dependencies_parsed_at":"2024-09-12T11:35:46.325Z","dependency_job_id":"2d1704d2-b4e7-4adc-8d86-a920c21f04e5","html_url":"https://github.com/oir/startle","commit_stats":null,"previous_names":["oir/startle"],"tags_count":19,"template":false,"template_full_name":null,"purl":"pkg:github/oir/startle","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oir%2Fstartle","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oir%2Fstartle/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oir%2Fstartle/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oir%2Fstartle/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/oir","download_url":"https://codeload.github.com/oir/startle/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oir%2Fstartle/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28008452,"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","status":"online","status_checked_at":"2025-12-24T02:00:07.193Z","response_time":83,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["argparse","argument-parser","cli","command-line","python","shell","typehints"],"created_at":"2025-12-24T21:05:43.941Z","updated_at":"2025-12-24T21:06:26.905Z","avatar_url":"https://github.com/oir.png","language":"Python","readme":"\u003cdiv align=\"center\"\u003e\n\u003cpicture\u003e\n  \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"https://github.com/user-attachments/assets/26485518-3586-43d3-b77c-066868181795\" width=\"400\"\u003e\n  \u003csource media=\"(prefers-color-scheme: light)\" srcset=\"https://github.com/user-attachments/assets/c26368f6-00d6-425f-974e-99c6af8eb680\" width=\"400\"\u003e\n  \u003cimg src=\"https://github.com/user-attachments/assets/c26368f6-00d6-425f-974e-99c6af8eb680\" width=\"400\"\u003e\n\u003c/picture\u003e\n\n_Give your code a start._ ⚡👀\n\n![tests](https://github.com/oir/startle/actions/workflows/test.yml/badge.svg)\n[![Coveralls](https://img.shields.io/coverallsCoverage/github/oir/startle?logo=Coveralls)](https://coveralls.io/github/oir/startle)\n[![Docs](https://img.shields.io/badge/docs-2ECE53?logo=docsify\u0026logoColor=fff)](https://oir.github.io/startle/)\n\u003cbr\u003e\n[![Supported Python Versions](https://img.shields.io/pypi/pyversions/startle?logo=Python\u0026logoColor=FFFFFF)](https://pypi.org/project/startle/)\n[![PyPI Version](https://img.shields.io/pypi/v/startle?label=pip%20install%20startle\u0026color=blue\u0026logo=data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1MTIgNTEyIj48IS0tIUZvbnQgQXdlc29tZSBGcmVlIDYuNy4yIGJ5IEBmb250YXdlc29tZSAtIGh0dHBzOi8vZm9udGF3ZXNvbWUuY29tIExpY2Vuc2UgLSBodHRwczovL2ZvbnRhd2Vzb21lLmNvbS9saWNlbnNlL2ZyZWUgQ29weXJpZ2h0IDIwMjQgRm9udGljb25zLCBJbmMuLS0+PHBhdGggZmlsbD0iI2VhZWJlZSIgZD0iTTI4OCAzMmMwLTE3LjctMTQuMy0zMi0zMi0zMnMtMzIgMTQuMy0zMiAzMmwwIDI0Mi43LTczLjQtNzMuNGMtMTIuNS0xMi41LTMyLjgtMTIuNS00NS4zIDBzLTEyLjUgMzIuOCAwIDQ1LjNsMTI4IDEyOGMxMi41IDEyLjUgMzIuOCAxMi41IDQ1LjMgMGwxMjgtMTI4YzEyLjUtMTIuNSAxMi41LTMyLjggMC00NS4zcy0zMi44LTEyLjUtNDUuMyAwTDI4OCAyNzQuNyAyODggMzJ6TTY0IDM1MmMtMzUuMyAwLTY0IDI4LjctNjQgNjRsMCAzMmMwIDM1LjMgMjguNyA2NCA2NCA2NGwzODQgMGMzNS4zIDAgNjQtMjguNyA2NC02NGwwLTMyYzAtMzUuMy0yOC43LTY0LTY0LTY0bC0xMDEuNSAwLTQ1LjMgNDUuM2MtMjUgMjUtNjUuNSAyNS05MC41IDBMMTY1LjUgMzUyIDY0IDM1MnptMzY4IDU2YTI0IDI0IDAgMSAxIDAgNDggMjQgMjQgMCAxIDEgMC00OHoiLz48L3N2Zz4=)](https://pypi.org/project/startle/)\n[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)\n[![Pyright](https://img.shields.io/badge/types-pyright-blue.svg)](https://github.com/microsoft/pyright)\n\n\u003c/div\u003e\n\n\u003e [!WARNING]  \n\u003e **Startle** is _alpha_ and should be considered unstable as its interface is fluid 😅, consider pinning to a version.\n\n**Startle** lets you transform a python function (or functions) into a command line entry point, e.g:\n\n`wc.py`:\n```python\nfrom pathlib import Path\nfrom typing import Literal\n\nfrom startle import start\n\n\ndef word_count(\n    fname: Path, /, kind: Literal[\"word\", \"char\"] = \"word\", *, verbose: bool = False\n) -\u003e None:\n    \"\"\"\n    Count the number of words or characters in a file.\n\n    Args:\n        fname: The file to count.\n        kind: Whether to count words or characters.\n        verbose: Whether to print additional info.\n    \"\"\"\n\n    text = open(fname).read()\n    count = len(text.split()) if kind == \"word\" else len(text)\n\n    print(f\"{count} {kind}s in {fname}\" if verbose else count)\n\n\nstart(word_count)\n```\n\n\u003cpicture\u003e\n  \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"https://github.com/user-attachments/assets/95f95d86-813d-4197-b5e4-5ad9b4f5b172\" width=\"100%\"\u003e\n  \u003csource media=\"(prefers-color-scheme: light)\" srcset=\"https://github.com/user-attachments/assets/03d5dfe3-5379-4df9-ac0c-ecc836b62120\" width=\"100%\"\u003e\n  \u003cimg src=\"https://github.com/user-attachments/assets/03d5dfe3-5379-4df9-ac0c-ecc836b62120\" width=\"100%\"\u003e\n\u003c/picture\u003e\n\nWhen you invoke `start()`, it will construct an argparser (based on type hints and docstring),\nparse the arguments, and invoke `word_count`.\n\n\u003cpicture\u003e\n  \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"https://github.com/user-attachments/assets/05b640a9-5711-4fc8-a8f8-ab0da17016bd\" width=\"100%\"\u003e\n  \u003csource media=\"(prefers-color-scheme: light)\" srcset=\"https://github.com/user-attachments/assets/36edf935-50a1-48a4-8f60-c30b36e471d1\" width=\"100%\"\u003e\n  \u003cimg src=\"https://github.com/user-attachments/assets/36edf935-50a1-48a4-8f60-c30b36e471d1\" width=\"100%\"\u003e\n\u003c/picture\u003e\n\nYou can also invoke `start()` with a list of functions instead of a single function.\nIn this case, functions are made available as _commands_ with their own arguments\nand options in your CLI. See [here](https://oir.github.io/startle/#/function-interface?id=commands).\n\n---\n\n**Startle** also allows you to transform a class (possibly a dataclass) into a command line parser:\n\n```python\nimport random\nfrom dataclasses import dataclass\nfrom typing import Literal\n\nfrom startle import parse\n\n\n@dataclass\nclass Config:\n    \"\"\"\n    Configuration for the dice program.\n\n    Attributes:\n        sides: The number of sides on the dice.\n        count: The number of dice to throw.\n        kind: Whether to throw a single die or a pair of dice.\n    \"\"\"\n\n    sides: int = 6\n    count: int = 1\n    kind: Literal[\"single\", \"pair\"] = \"single\"\n\n\ndef throw_dice(cfg: Config) -\u003e None:\n    \"\"\"\n    Throw the dice according to the configuration.\n    \"\"\"\n    if cfg.kind == \"single\":\n        for _ in range(cfg.count):\n            print(random.randint(1, cfg.sides))\n    else:\n        for _ in range(cfg.count):\n            print(random.randint(1, cfg.sides), random.randint(1, cfg.sides))\n\n\nif __name__ == \"__main__\":\n    cfg = parse(Config, brief=\"A program to throw dice.\")\n    throw_dice(cfg)\n```\n\nThen `dice.py` can be executed like:\n\n\u003cpicture\u003e\n  \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"https://github.com/user-attachments/assets/a8c7d949-5d36-4b71-8427-2b54dbdac95c\" width=\"100%\"\u003e\n  \u003csource media=\"(prefers-color-scheme: light)\" srcset=\"https://github.com/user-attachments/assets/26715b4c-a159-4aad-a428-28002ef5c84d\" width=\"100%\"\u003e\n  \u003cimg src=\"https://github.com/user-attachments/assets/26715b4c-a159-4aad-a428-28002ef5c84d\" width=\"100%\"\u003e\n\u003c/picture\u003e\n\n\u003cpicture\u003e\n  \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"https://github.com/user-attachments/assets/e2222195-31c4-4fd9-959e-6ea73d68b49e\" width=\"100%\"\u003e\n  \u003csource media=\"(prefers-color-scheme: light)\" srcset=\"https://github.com/user-attachments/assets/1069d770-c334-425b-b9df-79eeb56991f6\" width=\"100%\"\u003e\n  \u003cimg src=\"https://github.com/user-attachments/assets/1069d770-c334-425b-b9df-79eeb56991f6\" width=\"100%\"\u003e\n\u003c/picture\u003e\n\n---\n\u003cbr\u003e\n\n**Startle** is inspired by [Typer](https://github.com/fastapi/typer), [Fire](https://github.com/google/python-fire),\nand [HFArgumentParser](https://github.com/huggingface/transformers/blob/main/src/transformers/hf_argparser.py),\nbut aims to be _non-intrusive_, to have stronger type support, and to have saner defaults.\nThus, some decisions are done differently:\n\n- Use of positional-only or keyword-only argument separators (`/`, `*`, see PEP 570, 3102) are naturally translated into positional arguments or options.\n  See above example ([wc.py](https://github.com/oir/startle/blob/main/examples/wc.py)).\n- Like Typer and unlike Fire, type hints strictly determine how the individual arguments are parsed and typed.\n- Short forms (e.g. `-k`, `-v` above) are automatically provided based on the initial of the argument.\n- Variable length arguments are more intuitively handled.\n  You can use `--things a b c` (in addition to `--things=a --things=b --things=c`).\n  See [example](https://github.com/oir/startle/blob/main/examples/cat.py).\n- Like Typer and unlike Fire, help is simply printed and not displayed in pager mode by default, so you can keep referring to it as you type your command.\n- Like Fire and unlike Typer, docstrings determine the description of each argument in the help text, instead of having to individually add extra type annotations. This allows for a very non-intrusive design, you can adopt (or un-adopt) **Startle** with no changes to your functions.\n- `*args` but also `**kwargs` are supported, to parse unknown arguments as well as unknown options (`--unk-key unk-val`).\n  See [example](https://github.com/oir/startle/blob/main/examples/search_gh.py).\n\nSee all [examples](https://github.com/oir/startle/tree/main/examples),\nor the [documentation](https://oir.github.io/startle/) for more.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foir%2Fstartle","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Foir%2Fstartle","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foir%2Fstartle/lists"}