headerparser


Nameheaderparser JSON
Version 0.5.2 PyPI version JSON
download
home_pageNone
Summaryargparse for mail-style headers
upload_time2024-12-01 12:43:08
maintainerNone
docs_urlNone
authorNone
requires_python>=3.8
licenseMIT
keywords e-mail email headers mail parser rfc2822 rfc5322 rfc822
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            |repostatus| |ci-status| |coverage| |pyversions| |license|

.. |repostatus| image:: https://www.repostatus.org/badges/latest/active.svg
    :target: https://www.repostatus.org/#active
    :alt: Project Status: Active — The project has reached a stable, usable
          state and is being actively developed.

.. |ci-status| image:: https://github.com/wheelodex/headerparser/actions/workflows/test.yml/badge.svg
    :target: https://github.com/wheelodex/headerparser/actions/workflows/test.yml
    :alt: CI Status

.. |coverage| image:: https://codecov.io/gh/wheelodex/headerparser/branch/master/graph/badge.svg
    :target: https://codecov.io/gh/wheelodex/headerparser

.. |pyversions| image:: https://img.shields.io/pypi/pyversions/headerparser.svg
    :target: https://pypi.org/project/headerparser

.. |license| image:: https://img.shields.io/github/license/wheelodex/headerparser.svg
    :target: https://opensource.org/licenses/MIT
    :alt: MIT License

`GitHub <https://github.com/wheelodex/headerparser>`_
| `PyPI <https://pypi.org/project/headerparser>`_
| `Documentation <https://headerparser.readthedocs.io>`_
| `Issues <https://github.com/wheelodex/headerparser/issues>`_
| `Changelog <https://github.com/wheelodex/headerparser/blob/master/CHANGELOG.md>`_

``headerparser`` parses key-value pairs in the style of RFC 822 (e-mail)
headers and converts them into case-insensitive dictionaries with the trailing
message body (if any) attached.  Fields can be converted to other types, marked
required, or given default values using an API based on the standard library's
``argparse`` module.  (Everyone loves ``argparse``, right?)  Low-level
functions for just scanning header fields (breaking them into sequences of
key-value pairs without any further processing) are also included.

The Format
==========
RFC 822-style headers are header fields that follow the general format of
e-mail headers as specified by RFC 822 and friends: each field is a line of the
form "``Name: Value``", with long values continued onto multiple lines
("folded") by indenting the extra lines.  A blank line marks the end of the
header section and the beginning of the message body.

This basic grammar has been used by numerous textual formats besides e-mail,
including but not limited to:

- HTTP request & response headers
- Usenet messages
- most Python packaging metadata files
- Debian packaging control files
- ``META-INF/MANIFEST.MF`` files in Java JARs
- a subset of the `YAML <http://www.yaml.org/>`_ serialization format

— all of which this package can parse.


Installation
============
``headerparser`` requires Python 3.8 or higher.  Just use `pip
<https://pip.pypa.io>`_ for Python 3 (You have pip, right?) to install
``headerparser``::

    python3 -m pip install headerparser


Examples
========

Define a parser:

>>> import headerparser
>>> parser = headerparser.HeaderParser()
>>> parser.add_field('Name', required=True)
>>> parser.add_field('Type', choices=['example', 'demonstration', 'prototype'], default='example')
>>> parser.add_field('Public', type=headerparser.BOOL, default=False)
>>> parser.add_field('Tag', multiple=True)
>>> parser.add_field('Data')

Parse some headers and inspect the results:

>>> msg = parser.parse('''\
... Name: Sample Input
... Public: yes
... tag: doctest, examples,
...   whatever
... TAG: README
...
... Wait, why I am using a body instead of the "Data" field?
... ''')
>>> sorted(msg.keys())
['Name', 'Public', 'Tag', 'Type']
>>> msg['Name']
'Sample Input'
>>> msg['Public']
True
>>> msg['Tag']
['doctest, examples,\n  whatever', 'README']
>>> msg['TYPE']
'example'
>>> msg['Data']
Traceback (most recent call last):
    ...
KeyError: 'data'
>>> msg.body
'Wait, why I am using a body instead of the "Data" field?\n'

Fail to parse headers that don't meet your requirements:

>>> parser.parse('Type: demonstration')
Traceback (most recent call last):
    ...
headerparser.errors.MissingFieldError: Required header field 'Name' is not present
>>> parser.parse('Name: Bad type\nType: other')
Traceback (most recent call last):
    ...
headerparser.errors.InvalidChoiceError: 'other' is not a valid choice for 'Type'
>>> parser.parse('Name: unknown field\nField: Value')
Traceback (most recent call last):
    ...
headerparser.errors.UnknownFieldError: Unknown header field 'Field'

Allow fields you didn't even think of:

>>> parser.add_additional()
>>> msg = parser.parse('Name: unknown field\nField: Value')
>>> msg['Field']
'Value'

Just split some headers into names & values and worry about validity later:

