{"id":17477713,"url":"https://github.com/wheelodex/headerparser","last_synced_at":"2025-04-12T19:53:23.059Z","repository":{"id":43703195,"uuid":"80020669","full_name":"wheelodex/headerparser","owner":"wheelodex","description":"argparse for mail-style headers","archived":false,"fork":false,"pushed_at":"2025-04-07T13:12:49.000Z","size":317,"stargazers_count":6,"open_issues_count":48,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-12T19:53:17.669Z","etag":null,"topics":["available-on-pypi","e-mail","email","headers","mail","parser","python","rfc2822","rfc5322","rfc822"],"latest_commit_sha":null,"homepage":"","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/wheelodex.png","metadata":{"files":{"readme":"README.rst","changelog":"CHANGELOG.md","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":"2017-01-25T14:14:33.000Z","updated_at":"2025-02-01T18:54:59.000Z","dependencies_parsed_at":"2023-10-01T16:42:21.265Z","dependency_job_id":"51e498e8-3230-4f89-ae22-8fa2c9878277","html_url":"https://github.com/wheelodex/headerparser","commit_stats":{"total_commits":239,"total_committers":2,"mean_commits":119.5,"dds":"0.012552301255230103","last_synced_commit":"e25f5a8749c7f3581a579567a86c9d644666543d"},"previous_names":["wheelodex/headerparser","jwodder/headerparser"],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wheelodex%2Fheaderparser","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wheelodex%2Fheaderparser/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wheelodex%2Fheaderparser/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wheelodex%2Fheaderparser/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wheelodex","download_url":"https://codeload.github.com/wheelodex/headerparser/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248625509,"owners_count":21135513,"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":["available-on-pypi","e-mail","email","headers","mail","parser","python","rfc2822","rfc5322","rfc822"],"created_at":"2024-10-18T20:09:09.402Z","updated_at":"2025-04-12T19:53:23.032Z","avatar_url":"https://github.com/wheelodex.png","language":"Python","readme":"|repostatus| |ci-status| |coverage| |pyversions| |license|\n\n.. |repostatus| image:: https://www.repostatus.org/badges/latest/active.svg\n    :target: https://www.repostatus.org/#active\n    :alt: Project Status: Active — The project has reached a stable, usable\n          state and is being actively developed.\n\n.. |ci-status| image:: https://github.com/wheelodex/headerparser/actions/workflows/test.yml/badge.svg\n    :target: https://github.com/wheelodex/headerparser/actions/workflows/test.yml\n    :alt: CI Status\n\n.. |coverage| image:: https://codecov.io/gh/wheelodex/headerparser/branch/master/graph/badge.svg\n    :target: https://codecov.io/gh/wheelodex/headerparser\n\n.. |pyversions| image:: https://img.shields.io/pypi/pyversions/headerparser.svg\n    :target: https://pypi.org/project/headerparser\n\n.. |license| image:: https://img.shields.io/github/license/wheelodex/headerparser.svg\n    :target: https://opensource.org/licenses/MIT\n    :alt: MIT License\n\n`GitHub \u003chttps://github.com/wheelodex/headerparser\u003e`_\n| `PyPI \u003chttps://pypi.org/project/headerparser\u003e`_\n| `Documentation \u003chttps://headerparser.readthedocs.io\u003e`_\n| `Issues \u003chttps://github.com/wheelodex/headerparser/issues\u003e`_\n| `Changelog \u003chttps://github.com/wheelodex/headerparser/blob/master/CHANGELOG.md\u003e`_\n\n``headerparser`` parses key-value pairs in the style of RFC 822 (e-mail)\nheaders and converts them into case-insensitive dictionaries with the trailing\nmessage body (if any) attached.  Fields can be converted to other types, marked\nrequired, or given default values using an API based on the standard library's\n``argparse`` module.  (Everyone loves ``argparse``, right?)  Low-level\nfunctions for just scanning header fields (breaking them into sequences of\nkey-value pairs without any further processing) are also included.\n\nThe Format\n==========\nRFC 822-style headers are header fields that follow the general format of\ne-mail headers as specified by RFC 822 and friends: each field is a line of the\nform \"``Name: Value``\", with long values continued onto multiple lines\n(\"folded\") by indenting the extra lines.  A blank line marks the end of the\nheader section and the beginning of the message body.\n\nThis basic grammar has been used by numerous textual formats besides e-mail,\nincluding but not limited to:\n\n- HTTP request \u0026 response headers\n- Usenet messages\n- most Python packaging metadata files\n- Debian packaging control files\n- ``META-INF/MANIFEST.MF`` files in Java JARs\n- a subset of the `YAML \u003chttp://www.yaml.org/\u003e`_ serialization format\n\n— all of which this package can parse.\n\n\nInstallation\n============\n``headerparser`` requires Python 3.8 or higher.  Just use `pip\n\u003chttps://pip.pypa.io\u003e`_ for Python 3 (You have pip, right?) to install\n``headerparser``::\n\n    python3 -m pip install headerparser\n\n\nExamples\n========\n\nDefine a parser:\n\n\u003e\u003e\u003e import headerparser\n\u003e\u003e\u003e parser = headerparser.HeaderParser()\n\u003e\u003e\u003e parser.add_field('Name', required=True)\n\u003e\u003e\u003e parser.add_field('Type', choices=['example', 'demonstration', 'prototype'], default='example')\n\u003e\u003e\u003e parser.add_field('Public', type=headerparser.BOOL, default=False)\n\u003e\u003e\u003e parser.add_field('Tag', multiple=True)\n\u003e\u003e\u003e parser.add_field('Data')\n\nParse some headers and inspect the results:\n\n\u003e\u003e\u003e msg = parser.parse('''\\\n... Name: Sample Input\n... Public: yes\n... tag: doctest, examples,\n...   whatever\n... TAG: README\n...\n... Wait, why I am using a body instead of the \"Data\" field?\n... ''')\n\u003e\u003e\u003e sorted(msg.keys())\n['Name', 'Public', 'Tag', 'Type']\n\u003e\u003e\u003e msg['Name']\n'Sample Input'\n\u003e\u003e\u003e msg['Public']\nTrue\n\u003e\u003e\u003e msg['Tag']\n['doctest, examples,\\n  whatever', 'README']\n\u003e\u003e\u003e msg['TYPE']\n'example'\n\u003e\u003e\u003e msg['Data']\nTraceback (most recent call last):\n    ...\nKeyError: 'data'\n\u003e\u003e\u003e msg.body\n'Wait, why I am using a body instead of the \"Data\" field?\\n'\n\nFail to parse headers that don't meet your requirements:\n\n\u003e\u003e\u003e parser.parse('Type: demonstration')\nTraceback (most recent call last):\n    ...\nheaderparser.errors.MissingFieldError: Required header field 'Name' is not present\n\u003e\u003e\u003e parser.parse('Name: Bad type\\nType: other')\nTraceback (most recent call last):\n    ...\nheaderparser.errors.InvalidChoiceError: 'other' is not a valid choice for 'Type'\n\u003e\u003e\u003e parser.parse('Name: unknown field\\nField: Value')\nTraceback (most recent call last):\n    ...\nheaderparser.errors.UnknownFieldError: Unknown header field 'Field'\n\nAllow fields you didn't even think of:\n\n\u003e\u003e\u003e parser.add_additional()\n\u003e\u003e\u003e msg = parser.parse('Name: unknown field\\nField: Value')\n\u003e\u003e\u003e msg['Field']\n'Value'\n\nJust split some headers into names \u0026 values and worry about validity later:\n\n\u003e\u003e\u003e for field in headerparser.scan('''\\\n... Name: Scanner Sample\n... Unknown headers: no problem\n... Unparsed-Boolean: yes\n... CaSe-SeNsItIvE-rEsUlTs: true\n... Whitespace around colons:optional\n... Whitespace around colons  :  I already said it's optional.\n...   That means you have the _option_ to use as much as you want!\n...\n... And there's a body, too, I guess.\n... '''): print(field)\n('Name', 'Scanner Sample')\n('Unknown headers', 'no problem')\n('Unparsed-Boolean', 'yes')\n('CaSe-SeNsItIvE-rEsUlTs', 'true')\n('Whitespace around colons', 'optional')\n('Whitespace around colons', \"I already said it's optional.\\n  That means you have the _option_ to use as much as you want!\")\n(None, \"And there's a body, too, I guess.\\n\")\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwheelodex%2Fheaderparser","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwheelodex%2Fheaderparser","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwheelodex%2Fheaderparser/lists"}