diff --git a/.flake8 b/.flake8 new file mode 100644 index 00000000..32febf22 --- /dev/null +++ b/.flake8 @@ -0,0 +1,2 @@ +[flake8] +ignore = E501,W191,C901,E265,E402,E117 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..743a963e --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,69 @@ +--- +name: CI + +'on': + push: + branches: ["master"] + pull_request: + +jobs: + test: + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + python-version: ["3.8", "3.9"] + + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -Ue .[test] + pip install -Ue . + + - name: Run tests + run: | + python -m pytest + + - name: Upload coverage to codecov + uses: codecov/codecov-action@v4 + with: + token: ${{ secrets.CODECOV_TOKEN }} + + - name: Upload coverage to coveralls + if: success() + env: + COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_TOKEN }} + run: | + pip install coveralls + coveralls --service=github-actions + + lint: + runs-on: ubuntu-latest + + strategy: + matrix: + python-version: ["3.9"] + + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + + - name: Install flake8 + run: pip install -U flake8 + + - name: Run flake8 + run: | + flake8 diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index b4e0c429..00000000 --- a/.travis.yml +++ /dev/null @@ -1,45 +0,0 @@ -language: python - -python: - - "2.7" - - "3.5" - - "3.6" - - "3.7" - - "3.8" - - "3.9-dev" - - "pypy" - -before_install: - pip install codecov - -matrix: -# allow_failures: -# - python: "3.5" -# - python: "3.6" -# - python: "3.7" - include: - - python: 2.7 - install: pip install -U flake8 - script: flake8 --ignore E501,W191,C901,E265,E402,E117 - after_success: - - python: 3.5 - install: pip install -U flake8 - script: flake8 --ignore E501,W191,C901,E265,E402,E117 - after_success: -# - python: 2.7 -# install: pip install -U isort -# script: isort -c --diff -# after_success: - -install: - - pip install -Ur requirements-test.txt - - pip install -Ue . - -script: python setup.py test - -after_success: - - codecov - - coveralls - -notifications: - irc: "chat.freenode.net#httoop" diff --git a/README.md b/README.md index 2633a986..d4e7ca5c 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -[![Build Status](https://travis-ci.org/spaceone/httoop.svg)](https://travis-ci.org/spaceone/httoop) -[![codecov](https://codecov.io/gh/spaceone/httoop/branch/master/graph/badge.svg)](https://codecov.io/gh/spaceone/httoop) +[![Build Status](https://github.com/spaceone/httoop/actions/workflows/ci.yml/badge.svg)](https://github.com/spaceone/httoop/actions/workflows/ci.yml) +[![Coverage](https://codecov.io/gh/spaceone/httoop/branch/master/graph/badge.svg)](https://codecov.io/gh/spaceone/httoop) [![Code Climate](https://codeclimate.com/github/spaceone/httoop/badges/gpa.svg)](https://codeclimate.com/github/spaceone/httoop) [![MIT License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat)](https://github.com/spaceone/httoop/raw/master/LICENSE) diff --git a/httoop/__init__.py b/httoop/__init__.py index c1bdec2b..6949375f 100644 --- a/httoop/__init__.py +++ b/httoop/__init__.py @@ -51,8 +51,3 @@ '__version__', 'ServerProtocol', 'UserAgentHeader', 'ServerHeader', 'cache', 'ComposedRequest', 'ComposedResponse', ] - -try: - __import__('pkg_resources').declare_namespace(__name__) -except ImportError: # pragma: no cover - __path___ = __import__('pkgutil').extend_path(__path__, __name__) diff --git a/httoop/authentication/__init__.py b/httoop/authentication/__init__.py index 56f5752b..5d1035ac 100644 --- a/httoop/authentication/__init__.py +++ b/httoop/authentication/__init__.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +from __future__ import annotations import re from typing import Any, Dict, List, Tuple, Union diff --git a/httoop/authentication/basic.py b/httoop/authentication/basic.py index 333aed6c..f8c8d2cb 100644 --- a/httoop/authentication/basic.py +++ b/httoop/authentication/basic.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +from __future__ import annotations from binascii import Error as Base64Error from typing import Dict, Union diff --git a/httoop/authentication/digest.py b/httoop/authentication/digest.py index 7b22b638..da585654 100644 --- a/httoop/authentication/digest.py +++ b/httoop/authentication/digest.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +from __future__ import annotations from hashlib import md5, sha256 from typing import Callable, Dict, List, Tuple, Union diff --git a/httoop/codecs/__init__.py b/httoop/codecs/__init__.py index 81fd036a..800d5ffa 100644 --- a/httoop/codecs/__init__.py +++ b/httoop/codecs/__init__.py @@ -2,6 +2,7 @@ u"""Module containing various codecs which are common used in combination with HTTP. """ +from __future__ import annotations import inspect from typing import Any, Type diff --git a/httoop/codecs/application/hal_json.py b/httoop/codecs/application/hal_json.py index ca005fd0..25fde40d 100644 --- a/httoop/codecs/application/hal_json.py +++ b/httoop/codecs/application/hal_json.py @@ -2,6 +2,7 @@ """JSON Hypertext Application Language (application/hal+json) codec.""" from __future__ import absolute_import +from __future__ import annotations from typing import Any, Dict, Iterator, List, Optional, Union diff --git a/httoop/codecs/application/json.py b/httoop/codecs/application/json.py index d4ebbe55..c9a8306e 100644 --- a/httoop/codecs/application/json.py +++ b/httoop/codecs/application/json.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- from __future__ import absolute_import +from __future__ import annotations from json import dumps as json_encode, loads as json_decode from typing import Any, Dict, Optional, Union diff --git a/httoop/codecs/application/x_www_form_urlencoded.py b/httoop/codecs/application/x_www_form_urlencoded.py index 0410b6a7..d159d687 100644 --- a/httoop/codecs/application/x_www_form_urlencoded.py +++ b/httoop/codecs/application/x_www_form_urlencoded.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +from __future__ import annotations from typing import Any, List, Optional, Tuple, Union from httoop.codecs.codec import Codec diff --git a/httoop/codecs/application/zlib.py b/httoop/codecs/application/zlib.py index 84e3851e..60976f9f 100644 --- a/httoop/codecs/application/zlib.py +++ b/httoop/codecs/application/zlib.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- from __future__ import absolute_import +from __future__ import annotations import zlib from typing import Optional diff --git a/httoop/codecs/codec.py b/httoop/codecs/codec.py index c7f46fde..c9846a4a 100644 --- a/httoop/codecs/codec.py +++ b/httoop/codecs/codec.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +from __future__ import annotations from typing import Any diff --git a/httoop/codecs/message/http.py b/httoop/codecs/message/http.py index b5e4851c..0da9d1c9 100644 --- a/httoop/codecs/message/http.py +++ b/httoop/codecs/message/http.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- from __future__ import absolute_import +from __future__ import annotations from typing import Optional, Union diff --git a/httoop/codecs/multipart/multipart.py b/httoop/codecs/multipart/multipart.py index 0d23d185..d09d5b70 100644 --- a/httoop/codecs/multipart/multipart.py +++ b/httoop/codecs/multipart/multipart.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +from __future__ import annotations from typing import List, Optional from httoop.codecs.codec import Codec diff --git a/httoop/codecs/text/plain.py b/httoop/codecs/text/plain.py index 91ed3b3e..c53984ea 100644 --- a/httoop/codecs/text/plain.py +++ b/httoop/codecs/text/plain.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +from __future__ import annotations from typing import Optional from httoop.codecs.codec import Codec diff --git a/httoop/date.py b/httoop/date.py index a192ee2a..7ee7b854 100644 --- a/httoop/date.py +++ b/httoop/date.py @@ -5,6 +5,7 @@ """ from __future__ import absolute_import +from __future__ import annotations import locale import time diff --git a/httoop/gateway/wsgi.py b/httoop/gateway/wsgi.py index c4a7affb..5c8ab1b8 100644 --- a/httoop/gateway/wsgi.py +++ b/httoop/gateway/wsgi.py @@ -3,6 +3,7 @@ .. seealso:: `PEP 333 `_ """ +from __future__ import annotations from typing import Any, Callable, Dict, Iterator, Optional, Tuple, Union diff --git a/httoop/header/element.py b/httoop/header/element.py index d6500427..1c2b085c 100644 --- a/httoop/header/element.py +++ b/httoop/header/element.py @@ -7,6 +7,7 @@ .. seealso:: :rfc:`2616#section-14` """ +from __future__ import annotations import re from binascii import b2a_base64 diff --git a/httoop/header/headers.py b/httoop/header/headers.py index 1efd06c9..9e16847e 100644 --- a/httoop/header/headers.py +++ b/httoop/header/headers.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +from __future__ import annotations import re from typing import Any, Dict, List, Optional, Union diff --git a/httoop/header/messaging.py b/httoop/header/messaging.py index 1780bfa9..cddbb90c 100644 --- a/httoop/header/messaging.py +++ b/httoop/header/messaging.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- # TODO: Via, Server, User-Agent can contain comments → parse them +from __future__ import annotations import re from typing import Any, List, Optional diff --git a/httoop/header/range.py b/httoop/header/range.py index 76891022..83afc500 100644 --- a/httoop/header/range.py +++ b/httoop/header/range.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +from __future__ import annotations from io import BytesIO from math import sqrt from os import SEEK_END, SEEK_SET diff --git a/httoop/header/security.py b/httoop/header/security.py index 0007ae90..e9a1f5d9 100644 --- a/httoop/header/security.py +++ b/httoop/header/security.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- """Security related header.""" +from __future__ import annotations import re from typing import List diff --git a/httoop/messages/body.py b/httoop/messages/body.py index afa37a1e..08a47f7d 100644 --- a/httoop/messages/body.py +++ b/httoop/messages/body.py @@ -3,6 +3,7 @@ .. seealso:: :rfc:`2616#section-4.3` """ +from __future__ import annotations from io import BytesIO from os import fstat diff --git a/httoop/messages/method.py b/httoop/messages/method.py index b0cfa67d..dea49bd8 100644 --- a/httoop/messages/method.py +++ b/httoop/messages/method.py @@ -3,6 +3,7 @@ .. seealso:: :rfc:`2616#section-4` """ +from __future__ import annotations import re from typing import Optional diff --git a/httoop/messages/protocol.py b/httoop/messages/protocol.py index 5a2313da..37bbf4b1 100644 --- a/httoop/messages/protocol.py +++ b/httoop/messages/protocol.py @@ -3,6 +3,7 @@ .. seealso:: :rfc:`2616#section-4` """ +from __future__ import annotations import re from typing import Any, Tuple, Union diff --git a/httoop/meta.py b/httoop/meta.py index c32d0d80..885f67d6 100644 --- a/httoop/meta.py +++ b/httoop/meta.py @@ -1,6 +1,7 @@ """MetaClasses for HTTOOP types.""" from __future__ import absolute_import +from __future__ import annotations from typing import Any, Dict, Tuple, Type, Union diff --git a/httoop/parser.py b/httoop/parser.py index 1a1e99cf..814d9ef9 100644 --- a/httoop/parser.py +++ b/httoop/parser.py @@ -3,6 +3,7 @@ # TODO: translation API from __future__ import absolute_import +from __future__ import annotations from typing import Iterator, Optional, Tuple, Union diff --git a/httoop/semantic/response.py b/httoop/semantic/response.py index 28334701..ef485130 100644 --- a/httoop/semantic/response.py +++ b/httoop/semantic/response.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +from __future__ import annotations from typing import Any, Iterator, Union from httoop.date import Date diff --git a/httoop/server/__init__.py b/httoop/server/__init__.py index 89a952bf..a461679a 100644 --- a/httoop/server/__init__.py +++ b/httoop/server/__init__.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +from __future__ import annotations from typing import Optional, Tuple, Union import httoop.messages.request diff --git a/httoop/status/client_error.py b/httoop/status/client_error.py index a60194b8..aa9317e1 100644 --- a/httoop/status/client_error.py +++ b/httoop/status/client_error.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +from __future__ import annotations from typing import Dict, Union from httoop.status.types import StatusException diff --git a/httoop/status/redirect.py b/httoop/status/redirect.py index a7ec2792..b53d4f18 100644 --- a/httoop/status/redirect.py +++ b/httoop/status/redirect.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +from __future__ import annotations from typing import Dict, Optional, Tuple, Union from httoop.status.types import StatusException diff --git a/httoop/status/server_error.py b/httoop/status/server_error.py index 5af6cb2e..17344343 100644 --- a/httoop/status/server_error.py +++ b/httoop/status/server_error.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +from __future__ import annotations from typing import Dict, Union from httoop.status.types import StatusException diff --git a/httoop/status/status.py b/httoop/status/status.py index ef498bcc..d4d946f7 100644 --- a/httoop/status/status.py +++ b/httoop/status/status.py @@ -4,6 +4,7 @@ .. seealso:: :rfc:`2616#section-6.2` .. seealso:: :rfc:`2616#section-10` """ +from __future__ import annotations import re from typing import Any, Optional, Union diff --git a/httoop/status/success.py b/httoop/status/success.py index 6c56df9c..1e6c4594 100644 --- a/httoop/status/success.py +++ b/httoop/status/success.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +from __future__ import annotations from typing import Dict, Union from httoop.status.types import StatusException diff --git a/httoop/status/types.py b/httoop/status/types.py index cab6e942..57f5a679 100644 --- a/httoop/status/types.py +++ b/httoop/status/types.py @@ -3,6 +3,7 @@ .. seealso:: :rfc:`2616#section-10` """ +from __future__ import annotations from typing import Any, Dict, Optional, Type, Union diff --git a/httoop/uri/query_string.py b/httoop/uri/query_string.py index 52288ce0..ff695429 100644 --- a/httoop/uri/query_string.py +++ b/httoop/uri/query_string.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +from __future__ import annotations import stringprep from typing import Optional, Tuple, Union diff --git a/httoop/uri/type.py b/httoop/uri/type.py index 71872f50..a585600f 100644 --- a/httoop/uri/type.py +++ b/httoop/uri/type.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +from __future__ import annotations from typing import Any, Dict, Tuple, Type, Union from httoop.meta import HTTPSemantic diff --git a/httoop/uri/uri.py b/httoop/uri/uri.py index 7ecfdec4..86d4594e 100644 --- a/httoop/uri/uri.py +++ b/httoop/uri/uri.py @@ -5,6 +5,7 @@ """ # TODO: parse HTTP/1.0-';'-params? +from __future__ import annotations import re from socket import AF_INET, AF_INET6, error as SocketError, inet_ntop, inet_pton from typing import Any, Iterator, Optional, Union diff --git a/httoop/util.py b/httoop/util.py index f99e62dd..a23d80b8 100644 --- a/httoop/util.py +++ b/httoop/util.py @@ -2,6 +2,7 @@ u"""Utilities for python2/3 compatibility.""" from __future__ import absolute_import +from __future__ import annotations import codecs import sys diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..5ab76d4a --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,163 @@ +[build-system] +requires = ["setuptools>=61", "six"] +build-backend = "setuptools.build_meta" + +[tool.setuptools.dynamic] +version = { attr = "httoop.version.__version__" } + +[project] +name = "httoop" +# version = "0.1.1" +dynamic = ["version"] +description = "object oriented HTTP protocol library" +readme = { file = "README.md", content-type = "text/markdown" } +authors = [ + { name = "SpaceOne", email = "space@wechall.net" } +] +license = { text = "MIT" } +keywords = ["HTTP", "web", "proxy", "cache", "client", "server", "library"] +classifiers = [ + "Environment :: Web Environment", + "Intended Audience :: Developers", + "Intended Audience :: Information Technology", + "License :: OSI Approved :: MIT License", + "Natural Language :: English", + "Operating System :: POSIX :: BSD", + "Operating System :: POSIX :: Linux", + "Operating System :: MacOS :: MacOS X", + "Operating System :: Microsoft :: Windows", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Topic :: Internet :: WWW/HTTP :: HTTP Servers", + "Topic :: Internet :: WWW/HTTP :: WSGI :: Application", + "Topic :: Internet :: WWW/HTTP :: WSGI :: Middleware", + "Topic :: Internet :: WWW/HTTP :: WSGI :: Server", + "Topic :: Software Development :: Libraries :: Application Frameworks", + "Topic :: Software Development :: Libraries :: Python Modules", +] + +requires-python = ">=3.8" + +dependencies = ["six"] + +[project.optional-dependencies] +xml = ["defusedxml"] +hal = ["uritemplate"] +test = [ + "pytest", + "pytest-cov", + "coveralls", + "defusedxml", +] + +[tool.pytest.ini_options] +addopts = "--tb=native --strict-markers --cov=httoop --cov-report=xml --cov-report=term-missing" + +[tool.setuptools.packages.find] +where = ["."] +exclude = ["tests", "tests.*"] + +[tool.setuptools] +zip-safe = true + +[project.urls] +Homepage = "https://github.com/spaceone/httoop" + +[tool.ruff] +line-length = 180 +target-version = "py37" + +[tool.ruff.lint] +preview = true +select = ["E", "W", "F", "I", "D", "TD", "ALL"] +ignore = [ + "E501", # line-too-long + "E203", # whitespace-before-punctuation + "COM812", # missing-trailing-comma + "D203", # one-blank-line-before-class + "D212", # multi-line-summary-first-line + "D400", # ends-in-period + "D415", # ends-in-punctuation + "D100", # Missing docstring in public module + "D101", # Missing docstring in public class + "D102", # Missing docstring in public method + "D103", # Missing docstring in public function + "D107", # Missing docstring in `__init__` + "D205", # 1 blank line required between summary line and description + "D105", # Missing docstring in magic method + "D401", # First line of docstring should be in imperative mood: "A shortcut to abspath, escape and lowercase." + "D402", # First line should not be the function's signature + "D403", # first-word-uncapitalized + "D404", # First word of the docstring should not be "This" + "D104", # Missing docstring in public package + "T201", "T203", # print, p-print + "TD001", # invalid-todo-tag + "TD002", # missing-todo-author + "TD003", # missing-todo-link + # "I", "S101", "Q000", "ANN", "ERA", "UP004", "ARG001", "ARG002", +] + + +# Exclude a variety of commonly ignored directories. +exclude = [ + ".bzr", + ".direnv", + ".eggs", + ".git", + ".hg", + ".mypy_cache", + ".nox", + ".pants.d", + ".ruff_cache", + ".svn", + ".tox", + ".venv", + "__pypackages__", + "_build", + "buck-out", + "build", + "dist", + "node_modules", + "venv", +] + +# Allow unused variables when underscore-prefixed. +dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$" + +task-tags = ["TODO", "FIXME"] + +[tool.ruff.lint.extend-per-file-ignores] +"tests/*" = [ + "ANN", + "S101", +] + +[tool.ruff.lint.mccabe] +max-complexity = 40 + +[tool.ruff.lint.flake8-quotes] +docstring-quotes = "double" +multiline-quotes = "double" +inline-quotes = "single" + +[tool.ruff.lint.flake8-unused-arguments] +ignore-variadic-names = true + +[tool.ruff.lint.flake8-pytest-style] +parametrize-names-type = "csv" + +[tool.ruff.format] +quote-style = "single" + +[tool.ruff.lint.isort] +combine-as-imports = true +#filter-files = true +#force-grid-wrap = false +known-first-party = ["httoop"] +# https://github.com/astral-sh/ruff/issues/2600 : +#multi-line-output = 5 +#include-trailing-comma = true +lines-after-imports = 2 +split-on-trailing-comma = false + +# length-sort = true diff --git a/requirements-test.txt b/requirements-test.txt deleted file mode 100644 index 8b45540a..00000000 --- a/requirements-test.txt +++ /dev/null @@ -1,5 +0,0 @@ -six -pytest -pytest-cov -coveralls -defusedxml diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 8806dfcb..00000000 --- a/requirements.txt +++ /dev/null @@ -1,3 +0,0 @@ -six -defusedxml -uritemplate diff --git a/setup.py b/setup.py deleted file mode 100755 index 985eb7ab..00000000 --- a/setup.py +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env python - -#from glob import glob -from setuptools import find_packages, setup - -from httoop.version import __version__ as version - -setup( - name='httoop', - version=version, - description='object oriented HTTP protocol library', - long_description=open('README.md').read(), - long_description_content_type='text/markdown', - author='SpaceOne', - author_email='space@wechall.net', - url='https://github.com/spaceone/httoop', - #download_url='', - classifiers=[ - 'Environment :: Web Environment', - 'Intended Audience :: Developers', - 'Intended Audience :: Information Technology', - 'License :: OSI Approved :: MIT License', - 'Natural Language :: English', - 'Operating System :: POSIX :: BSD', - 'Operating System :: POSIX :: Linux', - 'Operating System :: MacOS :: MacOS X', - 'Operating System :: Microsoft :: Windows', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', - 'Programming Language :: Python :: 3.8', - 'Programming Language :: Python :: 3.9', - 'Topic :: Internet :: WWW/HTTP :: HTTP Servers', - 'Topic :: Internet :: WWW/HTTP :: WSGI :: Application', - 'Topic :: Internet :: WWW/HTTP :: WSGI :: Middleware', - 'Topic :: Internet :: WWW/HTTP :: WSGI :: Server', - 'Topic :: Software Development :: Libraries :: Application Frameworks', - 'Topic :: Software Development :: Libraries :: Python Modules', - ], - license='MIT', - keywords='HTTP web proxy cache client server library', - platforms='POSIX', - packages=find_packages('.', exclude=['tests.*', 'tests']), - #scripts=glob('bin/*'), - install_requires=['six'], - entry_points={}, - test_suite='tests.main.main', - zip_safe=True -)