{"id":31079596,"url":"https://github.com/welchbj/almanac","last_synced_at":"2025-09-16T10:28:10.731Z","repository":{"id":42861814,"uuid":"193141053","full_name":"welchbj/almanac","owner":"welchbj","description":"a framework for interactive, page-based console applications","archived":false,"fork":false,"pushed_at":"2022-12-08T14:28:58.000Z","size":469,"stargazers_count":6,"open_issues_count":5,"forks_count":2,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-08-24T12:51:45.778Z","etag":null,"topics":["asyncio","console-framework","python-prompt-toolkit"],"latest_commit_sha":null,"homepage":"https://almanac.brianwel.ch","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/welchbj.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-06-21T18:07:22.000Z","updated_at":"2023-06-08T07:41:52.000Z","dependencies_parsed_at":"2023-01-25T14:00:57.319Z","dependency_job_id":null,"html_url":"https://github.com/welchbj/almanac","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/welchbj/almanac","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/welchbj%2Falmanac","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/welchbj%2Falmanac/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/welchbj%2Falmanac/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/welchbj%2Falmanac/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/welchbj","download_url":"https://codeload.github.com/welchbj/almanac/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/welchbj%2Falmanac/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":275403933,"owners_count":25458812,"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-09-16T02:00:10.229Z","response_time":65,"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":["asyncio","console-framework","python-prompt-toolkit"],"created_at":"2025-09-16T10:28:06.512Z","updated_at":"2025-09-16T10:28:10.723Z","avatar_url":"https://github.com/welchbj.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg width=\"600\" height=\"162\" src=\"https://github.com/welchbj/almanac/blob/devel/docs/_static/logo.png?raw=true\" alt=\"almanac logo\"\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n  \u003cem\u003ea framework for interactive, page-based console applications\u003c/em\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://travis-ci.org/welchbj/almanac\"\u003e\n    \u003cimg src=\"https://img.shields.io/travis/welchbj/almanac/devel.svg?style=flat-square\u0026label=linux%20build\" alt=\"linux build status\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://ci.appveyor.com/project/welchbj/almanac\"\u003e\n    \u003cimg src=\"https://img.shields.io/appveyor/ci/welchbj/almanac/devel.svg?style=flat-square\u0026label=windows%20build\" alt=\"windows build status\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://pypi.org/project/almanac/\"\u003e\n    \u003cimg src=\"https://img.shields.io/pypi/v/almanac.svg?style=flat-square\u0026label=pypi\" alt=\"pypi\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://www.python.org/\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/python-3.9+-b042f4.svg?style=flat-square\" alt=\"python version\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n## Synopsis\n\nThe `almanac` framework aims to serve as an intuitive interface for spinning up interactive, page-based console applications. Think of it as a Python metaprogramming layer on top of [Python Prompt Toolkit](https://github.com/prompt-toolkit/python-prompt-toolkit) and [Pygments](https://pygments.org/).\n\n## Example\n\n`almanac` turns this:\n\n```python\n\"\"\"Welcome to a simple interactive HTTP client.\n\nThe current URL to request is the application's current path. Directories will be\ncreated as you cd into them.\n\"\"\"\n\nimport aiohttp\nimport asyncio\n\nfrom almanac import highlight_for_mimetype, make_standard_app, PagePath\n\napp = make_standard_app()\n\n\n@app.on_init()\nasync def runs_at_start_up():\n    app.io.raw(__doc__)\n\n    app.bag.session = aiohttp.ClientSession()\n    app.io.info('Session opened!')\n\n\n@app.on_exit()\nasync def runs_at_shut_down():\n    await app.bag.session.close()\n    app.io.info('Session closed!')\n\n\n@app.prompt_text()\ndef custom_prompt():\n    stripped_path = str(app.page_navigator.current_page.path).lstrip('/')\n    return f'{stripped_path}\u003e '\n\n\n@app.hook.before('cd')\nasync def cd_hook_before(path: PagePath):\n    if path not in app.page_navigator:\n        app.page_navigator.add_directory_page(path)\n\n\n@app.hook.exception(aiohttp.ClientError)\nasync def handle_aiohttp_errors(exc: aiohttp.ClientError):\n    app.io.error(f'{exc.__class__.__name__}: {str(exc)}')\n\n\n@app.cmd.register()\n@app.arg.method(choices=['GET', 'POST', 'PUT'], description='HTTP verb for request.')\n@app.arg.proto(choices=['http', 'https'], description='Protocol for request.')\nasync def request(method: str, *, proto: str = 'https', **params: str):\n    \"\"\"Send an HTTP or HTTPS request.\"\"\"\n    path = str(app.current_path).lstrip('/')\n    url = f'{proto}://{path}'\n    app.io.info(f'Sending {method} request to {url}...')\n\n    resp = await app.bag.session.request(method, url, params=params)\n    async with resp:\n        text = await resp.text()\n        highlighted_text = highlight_for_mimetype(text, resp.content_type)\n\n        app.io.info(f'Status {resp.status} response from {resp.url}')\n        app.io.info('Here\\'s the content:')\n        app.io.ansi(highlighted_text)\n\n\nif __name__ == '__main__':\n    asyncio.run(app.prompt())\n```\n\nInto this:\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://asciinema.org/a/352061?autoplay=1\u0026speed=1.5\"\u003e\n    \u003cimg src=\"https://asciinema.org/a/352061.png\" width=\"750\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n## Installation\n\nYou can download the latest packaged version from PyPI:\n\n```sh\npip install almanac\n```\n\n## License\n\nThe original content of this repository is licensed under the [MIT License](https://opensource.org/licenses/MIT), as per the [`LICENSE.txt`](./LICENSE.txt) file.\n\nSome of the parsing logic is borrowed from the [python-nubia](https://github.com/facebookincubator/python-nubia) project and is licensed under that project's [BSD License](https://github.com/facebookincubator/python-nubia/blob/master/LICENSE). For more information, please see the comment in [`almanac/parsing/parsing.py`](almanac/parsing/parsing.py).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwelchbj%2Falmanac","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwelchbj%2Falmanac","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwelchbj%2Falmanac/lists"}