{"id":13935743,"url":"https://github.com/jawah/kiss-headers","last_synced_at":"2025-12-25T14:52:29.030Z","repository":{"id":42041753,"uuid":"247530380","full_name":"jawah/kiss-headers","owner":"jawah","description":"Python package for HTTP/1.1 style headers. Parse headers to objects. Most advanced available structure for http headers.","archived":false,"fork":false,"pushed_at":"2025-07-01T19:27:09.000Z","size":1785,"stargazers_count":116,"open_issues_count":2,"forks_count":8,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-07-05T09:14:50.522Z","etag":null,"topics":["cookie","cookies","email-parsing","header","header-only","header-parser","headers","http","http-headers","parser","python","requests"],"latest_commit_sha":null,"homepage":"https://jawah.github.io/kiss-headers/","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/jawah.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"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,"zenodo":null}},"created_at":"2020-03-15T18:50:14.000Z","updated_at":"2025-05-05T05:17:36.000Z","dependencies_parsed_at":"2024-01-19T09:23:14.228Z","dependency_job_id":"ee29b24c-34bc-4551-bf00-bce2330f2b5c","html_url":"https://github.com/jawah/kiss-headers","commit_stats":{"total_commits":417,"total_committers":4,"mean_commits":104.25,"dds":0.0767386091127098,"last_synced_commit":"ca39a55ba811f2f202604f8cda22bac0c57ec978"},"previous_names":["jawah/kiss-headers","ousret/kiss-headers"],"tags_count":28,"template":false,"template_full_name":null,"purl":"pkg:github/jawah/kiss-headers","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jawah%2Fkiss-headers","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jawah%2Fkiss-headers/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jawah%2Fkiss-headers/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jawah%2Fkiss-headers/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jawah","download_url":"https://codeload.github.com/jawah/kiss-headers/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jawah%2Fkiss-headers/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266019657,"owners_count":23864916,"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":["cookie","cookies","email-parsing","header","header-only","header-parser","headers","http","http-headers","parser","python","requests"],"created_at":"2024-08-07T23:02:03.433Z","updated_at":"2025-12-25T14:52:28.982Z","avatar_url":"https://github.com/jawah.png","language":"Python","funding_links":[],"categories":["Python"],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003eHTTP Headers, the Complete Toolkit 🧰 \u003ca href=\"https://twitter.com/intent/tweet?text=Python%20library%20for%20oriented%20object%20HTTP%20style%20headers.\u0026url=https://www.github.com/jawah/kiss-headers\u0026hashtags=python,headers,opensource\"\u003e\u003cimg src=\"https://img.shields.io/twitter/url/http/shields.io.svg?style=social\"/\u003e\u003c/a\u003e\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003csup\u003eObject-oriented headers. Kind of structured headers.\u003c/sup\u003e\u003cbr\u003e\n  \u003ca href='https://pypi.org/project/kiss-headers/'\u003e\n     \u003cimg src=\"https://img.shields.io/pypi/pyversions/kiss-headers.svg?orange=blue\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://codecov.io/gh/Ousret/kiss-headers\"\u003e\n      \u003cimg src=\"https://codecov.io/gh/Ousret/kiss-headers/branch/master/graph/badge.svg\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://pepy.tech/project/kiss-headers/\"\u003e\n     \u003cimg alt=\"Download Count Total\" src=\"https://pepy.tech/badge/kiss-headers\" /\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n### ❓ Why\n\nNo matter if you are currently dealing with code using HTTP or IMAP _(message, email)_, you should not worry about easily accessing and exploiting headers.\n\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"https://user-images.githubusercontent.com/9326700/77257881-55866300-6c77-11ea-820c-7550e6bdeee7.gif\" alt=\"using kiss-headers from python interpreter\"/\u003e\n\u003c/p\u003e\n\nI have seen so many chunks of code trying to deal with these headers; often I saw this implementation:\n```python\n# No more of that!\ncharset = headers['Content-Type'].split(';')[-1].split('=')[-1].replace('\"', '')\n# That too..\nresponse = get(\n    \"https://httpbin.org/headers\",\n    headers={\n        \"user-agent\": \"custom/2.22\",\n        \"referer\": \"https://www.google.com\",\n        \"accept\": \"text/html\",\n        \"accept-language\": \"en-US\",\n        \"custom-header-xyz\": \"hello; charset=utf-8\"\n    }\n)\n```\n\n**Scroll down and see how you could do it from now on.**\n\n## 🔪 Features\n\n`kiss-headers` is a basic library that allow you to handle headers as objects.\n\n* A backwards-compatible syntax using bracket style.\n* Capability to alter headers using simple, human-readable operator notation `+` and `-`.\n* Flexibility if headers are from an email or HTTP, use as you need with one library.\n* Ability to parse any object and extract recognized headers from it, it also supports UTF-8 encoded headers.\n* Offer an opinionated way to un/serialize headers.\n* Fully type-annotated.\n* Provide great auto-completion in Python interpreter or any capable IDE.\n* No dependencies. Never will be.\n* Support JSON in header value.\n* 90% test coverage.\n\nPlus all the features that you would expect from handling headers...\n\n* Properties syntax for headers and attribute in a header.\n* Supports headers and attributes OneToOne, OneToMany and ManySquashedIntoOne.\n* Capable of parsing `bytes`, `fp`, `str`, `dict`, `email.Message`, `requests.Response`, `niquests.Response`, `httpx._models.Response` and `urllib3.HTTPResponse`.\n* Automatically unquote and unfold the value of an attribute when retrieving it.\n* Keep headers and attributes ordering.\n* Case-insensitive with header name and attribute key.\n* Character `-` equal `_` in addition of above feature.\n* Any syntax you like, we like.\n\n### ✨ Installation\n\nWhatever you like, use `pipenv` or `pip`, it simply works. Requires Python 3.7+ installed.\n```sh\npip install kiss-headers --upgrade\n```\n\nThis project is included in [Niquests](https://github.com/jawah/niquests)! Your awesome drop-in replacement for Requests!\n\n### 🍰 Usage\n\n#### Quick start\n`parse_it()` method takes `bytes`, `str`, `fp`, `dict`, `email.Message` or even a `requests.Response` or `httpx._models.Response` itself and returns a `Headers` object.\n\n```python\nfrom requests import get\nfrom kiss_headers import parse_it\n\nresponse = get('https://www.google.fr')\nheaders = parse_it(response)\n\nheaders.content_type.charset  # output: ISO-8859-1\n# Its the same as\nheaders[\"content-type\"][\"charset\"]  # output: ISO-8859-1\n```\n\nand also, the other way around:\n\n```python\nfrom requests import get\nfrom kiss_headers import Headers, UserAgent, Referer, UpgradeInsecureRequests, Accept, AcceptLanguage, CustomHeader\n\nclass CustomHeaderXyz(CustomHeader):\n\n    __squash__ = False\n\n    def __init__(self, charset: str = \"utf-8\"):\n        super().__init__(\"hello\", charset=charset)\n\n# Officially supported with requests\nresponse = get(\n    \"https://httpbin.org/headers\",\n    headers=Headers(\n        UserAgent(\"custom/2.22\"),\n        Referer(\"https://www.google.com\"),\n        UpgradeInsecureRequests(),\n        Accept(\"text/html\"),\n        AcceptLanguage(\"en-US\"),\n        CustomHeaderXyz()\n    )\n)\n```\n\nhttpbin should get back with:\n\n```json\n{\n    \"headers\": {\n        \"Accept\": \"text/html\",\n        \"Accept-Encoding\": \"identity\",\n        \"Accept-Language\": \"en-US\",\n        \"Custom-Header-Xyz\": \"hello; charset=\\\"utf-8\\\"\",\n        \"Host\": \"httpbin.org\",\n        \"Referer\": \"https://www.google.com\",\n        \"Upgrade-Insecure-Requests\": \"1\",\n        \"User-Agent\": \"custom/2.22\",\n        \"X-Amzn-Trace-Id\": \"Root=1-622sz46b-973c5671113f58d611972de\"\n    }\n}\n```\n\nDo not forget that headers are not OneToOne. One header can be repeated multiple times and attributes can have multiple values within the same header.\n\n```python\nfrom kiss_headers import parse_it\n\nmy_cookies = \"\"\"set-cookie: 1P_JAR=2020-03-16-21; expires=Wed, 15-Apr-2020 21:27:31 GMT; path=/; domain=.google.fr; Secure; SameSite=none\nset-cookie: CONSENT=WP.284b10; expires=Fri, 01-Jan-2038 00:00:00 GMT; path=/; domain=.google.fr\"\"\"\n\nheaders = parse_it(my_cookies)\n\ntype(headers.set_cookie)  # output: list\nheaders.set_cookie[0].expires # output: Wed, 15-Apr-2020 21:27:31 GMT\nheaders.set_cookie[0]._1p_jar # output: 2020-03-16-21\nheaders.set_cookie[0][\"1P_JAR\"] # output: 2020-03-16-21\n```\n\nSince v2.1 you can transform an Header object to its target `CustomHeader` subclass to access more methods.\n\n```python\nfrom kiss_headers import parse_it, get_polymorphic, SetCookie\n\nmy_cookies = \"\"\"set-cookie: 1P_JAR=2020-03-16-21; expires=Wed, 15-Apr-2020 21:27:31 GMT; path=/; domain=.google.fr; Secure; SameSite=none\nset-cookie: CONSENT=WP.284b10; expires=Fri, 01-Jan-2038 00:00:00 GMT; path=/; domain=.google.fr\"\"\"\n\nheaders = parse_it(my_cookies)\n\ntype(headers.set_cookie[0])  # output: Header\n\nset_cookie = get_polymorphic(headers.set_cookie[0], SetCookie)\n\ntype(set_cookie)  # output: SetCookie\n\nset_cookie.get_cookie_name()  # output: 1P_JAR\nset_cookie.get_expire()  # output: datetime(...)\n```\n\nJust a note: Accessing a header that has the same name as a reserved keyword must be done this way :\n```python\nheaders = parse_it('From: Ousret; origin=www.github.com\\nIS: 1\\nWhile: Not-True')\n\n# this flavour\nheaders.from_ # to access From, just add a single underscore to it\n# or.. just using :\nheaders['from']\n```\n\n#### ✍️Serialization\n\nSince version 2.3.0 the package offer the possibility to un/serialize `Headers`.\n\n```python\nfrom requests import get\nfrom kiss_headers import parse_it, dumps\n\njson_repr: str = dumps(\n    parse_it(\n        get(\"https://www.google.fr\")\n    ),\n    indent=4\n)\n\nprint(json_repr)  # See the result bellow\n\n# Additionally, how to parse the JSON repr to Headers again\nheaders = parse_it(json_repr)  # Yes! that easy!\n```\n\n```json\n{\n    \"Date\": [\n        {\n            \"Tue, 02 Feb 2021 21:43:13 GMT\": null\n        }\n    ],\n    \"Expires\": [\n        {\n            \"-1\": null\n        }\n    ],\n    \"Cache-Control\": [\n        {\n            \"private\": null\n        },\n        {\n            \"max-age\": \"0\"\n        }\n    ],\n    \"Content-Type\": [\n        {\n            \"text/html\": null,\n            \"charset\": \"ISO-8859-1\"\n        }\n    ],\n    \"P3P\": [\n        {\n            \"CP\": \"This is not a P3P policy! See g.co/p3phelp for more info.\"\n        }\n    ],\n    \"Content-Encoding\": [\n        {\n            \"gzip\": null\n        }\n    ],\n    \"Server\": [\n        {\n            \"gws\": null\n        }\n    ],\n    \"X-XSS-Protection\": [\n        {\n            \"0\": null\n        }\n    ],\n    \"X-Frame-Options\": [\n        {\n            \"SAMEORIGIN\": null\n        }\n    ],\n    \"Set-Cookie\": [\n        {\n            \"NID\": \"208=D5XUqjrP9PNpiZu4laa_0xvy_IxBzQLtfxqeAqcPBgiY2y5sfSF51IFuXZnH0zDAF1KZ8x-0VsRyGOM0aStIzCUfdiPBOCxHSxUv39N0vwzku3aI2UkeRXhWw8-HWw5Ob41GB0PZi2coQsPM7ZEQ_fl9PlQ_ld1KrPA\",\n            \"expires\": \"Wed, 04-Aug-2021 21:43:13 GMT\",\n            \"path\": \"/\",\n            \"domain\": \".google.fr\",\n            \"HttpOnly\": null\n        },\n        {\n            \"CONSENT\": \"PENDING+880\",\n            \"expires\": \"Fri, 01-Jan-2038 00:00:00 GMT\",\n            \"path\": \"/\",\n            \"domain\": \".google.fr\"\n        }\n    ],\n    \"Alt-Svc\": [\n        {\n            \"h3-29\": \":443\",\n            \"ma\": \"2592000\"\n        },\n        {\n            \"h3-T051\": \":443\",\n            \"ma\": \"2592000\"\n        },\n        {\n            \"h3-Q050\": \":443\",\n            \"ma\": \"2592000\"\n        },\n        {\n            \"h3-Q046\": \":443\",\n            \"ma\": \"2592000\"\n        },\n        {\n            \"h3-Q043\": \":443\",\n            \"ma\": \"2592000\"\n        },\n        {\n            \"quic\": \":443\",\n            \"ma\": \"2592000\",\n            \"v\": \"46,43\"\n        }\n    ],\n    \"Transfer-Encoding\": [\n        {\n            \"chunked\": null\n        }\n    ]\n}\n```\n\nAlternatively you may use `from kiss_headers import parse_it, encode, decode` to transform `Headers` to `dict` (instead of JSON) or the other way around.\nUnderstand that the `dict` returned in `encode` will differ from the method `to_dict()` in `Headers`.\n\n#### 🛠️ Create headers from objects\n\nIntroduced in the version 2.0, kiss-headers now allow you to create headers with more than 40+ ready-to-use, fully documented, header objects.\n\n1st example usage\n```python\nfrom kiss_headers import Headers, Authorization\nfrom requests import get\n\nresponse = get(\"https://httpbin.org/bearer\", headers=Headers(Authorization(\"Bearer\", \"qwerty\")))\nprint(response.status_code)  # 200\n```\n\n2nd example usage\n```python\nfrom kiss_headers import *\n\nheaders = (\n    Host(\"developer.mozilla.org\")\n    + UserAgent(\n        \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:50.0) Gecko/20100101 Firefox/50.0\"\n    )\n    + Accept(\"text/html\")\n    + Accept(\"application/xhtml+xml\")\n    + Accept(\"application/xml\", qualifier=0.9)\n    + Accept(qualifier=0.8)\n    + AcceptLanguage(\"en-US\")\n    + AcceptLanguage(\"en\", qualifier=0.5)\n    + AcceptEncoding(\"gzip\")\n    + AcceptEncoding(\"deflate\")\n    + AcceptEncoding(\"br\")\n    + Referer(\"https://developer.mozilla.org/testpage.html\")\n    + Connection(should_keep_alive=True)\n    + UpgradeInsecureRequests()\n    + IfModifiedSince(\"Mon, 18 Jul 2016 02:36:04 GMT\")\n    + IfNoneMatch(\"c561c68d0ba92bbeb8b0fff2a9199f722e3a621a\")\n    + CacheControl(max_age=0)\n)\n\nraw_headers = str(headers)\n```\n\n`raw_headers` now retain the following :\n\n```\nHost: developer.mozilla.org\nUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:50.0) Gecko/20100101 Firefox/50.0\nAccept: text/html, application/xhtml+xml, application/xml; q=\"0.9\", */*; q=\"0.8\"\nAccept-Language: en-US, en; q=\"0.5\"\nAccept-Encoding: gzip, deflate, br\nReferer: https://developer.mozilla.org/testpage.html\nConnection: keep-alive\nUpgrade-Insecure-Requests: 1\nIf-Modified-Since: Mon, 18 Jul 2016 02:36:04 GMT\nIf-None-Match: \"c561c68d0ba92bbeb8b0fff2a9199f722e3a621a\"\nCache-Control: max-age=\"0\"\n```\n\nSee the complete list of available header class in the full documentation.\nAlso, you can create your own custom header object using the class `kiss_headers.CustomHeader`.\n\n## 📜 Documentation\n\nSee the full documentation for advanced usages : [jawah.github.io/kiss-headers](https://jawah.github.io/kiss-headers/)\n\n## 👤 Contributing\n\nContributions, issues and feature requests are very much welcome.\u003cbr /\u003e\nFeel free to check [issues page](https://github.com/jawah/kiss-headers/issues) if you want to contribute.\n\nFirstly, after getting your own local copy, run `./scripts/install` to initialize your virtual environment.\nThen run `./scripts/check` before you commit, make sure everything is still working.\n\nRemember to keep it sweet and simple when contributing to this project.\n\n## 📝 License\n\nCopyright © 2020 [Ahmed TAHRI @Ousret](https://github.com/Ousret).\u003cbr /\u003e\nThis project is [MIT](https://github.com/jawah/kiss-headers/blob/master/LICENSE) licensed.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjawah%2Fkiss-headers","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjawah%2Fkiss-headers","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjawah%2Fkiss-headers/lists"}