{"id":16346233,"url":"https://github.com/jorenham/mainpy","last_synced_at":"2025-03-20T23:32:47.111Z","repository":{"id":57439296,"uuid":"477167322","full_name":"jorenham/mainpy","owner":"jorenham","description":"Simplify your project's main entrypoint definition with @main","archived":false,"fork":false,"pushed_at":"2024-10-03T12:36:08.000Z","size":315,"stargazers_count":6,"open_issues_count":3,"forks_count":2,"subscribers_count":4,"default_branch":"main","last_synced_at":"2024-10-12T00:34:58.419Z","etag":null,"topics":["asyncio","python","python-3"],"latest_commit_sha":null,"homepage":"https://pypi.org/project/mainpy/","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/jorenham.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"jorenham"}},"created_at":"2022-04-02T20:44:57.000Z","updated_at":"2024-10-01T14:18:37.000Z","dependencies_parsed_at":"2024-02-29T02:45:28.638Z","dependency_job_id":"fd62a28c-b2ff-40ce-afb6-ac1f68eaf5a1","html_url":"https://github.com/jorenham/mainpy","commit_stats":{"total_commits":3,"total_committers":1,"mean_commits":3.0,"dds":0.0,"last_synced_commit":"fac2f50b6ee14fc05a4d8db2114407a57ae311c3"},"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jorenham%2Fmainpy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jorenham%2Fmainpy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jorenham%2Fmainpy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jorenham%2Fmainpy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jorenham","download_url":"https://codeload.github.com/jorenham/mainpy/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":221810220,"owners_count":16884070,"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":["asyncio","python","python-3"],"created_at":"2024-10-11T00:34:50.933Z","updated_at":"2025-03-20T23:32:47.105Z","avatar_url":"https://github.com/jorenham.png","language":"Python","funding_links":["https://github.com/sponsors/jorenham"],"categories":[],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003e\u003ccode\u003e@main\u003c/code\u003e.py\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n    \u003ca href=\"https://pypi.org/project/mainpy/\"\u003e\n        \u003cimg\n            alt=\"mainpy - PyPI\"\n            src=\"https://img.shields.io/pypi/v/mainpy?style=flat\"\n        /\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://github.com/jorenham/mainpy\"\u003e\n        \u003cimg\n            alt=\"mainpy - Python Versions\"\n            src=\"https://img.shields.io/pypi/pyversions/mainpy?style=flat\"\n        /\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://github.com/jorenham/mainpy\"\u003e\n        \u003cimg\n            alt=\"mainpy - license\"\n            src=\"https://img.shields.io/github/license/jorenham/mainpy?style=flat\"\n        /\u003e\n    \u003c/a\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n    \u003ca href=\"https://github.com/jorenham/mainpy/actions?query=workflow%3ACI\"\u003e\n        \u003cimg\n            alt=\"mainpy - CI\"\n            src=\"https://github.com/jorenham/mainpy/workflows/CI/badge.svg\"\n        /\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://github.com/jorenham/mainpy\"\u003e\n        \u003cimg\n            alt=\"scipy-stubs - typed\"\n            src=\"https://img.shields.io/pypi/types/mainpy?color=blue\u0026style=flat\"\n        /\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://github.com/KotlinIsland/basedmypy\"\u003e\n        \u003cimg\n            alt=\"mainpy - basedmypy\"\n            src=\"https://img.shields.io/badge/basedmypy-checked-fd9002\"\n        /\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://detachhead.github.io/basedpyright\"\u003e\n        \u003cimg\n            alt=\"mainpy - basedpyright\"\n            src=\"https://img.shields.io/badge/basedpyright-checked-42b983\"\n        /\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://github.com/astral-sh/ruff\"\u003e\n        \u003cimg\n            alt=\"mainpy - ruff\"\n            src=\"https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json\"\n        /\u003e\n    \u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n## Basic Examples\n\nWith `mainpy`, there's no need to write `if __name__ == '__main__'` the\nboilerplate anymore:\n\n\u003ctable\u003e\n\u003ctr\u003e\n\u003cth width=\"415px\"\u003ewithout \u003ccode\u003emainpy\u003c/code\u003e\u003c/th\u003e\n\u003cth width=\"415px\"\u003ewith \u003ccode\u003emainpy\u003c/code\u003e\u003c/th\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd width=\"415px\"\u003e\n\n```python\nif __name__ == '__main__':\n    app()\n\ndef app(): ...\n```\n\n\u003c/td\u003e\n\u003ctd width=\"415px\"\u003e\n\n```python\nfrom mainpy import main\n\n@main\ndef app(): ...\n```\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\nFor async apps, the improvement becomes even more obvious:\n\n\u003ctable\u003e\n\u003ctr\u003e\n\u003cth width=\"415px\"\u003ewithout \u003ccode\u003emainpy\u003c/code\u003e\u003c/th\u003e\n\u003cth width=\"415px\"\u003ewith \u003ccode\u003emainpy\u003c/code\u003e\u003c/th\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd width=\"415px\"\u003e\n\n```python\nimport asyncio\n\nasync def async_app(): ...\n\nif __name__ == '__main__':\n    with asyncio.Runner() as runner:\n        runner.run(async_app())\n```\n\n\u003c/td\u003e\n\u003ctd width=\"415px\"\u003e\n\n```python\nfrom mainpy import main\n\n@main\nasync def async_app(): ...\n```\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\n## External Libraries\n\nEven though `mainpy` requires no other dependencies than `typing_extensions`\n(on Python \u003c 3.10), it has optional support for [`uvloop`][UVLOOP], and plays\nnicely with popular CLI libraries, e.g. [`click`][CLICK] and [`typer`][TYPER].\n\n### `uvloop`\n\nIf you have [uvloop][UVLOOP] installed, mainpy will automatically call\n`uvloop.install()` before running your async main function.\nThis can be disabled by setting `use_uvloop=False`, e.g.:\n\n```python\n@main(use_uvloop=False)\nasync def app(): ...\n```\n\n### Click\n\nWith [`click`][CLICK] you can simply add the decorator as usual.\n\n\u003e [!IMPORTANT]\n\u003e The `@mainpy.main` decorator must come *before* `@click.command()`.\n\n```python\nimport mainpy\nimport click\n\n@mainpy.main\n@click.command()\ndef click_command():\n    click.echo('Hello from click_command')\n```\n\nThe function that is decorated with `@mainpy.main` is executed immediately.\nBut a `@click.group` must be defined *before* the command function.\nIn this case, `mainpy.main` should be called *after* all has been setup:\n\n```python\nimport mainpy\nimport click\n\n@click.group()\ndef group(): ...\n\n@group.command()\ndef command(): ...\n\nmainpy.main(group)\n```\n\n### Typer\n\nA [`typer`][TYPER] internally does some initialization after a command\nhas been defined.\nInstead of using `@mainpy.main` on the command itself, you should use\n`mainpy.main()` manually:\n\n```python\nimport mainpy\nimport typer\n\napp = typer.Typer()\n\n@app.command()\ndef command():\n    typer.echo('typer.Typer()')\n\nmainpy.main(command)\n```\n\n## Debug mode\n\nOptionally, Python's [development mode][DEVMODE] can be emulated by passing\n`debug=True` to `mainpy.main`. This does three things:\n\n- Enable the [faulthandler][FAULTHANDLER]\n- Configure [`warnings`][WARNINGS] to display all warnings\n- Runs `async` functions in [debug mode][ADEBUG]\n\n```python\n@main(debug=True)\ndef app(): ...\n```\n\n## Installation\n\nThe `mainpy` package is available on [pypi][PYPI] for Python $\\ge 3.9$:\n\n```shell\npip install mainpy\n```\n\nAdditionally, you can install the [`uvloop`][UVLOOP] extra which will install\n`uvloop\u003e=0.15.2` (unless you're on windows):\n\n```shell\npip install mainpy[uvloop]\n```\n\n[PYPI]: https://pypi.org/project/mainpy/\n[UVLOOP]: https://github.com/MagicStack/uvloop\n[CLICK]: https://github.com/pallets/click\n[TYPER]: https://github.com/tiangolo/typer\n[DEVMODE]: https://docs.python.org/3/library/devmode.html\n[FAULTHANDLER]: https://docs.python.org/3/library/faulthandler.html\n[WARNINGS]: https://docs.python.org/3/library/warnings.html\n[ADEBUG]: https://docs.python.org/3/library/asyncio-dev.html#asyncio-debug-mode\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjorenham%2Fmainpy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjorenham%2Fmainpy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjorenham%2Fmainpy/lists"}