From e079c368d123053ab26d27c165bd2167b210e3c6 Mon Sep 17 00:00:00 2001 From: TAHRI Ahmed R Date: Sat, 16 Apr 2022 07:44:08 +0200 Subject: [PATCH] Release 2.3.1 (#48) * :sparkle: Migrate to GHA * :sparkle: Add support 3.11 explicit * :sparkle: Add __all__ to top-level package init --- .github/workflows/lint.yml | 36 ++++ .github/workflows/run-tests.yml | 31 +++ .travis.yml | 33 --- MANIFEST.in | 7 +- README.md | 71 +++++-- requirements.txt => dev-requirements.txt | 0 kiss_headers/__init__.py | 247 ++++++++++++++--------- kiss_headers/version.py | 2 +- setup.py | 159 +++++++-------- 9 files changed, 363 insertions(+), 223 deletions(-) create mode 100644 .github/workflows/lint.yml create mode 100644 .github/workflows/run-tests.yml delete mode 100644 .travis.yml rename requirements.txt => dev-requirements.txt (100%) 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.
- - - - - - - - PyPi Publish Action - - - Code style: black - - - Checked with mypy - Download Count Total @@ -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", + ], +)