>>> for field in headerparser.scan('''\
... Name: Scanner Sample
... Unknown headers: no problem
... Unparsed-Boolean: yes
... CaSe-SeNsItIvE-rEsUlTs: true
... Whitespace around colons:optional
... Whitespace around colons  :  I already said it's optional.
...   That means you have the _option_ to use as much as you want!
...
... And there's a body, too, I guess.
... '''): print(field)
('Name', 'Scanner Sample')
('Unknown headers', 'no problem')
('Unparsed-Boolean', 'yes')
('CaSe-SeNsItIvE-rEsUlTs', 'true')
('Whitespace around colons', 'optional')
('Whitespace around colons', "I already said it's optional.\n  That means you have the _option_ to use as much as you want!")
(None, "And there's a body, too, I guess.\n")

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "headerparser",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": null,
    "keywords": "e-mail, email, headers, mail, parser, rfc2822, rfc5322, rfc822",
    "author": null,
    "author_email": "John Thorvald Wodder II <headerparser@varonathe.org>",
    "download_url": "https://files.pythonhosted.org/packages/86/97/ecdbe764cb2909999ca51db3a76852aaba4f938c309c41b86014c90a8d4b/headerparser-0.5.2.tar.gz",
    "platform": null,
    "description": "|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 \u2014 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 <https://github.com/wheelodex/headerparser>`_\n| `PyPI <https://pypi.org/project/headerparser>`_\n| `Documentation <https://headerparser.readthedocs.io>`_\n| `Issues <https://github.com/wheelodex/headerparser/issues>`_\n| `Changelog <https://github.com/wheelodex/headerparser/blob/master/CHANGELOG.md>`_\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 & 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 <http://www.yaml.org/>`_ serialization format\n\n\u2014 all of which this package can parse.\n\n\nInstallation\n============\n``headerparser`` requires Python 3.8 or higher.  Just use `pip\n<https://pip.pypa.io>`_ 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>>> import headerparser\n>>> parser = headerparser.HeaderParser()\n>>> parser.add_field('Name', required=True)\n>>> parser.add_field('Type', choices=['example', 'demonstration', 'prototype'], default='example')\n>>> parser.add_field('Public', type=headerparser.BOOL, default=False)\n>>> parser.add_field('Tag', multiple=True)\n>>> parser.add_field('Data')\n\nParse some headers and inspect the results:\n\n>>> 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>>> sorted(msg.keys())\n['Name', 'Public', 'Tag', 'Type']\n>>> msg['Name']\n'Sample Input'\n>>> msg['Public']\nTrue\n>>> msg['Tag']\n['doctest, examples,\\n  whatever', 'README']\n>>> msg['TYPE']\n'example'\n>>> msg['Data']\nTraceback (most recent call last):\n    ...\nKeyError: 'data'\n>>> 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>>> parser.parse('Type: demonstration')\nTraceback (most recent call last):\n    ...\nheaderparser.errors.MissingFieldError: Required header field 'Name' is not present\n>>> 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>>> 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>>> parser.add_additional()\n>>> msg = parser.parse('Name: unknown field\\nField: Value')\n>>> msg['Field']\n'Value'\n\nJust split some headers into names & values and worry about validity later:\n\n>>> 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",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "argparse for mail-style headers",
    "version": "0.5.2",
    "project_urls": {
        "Bug Tracker": "https://github.com/wheelodex/headerparser/issues",
        "Documentation": "https://headerparser.readthedocs.io",
        "Source Code": "https://github.com/wheelodex/headerparser"
    },
    "split_keywords": [
        "e-mail",
        " email",
        " headers",
        " mail",
        " parser",
        " rfc2822",
        " rfc5322",
        " rfc822"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "0f879b5b7eb8eade5d5c5357b19ced4b719c0c0815089c5dc0e9a68cd3b8ff5c",
                "md5": "a9d5985f29b1f957882ad7f529b6e778",
                "sha256": "e89d35c8cfe494f7fdec6eff14b4a9d5542fc2b2b8f1b50d750b62d822d0b8d6"
            },
            "downloads": -1,
            "filename": "headerparser-0.5.2-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "a9d5985f29b1f957882ad7f529b6e778",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8",
            "size": 18120,
            "upload_time": "2024-12-01T12:43:00",
            "upload_time_iso_8601": "2024-12-01T12:43:00.450315Z",
            "url": "https://files.pythonhosted.org/packages/0f/87/9b5b7eb8eade5d5c5357b19ced4b719c0c0815089c5dc0e9a68cd3b8ff5c/headerparser-0.5.2-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "8697ecdbe764cb2909999ca51db3a76852aaba4f938c309c41b86014c90a8d4b",
                "md5": "a1743cf84b081f01f6c4069e87c8a163",
                "sha256": "2e24ae218ed5d2ef5839fafeff084c40ee1e317bbbe6489cfe333385d7cb98e7"
            },
            "downloads": -1,
            "filename": "headerparser-0.5.2.tar.gz",
            "has_sig": false,
            "md5_digest": "a1743cf84b081f01f6c4069e87c8a163",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8",
            "size": 31063,
            "upload_time": "2024-12-01T12:43:08",
            "upload_time_iso_8601": "2024-12-01T12:43:08.144504Z",
            "url": "https://files.pythonhosted.org/packages/86/97/ecdbe764cb2909999ca51db3a76852aaba4f938c309c41b86014c90a8d4b/headerparser-0.5.2.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-12-01 12:43:08",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "wheelodex",
    "github_project": "headerparser",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "tox": true,
    "lcname": "headerparser"
}
        
Elapsed time: 0.44053s