diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
new file mode 100644
index 0000000..08757aa
--- /dev/null
+++ b/.github/workflows/lint.yml
@@ -0,0 +1,36 @@
+name: 🎨 Linters
+
+on: [push, pull_request]
+
+jobs:
+ lint:
+ runs-on: ${{ matrix.os }}
+
+ strategy:
+ fail-fast: false
+ matrix:
+ python-version: [3.9]
+ os: [ubuntu-latest]
+
+ steps:
+ - uses: actions/checkout@v2
+ - name: Set up Python ${{ matrix.python-version }}
+ uses: actions/setup-python@v2
+ with:
+ python-version: ${{ matrix.python-version }}
+ - name: Install dependencies
+ run: |
+ pip install -U pip setuptools
+ pip install -r dev-requirements.txt
+ - name: Install the package
+ run: |
+ python setup.py install
+ - name: Type checking (Mypy)
+ run: |
+ mypy kiss_headers
+ - name: Import sorting check (isort)
+ run: |
+ isort --check kiss_headers
+ - name: Code format (Black)
+ run: |
+ black --check --diff --target-version=py36 kiss_headers
diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml
new file mode 100644
index 0000000..818cc53
--- /dev/null
+++ b/.github/workflows/run-tests.yml
@@ -0,0 +1,31 @@
+name: Tests
+
+on: [push, pull_request]
+
+jobs:
+ tests:
+ runs-on: ${{ matrix.os }}
+
+ strategy:
+ fail-fast: false
+ matrix:
+ python-version: [3.6, 3.7, 3.8, 3.9, "3.10", "3.11.0-alpha.7"]
+ os: [ubuntu-latest]
+
+ steps:
+ - uses: actions/checkout@v2
+ - name: Set up Python ${{ matrix.python-version }}
+ uses: actions/setup-python@v2
+ with:
+ python-version: ${{ matrix.python-version }}
+ - name: Install dependencies
+ run: |
+ pip install -U pip setuptools
+ pip install -r dev-requirements.txt
+ - name: Install the package
+ run: |
+ python setup.py install
+ - name: Run tests
+ run: |
+ pytest
+ - uses: codecov/codecov-action@v1
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index e87e5ba..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,33 +0,0 @@
-dist: focal
-language: python
-cache: pip
-
-python:
- - "3.6"
- - "3.7"
- - "3.8"
- - "3.9"
- - "3.10-dev"
- - "pypy3"
-
-jobs:
- allow_failures:
- - python: "3.10-dev"
- - python: "pypy3"
-
-before_install:
- - "pip install -U pip setuptools"
- - "pip install -r requirements.txt"
-
-install:
- - "python setup.py install"
-
-script:
- - export SOURCE_FILES="kiss_headers tests"
- - black --check --diff --target-version=py36 $SOURCE_FILES
- - mypy kiss_headers
- - isort --check --diff --project=kiss_headers $SOURCE_FILES
- - pytest
-
-after_success:
- - codecov
\ No newline at end of file
diff --git a/MANIFEST.in b/MANIFEST.in
index 3bb94a0..8a6ad9f 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,3 +1,4 @@
-include LICENSE
-include README.md
-include kiss_headers/py.typed
+include LICENSE README.md kiss_headers/py.typed dev-requirements.txt UPGRADE.md
+include kiss_headers/py.typed
+recursive-include docs *
+recursive-include tests *
diff --git a/README.md b/README.md
index 71d5bdd..2fd44f8 100644
--- a/README.md
+++ b/README.md
@@ -2,27 +2,12 @@
Object-oriented headers. Kind of structured headers.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -40,6 +25,17 @@ I have seen so many chunks of code trying to deal with these headers; often I sa
```python
# No more of that!
charset = headers['Content-Type'].split(';')[-1].split('=')[-1].replace('"', '')
+# That too..
+response = get(
+ "https://httpbin.org/headers",
+ headers={
+ "user-agent": "custom/2.22",
+ "referer": "https://www.google.com",
+ "accept": "text/html",
+ "accept-language": "en-US",
+ "custom-header-xyz": "hello; charset=utf-8"
+ }
+)
```
**Scroll down and see how you could do it from now on.**
@@ -93,6 +89,51 @@ headers.content_type.charset # output: ISO-8859-1
headers["content-type"]["charset"] # output: ISO-8859-1
```
+and also, the other way around:
+
+```python
+from requests import get
+from kiss_headers import Headers, UserAgent, Referer, UpgradeInsecureRequests, Accept, AcceptLanguage, CustomHeader
+
+class CustomHeaderXyz(CustomHeader):
+
+ __squash__ = False
+
+ def __init__(self, charset: str = "utf-8"):
+ super().__init__("hello", charset=charset)
+
+# Officially supported with requests
+response = get(
+ "https://httpbin.org/headers",
+ headers=Headers(
+ UserAgent("custom/2.22"),
+ Referer("https://www.google.com"),
+ UpgradeInsecureRequests(),
+ Accept("text/html"),
+ AcceptLanguage("en-US"),
+ CustomHeaderXyz()
+ )
+)
+```
+
+httpbin should get back with:
+
+```json
+{
+ "headers": {
+ "Accept": "text/html",
+ "Accept-Encoding": "identity",
+ "Accept-Language": "en-US",
+ "Custom-Header-Xyz": "hello; charset=\"utf-8\"",
+ "Host": "httpbin.org",
+ "Referer": "https://www.google.com",
+ "Upgrade-Insecure-Requests": "1",
+ "User-Agent": "custom/2.22",
+ "X-Amzn-Trace-Id": "Root=1-622sz46b-973c5671113f58d611972de"
+ }
+}
+```
+
Do not forget that headers are not OneToOne. One header can be repeated multiple times and attributes can have multiple values within the same header.
```python
diff --git a/requirements.txt b/dev-requirements.txt
similarity index 100%
rename from requirements.txt
rename to dev-requirements.txt
diff --git a/kiss_headers/__init__.py b/kiss_headers/__init__.py
index 285431a..89ef672 100644
--- a/kiss_headers/__init__.py
+++ b/kiss_headers/__init__.py
@@ -1,92 +1,155 @@
-"""
-Kiss-Headers
-~~~~~~~~~~~~~~
-
-Kiss-Headers is a headers, HTTP or IMAP4 _(message, email)_ flavour, utility, written in pure Python, for humans.
-Object oriented headers. Keep it sweet and simple.
-Basic usage:
-
- >>> import requests
- >>> from kiss_headers import parse_it
- >>> r = requests.get('https://www.python.org')
- >>> headers = parse_it(r)
- >>> 'charset' in headers.content_type
- True
- >>> headers.content_type.charset
- 'utf-8'
- >>> 'text/html' in headers.content_type
- True
- >>> headers.content_type == 'text/html'
- True
- >>> headers -= 'content-type'
- >>> 'Content-Type' in headers
- False
-
-... or from a raw IMAP4 message:
-
- >>> message = requests.get("https://gist.githubusercontent.com/Ousret/8b84b736c375bb6aa3d389e86b5116ec/raw/21cb2f7af865e401c37d9b053fb6fe1abf63165b/sample-message.eml").content
- >>> headers = parse_it(message)
- >>> 'Sender' in headers
- True
-
-Others methods and usages are available - see the full documentation
-at .
-
-:copyright: (c) 2020 by Ahmed TAHRI
-:license: MIT, see LICENSE for more details.
-"""
-
-from kiss_headers.api import dumps, explain, get_polymorphic, parse_it
-from kiss_headers.builder import (
- Accept,
- AcceptEncoding,
- AcceptLanguage,
- Allow,
- AltSvc,
- Authorization,
- BasicAuthorization,
- CacheControl,
- Connection,
- ContentDisposition,
- ContentEncoding,
- ContentLength,
- ContentRange,
- ContentSecurityPolicy,
- ContentType,
- CrossOriginResourcePolicy,
- CustomHeader,
- Date,
- Digest,
- Dnt,
- Etag,
- Expires,
- Forwarded,
- From,
- Host,
- IfMatch,
- IfModifiedSince,
- IfNoneMatch,
- IfUnmodifiedSince,
- KeepAlive,
- LastModified,
- Location,
- ProxyAuthorization,
- Referer,
- ReferrerPolicy,
- RetryAfter,
- Server,
- SetCookie,
- StrictTransportSecurity,
- TransferEncoding,
- UpgradeInsecureRequests,
- UserAgent,
- Vary,
- WwwAuthenticate,
- XContentTypeOptions,
- XDnsPrefetchControl,
- XFrameOptions,
- XXssProtection,
-)
-from kiss_headers.models import Attributes, Header, Headers, lock_output_type
-from kiss_headers.serializer import decode, encode
-from kiss_headers.version import VERSION, __version__
+"""
+Kiss-Headers
+~~~~~~~~~~~~~~
+
+Kiss-Headers is a headers, HTTP or IMAP4 _(message, email)_ flavour, utility, written in pure Python, for humans.
+Object oriented headers. Keep it sweet and simple.
+Basic usage:
+
+ >>> import requests
+ >>> from kiss_headers import parse_it
+ >>> r = requests.get('https://www.python.org')
+ >>> headers = parse_it(r)
+ >>> 'charset' in headers.content_type
+ True
+ >>> headers.content_type.charset
+ 'utf-8'
+ >>> 'text/html' in headers.content_type
+ True
+ >>> headers.content_type == 'text/html'
+ True
+ >>> headers -= 'content-type'
+ >>> 'Content-Type' in headers
+ False
+
+... or from a raw IMAP4 message:
+
+ >>> message = requests.get("https://gist.githubusercontent.com/Ousret/8b84b736c375bb6aa3d389e86b5116ec/raw/21cb2f7af865e401c37d9b053fb6fe1abf63165b/sample-message.eml").content
+ >>> headers = parse_it(message)
+ >>> 'Sender' in headers
+ True
+
+Others methods and usages are available - see the full documentation
+at .
+
+:copyright: (c) 2020 by Ahmed TAHRI
+:license: MIT, see LICENSE for more details.
+"""
+
+from kiss_headers.api import dumps, explain, get_polymorphic, parse_it
+from kiss_headers.builder import (
+ Accept,
+ AcceptEncoding,
+ AcceptLanguage,
+ Allow,
+ AltSvc,
+ Authorization,
+ BasicAuthorization,
+ CacheControl,
+ Connection,
+ ContentDisposition,
+ ContentEncoding,
+ ContentLength,
+ ContentRange,
+ ContentSecurityPolicy,
+ ContentType,
+ CrossOriginResourcePolicy,
+ CustomHeader,
+ Date,
+ Digest,
+ Dnt,
+ Etag,
+ Expires,
+ Forwarded,
+ From,
+ Host,
+ IfMatch,
+ IfModifiedSince,
+ IfNoneMatch,
+ IfUnmodifiedSince,
+ KeepAlive,
+ LastModified,
+ Location,
+ ProxyAuthorization,
+ Referer,
+ ReferrerPolicy,
+ RetryAfter,
+ Server,
+ SetCookie,
+ StrictTransportSecurity,
+ TransferEncoding,
+ UpgradeInsecureRequests,
+ UserAgent,
+ Vary,
+ WwwAuthenticate,
+ XContentTypeOptions,
+ XDnsPrefetchControl,
+ XFrameOptions,
+ XXssProtection,
+)
+from kiss_headers.models import Attributes, Header, Headers, lock_output_type
+from kiss_headers.serializer import decode, encode
+from kiss_headers.version import VERSION, __version__
+
+__all__ = (
+ "dumps",
+ "explain",
+ "get_polymorphic",
+ "parse_it",
+ "Attributes",
+ "Header",
+ "Headers",
+ "lock_output_type",
+ "decode",
+ "encode",
+ "VERSION",
+ "__version__",
+ "Accept",
+ "AcceptEncoding",
+ "AcceptLanguage",
+ "Allow",
+ "AltSvc",
+ "Authorization",
+ "BasicAuthorization",
+ "CacheControl",
+ "Connection",
+ "ContentDisposition",
+ "ContentEncoding",
+ "ContentLength",
+ "ContentRange",
+ "ContentSecurityPolicy",
+ "ContentType",
+ "CrossOriginResourcePolicy",
+ "CustomHeader",
+ "Date",
+ "Digest",
+ "Dnt",
+ "Etag",
+ "Expires",
+ "Forwarded",
+ "From",
+ "Host",
+ "IfMatch",
+ "IfModifiedSince",
+ "IfNoneMatch",
+ "IfUnmodifiedSince",
+ "KeepAlive",
+ "LastModified",
+ "Location",
+ "ProxyAuthorization",
+ "Referer",
+ "ReferrerPolicy",
+ "RetryAfter",
+ "Server",
+ "SetCookie",
+ "StrictTransportSecurity",
+ "TransferEncoding",
+ "UpgradeInsecureRequests",
+ "UserAgent",
+ "Vary",
+ "WwwAuthenticate",
+ "XContentTypeOptions",
+ "XDnsPrefetchControl",
+ "XFrameOptions",
+ "XXssProtection",
+)
diff --git a/kiss_headers/version.py b/kiss_headers/version.py
index 81dd88c..432201b 100644
--- a/kiss_headers/version.py
+++ b/kiss_headers/version.py
@@ -2,5 +2,5 @@
Expose version
"""
-__version__ = "2.3.0"
+__version__ = "2.3.1"
VERSION = __version__.split(".")
diff --git a/setup.py b/setup.py
index 14fa446..e641df1 100644
--- a/setup.py
+++ b/setup.py
@@ -1,79 +1,80 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-import io
-import os
-
-from setuptools import find_packages, setup
-from re import search
-
-
-def get_version():
- with open("kiss_headers/version.py") as version_file:
- return search(
- r"""__version__\s+=\s+(['"])(?P.+?)\1""", version_file.read()
- ).group("version")
-
-
-# Package meta-data.
-NAME = "kiss-headers"
-DESCRIPTION = "Python package for object oriented headers, HTTP/1.1 style. Parser and serializer for http headers."
-URL = "https://github.com/ousret/kiss-headers"
-EMAIL = "ahmed.tahri@cloudnursery.dev"
-AUTHOR = "Ahmed TAHRI @Ousret"
-REQUIRES_PYTHON = ">=3.6.0"
-VERSION = get_version()
-
-EXTRAS = {}
-
-here = os.path.abspath(os.path.dirname(__file__))
-
-try:
- with io.open(os.path.join(here, "README.md"), encoding="utf-8") as f:
- long_description = "\n" + f.read()
-except FileNotFoundError:
- long_description = DESCRIPTION
-
-setup(
- name=NAME,
- version=VERSION,
- description=DESCRIPTION,
- long_description=long_description,
- long_description_content_type="text/markdown",
- author=AUTHOR,
- author_email=EMAIL,
- python_requires=REQUIRES_PYTHON,
- url=URL,
- project_urls={
- "Documentation": "https://www.kiss-headers.tech",
- "Source": "https://github.com/Ousret/kiss-headers",
- "Issue tracker": "https://github.com/Ousret/kiss-headers/issues",
- },
- keywords=["headers", "http", "mail", "text", "imap", "header", "https", "imap4"],
- packages=find_packages(exclude=["tests", "*.tests", "*.tests.*", "tests.*"]),
- package_data={"kiss_headers": ["py.typed"]},
- install_requires=[], # We shall not require anything. This will remain the same.
- extras_require=EXTRAS,
- include_package_data=True,
- license="MIT",
- classifiers=[
- "License :: OSI Approved :: MIT License",
- "Intended Audience :: Developers",
- "Development Status :: 5 - Production/Stable",
- "Topic :: Communications :: Email",
- "Topic :: Internet :: WWW/HTTP",
- "Topic :: Internet :: WWW/HTTP :: Dynamic Content :: Content Management System",
- "Environment :: Web Environment",
- "Topic :: Software Development :: Libraries :: Python Modules",
- "Operating System :: OS Independent",
- "Programming Language :: Python :: 3",
- "Programming Language :: Python :: 3.6",
- "Programming Language :: Python :: 3.7",
- "Programming Language :: Python :: 3.8",
- "Programming Language :: Python :: 3.9",
- "Programming Language :: Python :: 3.10",
- "Programming Language :: Python :: 3 :: Only",
- "Topic :: Utilities",
- "Programming Language :: Python :: Implementation :: PyPy",
- ],
-)
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+import io
+import os
+
+from setuptools import find_packages, setup
+from re import search
+
+
+def get_version():
+ with open("kiss_headers/version.py") as version_file:
+ return search(
+ r"""__version__\s+=\s+(['"])(?P.+?)\1""", version_file.read()
+ ).group("version")
+
+
+# Package meta-data.
+NAME = "kiss-headers"
+DESCRIPTION = "Python package for object oriented headers, HTTP/1.1 style. Parser and serializer for http headers."
+URL = "https://github.com/ousret/kiss-headers"
+EMAIL = "ahmed.tahri@cloudnursery.dev"
+AUTHOR = "Ahmed TAHRI @Ousret"
+REQUIRES_PYTHON = ">=3.6"
+VERSION = get_version()
+
+EXTRAS = {}
+
+here = os.path.abspath(os.path.dirname(__file__))
+
+try:
+ with io.open(os.path.join(here, "README.md"), encoding="utf-8") as f:
+ long_description = "\n" + f.read()
+except FileNotFoundError:
+ long_description = DESCRIPTION
+
+setup(
+ name=NAME,
+ version=VERSION,
+ description=DESCRIPTION,
+ long_description=long_description,
+ long_description_content_type="text/markdown",
+ author=AUTHOR,
+ author_email=EMAIL,
+ python_requires=REQUIRES_PYTHON,
+ url=URL,
+ project_urls={
+ "Documentation": "https://ousret.github.io/kiss-headers",
+ "Source": "https://github.com/Ousret/kiss-headers",
+ "Issue tracker": "https://github.com/Ousret/kiss-headers/issues",
+ },
+ keywords=["headers", "http", "mail", "text", "imap", "header", "https", "imap4"],
+ packages=find_packages(exclude=["tests", "*.tests", "*.tests.*", "tests.*"]),
+ package_data={"kiss_headers": ["py.typed"]},
+ install_requires=[], # We shall not require anything. This will remain the same.
+ extras_require=EXTRAS,
+ include_package_data=True,
+ license="MIT",
+ classifiers=[
+ "License :: OSI Approved :: MIT License",
+ "Intended Audience :: Developers",
+ "Development Status :: 5 - Production/Stable",
+ "Topic :: Communications :: Email",
+ "Topic :: Internet :: WWW/HTTP",
+ "Topic :: Internet :: WWW/HTTP :: Dynamic Content :: Content Management System",
+ "Environment :: Web Environment",
+ "Topic :: Software Development :: Libraries :: Python Modules",
+ "Operating System :: OS Independent",
+ "Programming Language :: Python :: 3",
+ "Programming Language :: Python :: 3.6",
+ "Programming Language :: Python :: 3.7",
+ "Programming Language :: Python :: 3.8",
+ "Programming Language :: Python :: 3.9",
+ "Programming Language :: Python :: 3.10",
+ "Programming Language :: Python :: 3.11",
+ "Programming Language :: Python :: 3 :: Only",
+ "Topic :: Utilities",
+ "Programming Language :: Python :: Implementation :: PyPy",
+ ],
+)