diff --git a/.codeclimate.yml b/.codeclimate.yml deleted file mode 100644 index 247204ce2..000000000 --- a/.codeclimate.yml +++ /dev/null @@ -1,6 +0,0 @@ -# Save as .codeclimate.yml (note leading .) in project root directory -languages: - Python: true -exclude_paths: - - "tests/*" - - "connexion/swagger-ui/*" diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml index 6d85a4c77..191cb6467 100644 --- a/.github/workflows/pipeline.yml +++ b/.github/workflows/pipeline.yml @@ -19,7 +19,7 @@ jobs: - name: Install dependencies run: | pip install --upgrade pip - pip install "tox<4" "tox-gh-actions<3" "setuptools<58" "coveralls<4" + pip install "poetry<2" "tox<4" "tox-gh-actions<3" "coveralls<4" - name: Test with tox run: tox - name: Coveralls diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b10af0773..67005e0d7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -19,13 +19,12 @@ jobs: python-version: 3.9 - name: Update version - run: sed -i "s/__version__ = .*/__version__ = '${{github.ref_name}}'/" */__init__.py + run: sed -i "s/^version = .*/version = '${{github.ref_name}}'/" pyproject.toml - name: Build a binary wheel and a source tarball run: | - pip install --upgrade pip - pip install wheel - python setup.py sdist bdist_wheel + pip install poetry + poetry build - name: Publish distribution 📦 to Test PyPI if: github.event_name == 'push' diff --git a/.gitignore b/.gitignore index a22702e96..c63e03a57 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ venv/ .venv/ src/ *.un~ +poetry.lock diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f81d001f5..25e4ef40c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -11,7 +11,7 @@ repos: - flake8-rst-docstrings==0.2.3 - repo: https://github.com/PyCQA/isort - rev: 5.10.1 + rev: 5.12.0 hooks: - id: isort name: isort diff --git a/MAINTAINERS b/MAINTAINERS deleted file mode 100644 index 8e5a26b3a..000000000 --- a/MAINTAINERS +++ /dev/null @@ -1,5 +0,0 @@ -João Santos -Henning Jacobs -Daniel Grossmann-Kavanagh -Ruwan Lambrichts -Robbe Sneyders diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index e80f40b8c..000000000 --- a/MANIFEST.in +++ /dev/null @@ -1,3 +0,0 @@ -include *.txt -include *.rst -recursive-include connexion/resources *.json diff --git a/README.rst b/README.rst index 23aae9e7e..bdc2d6491 100644 --- a/README.rst +++ b/README.rst @@ -583,12 +583,12 @@ Contributing to Connexion/TODOs We welcome your ideas, issues, and pull requests. Just follow the usual/standard GitHub practices. -For easy development, install connexion in editable mode with the :code:`tests` extra, and +For easy development, install connexion using poetry with all extras, and install the pre-commit hooks to automatically run black formatting and static analysis checks. .. code-block:: bash - pip install -e .[tests] + poetry install --all-extras pre-commit install You can find out more about how Connexion works and where to apply your changes by having a look diff --git a/SECURITY.md b/SECURITY.md deleted file mode 100644 index 057739718..000000000 --- a/SECURITY.md +++ /dev/null @@ -1,8 +0,0 @@ -We acknowledge that every line of code that we write may potentially contain security issues. -We are trying to deal with it responsibly and provide patches as quickly as possible. - -We host our bug bounty program on HackerOne, it is currently private, therefore if you would like to report a vulnerability and get rewarded for it, please ask to join our program by filling this form: - -https://corporate.zalando.com/en/services-and-contact#security-form - -You can also send your report via this form if you do not want to join our bug bounty program and just want to report a vulnerability or security issue. diff --git a/bandit.yml b/bandit.yml deleted file mode 100644 index ee776b27c..000000000 --- a/bandit.yml +++ /dev/null @@ -1,2 +0,0 @@ -skips: - - "B101" # https://docs.openstack.org/bandit/latest/plugins/b101_assert_used.html diff --git a/connexion/__init__.py b/connexion/__init__.py index 271926ba4..6508a3710 100755 --- a/connexion/__init__.py +++ b/connexion/__init__.py @@ -31,6 +31,3 @@ App = FlaskApp Api = FlaskApi - -# This version is replaced during release process. -__version__ = "3.0.dev0" diff --git a/connexion/cli.py b/connexion/cli.py index 7884d2f8c..f8cb5c36b 100644 --- a/connexion/cli.py +++ b/connexion/cli.py @@ -8,6 +8,7 @@ from os import path import click +import importlib_metadata from clickclick import AliasedGroup, fatal_error import connexion @@ -47,7 +48,7 @@ def validate_server_requirements(ctx, param, value): def print_version(ctx, param, value): if not value or ctx.resilient_parsing: return - click.echo(f"Connexion {connexion.__version__}") + click.echo(f"Connexion {importlib_metadata.version('connexion')}") ctx.exit() diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 000000000..3f4e23920 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,95 @@ +[tool.poetry] +name = "connexion" +version = "3.0.dev0" +description = "Connexion - API first applications with OpenAPI/Swagger" +readme = "README.rst" +keywords = ["api", "swagger", "openapi"] +license = "Apache-2.0" +authors = [ + "Daniel Grossmann-Kavanagh ", + "Henning Jacobs ", + "João Santos ", + "Robbe Sneyders ", + "Ruwan Lambrichts ", +] +maintainers = [ + "Robbe Sneyders ", + "Ruwan Lambrichts ", +] +repository = "https://github.com/spec-first/connexion" +include = ["*.txt", "*.rst"] +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "License :: OSI Approved :: Apache Software License", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3 :: Only", + "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", + "Topic :: Internet", + "Topic :: Internet :: WWW/HTTP", + "Topic :: Internet :: WWW/HTTP :: HTTP Servers", + "Topic :: Software Development", + "Topic :: Software Development :: Libraries", + "Topic :: Software Development :: Libraries :: Python Modules", + "Typing :: Typed", +] + +[tool.poetry.scripts] +connexion = 'connexion.cli:main' + +[tool.poetry.dependencies] +python = '^3.7' +clickclick = ">= 1.2, < 21" +httpx = "^0.15" +importlib_metadata = { version = "^6.0.0", python = "<3.8" } +inflection = ">= 0.3.1, < 0.6" +jsonschema = "^4.0.1" +Jinja2 = "^3.0.0" +python-multipart = "~0.0.5" +PyYAML = ">= 5.1, < 7" +requests = "^2.27" +starlette = "^0.19" +typing-extensions = "^4" +werkzeug = "^2.2.1" + +a2wsgi = { version = "^1.4", optional = true } +flask = { version = "^2.2", extras = ["async"], optional = true } +py-swagger-ui = { version = "^1.1.0", optional = true } +uvicorn = { version = "^0.17.6", extras = ["standard"], optional = true } + +[tool.poetry.extras] +flask = ["a2wsgi", "flask"] +swagger-ui = ["py-swagger-ui"] +uvicorn = ["uvicorn"] + +[tool.poetry.group.tests.dependencies] +pre-commit = "~2.21.0" +pytest = "7.2.1" +pytest-asyncio = "~0.18.3" +pytest-cov = "~2.12.1" + +[tool.poetry.group.docs.dependencies] +sphinx-autoapi = "1.8.1" + +[build-system] +requires = ["poetry-core>=1.2.0"] +build-backend = "poetry.core.masonry.api" + +[tool.distutils.bdist_wheel] +universal = true + +[tool.pytest.ini_options] +filterwarnings = [ + "ignore::DeprecationWarning:connexion.*:", + "ignore::FutureWarning:connexion.*:", +] +asyncio_mode = "auto" + +[tool.isort] +profile = "black" diff --git a/pytest.ini b/pytest.ini deleted file mode 100644 index de19084f1..000000000 --- a/pytest.ini +++ /dev/null @@ -1,5 +0,0 @@ -[pytest] -filterwarnings = - ignore::DeprecationWarning:connexion.*: - ignore::FutureWarning:connexion.*: -asyncio_mode = auto diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 3480374bc..000000000 --- a/setup.cfg +++ /dev/null @@ -1,2 +0,0 @@ -[bdist_wheel] -universal=1 \ No newline at end of file diff --git a/setup.py b/setup.py deleted file mode 100755 index b59fb4e53..000000000 --- a/setup.py +++ /dev/null @@ -1,126 +0,0 @@ -#!/usr/bin/env python3 - -import inspect -import os -import sys - -from setuptools import find_packages, setup -from setuptools.command.test import test as TestCommand - -__location__ = os.path.join(os.getcwd(), os.path.dirname(inspect.getfile(inspect.currentframe()))) - - -def read_version(package): - with open(os.path.join(package, '__init__.py')) as fd: - for line in fd: - if line.startswith('__version__ = '): - return line.split()[-1].strip().strip("'") - - -version = read_version('connexion') - -install_requires = [ - 'clickclick>=1.2,<21', - 'jsonschema>=4.0.1,<5', - 'PyYAML>=5.1,<7', - 'requests>=2.27,<3', - 'inflection>=0.3.1,<0.6', - 'werkzeug>=2.2.1,<3', - 'starlette>=0.19,<1', - 'httpx>=0.15,<1', - 'typing-extensions>=4,<5', - 'python-multipart>=0.0.5', -] - -swagger_ui_require = 'py-swagger-ui>=1.1.0,<2' - -flask_require = [ - 'flask[async]>=2.2,<3', - 'a2wsgi>=1.4,<2', -] - -tests_require = [ - 'pytest>=6,<7', - 'pytest-asyncio>=0.18,<0.19', - 'pre-commit>=2,<3', - 'pytest-cov>=2,<3', - *flask_require, - swagger_ui_require -] - -docs_require = [ - 'sphinx-autoapi==1.8.1' -] - -uvicorn_requires = [ - 'uvicorn[standard]>=0.17.6' -] - - -class PyTest(TestCommand): - - user_options = [('cov-html=', None, 'Generate junit html report')] - - def initialize_options(self): - TestCommand.initialize_options(self) - self.cov = None - self.pytest_args = ['--cov', 'connexion', '--cov-report', 'term-missing', '-v', "--asyncio-mode", "auto"] - self.cov_html = False - - def finalize_options(self): - TestCommand.finalize_options(self) - if self.cov_html: - self.pytest_args.extend(['--cov-report', 'html']) - self.pytest_args.extend(['tests']) - - def run_tests(self): - import pytest - - errno = pytest.main(self.pytest_args) - sys.exit(errno) - - -def readme(): - try: - return open('README.rst', encoding='utf-8').read() - except TypeError: - return open('README.rst').read() - - -setup( - name='connexion', - packages=find_packages(), - version=version, - description='Connexion - API first applications with OpenAPI/Swagger and Flask', - long_description=readme(), - author='Zalando SE', - url='https://github.com/spec-first/connexion', - keywords='openapi oai swagger rest api oauth flask microservice framework', - license='Apache License Version 2.0', - python_requires=">=3.6", - install_requires=install_requires + flask_require, - tests_require=tests_require, - extras_require={ - 'tests': tests_require, - 'flask': flask_require, - 'swagger-ui': swagger_ui_require, - 'docs': docs_require, - 'uvicorn': uvicorn_requires, - }, - cmdclass={'test': PyTest}, - test_suite='tests', - classifiers=[ - 'Programming Language :: Python', - 'Programming Language :: Python :: 3.7', - 'Programming Language :: Python :: 3.8', - 'Programming Language :: Python :: 3.9', - 'Programming Language :: Python :: 3.10', - 'Development Status :: 5 - Production/Stable', - 'Intended Audience :: Developers', - 'Operating System :: OS Independent', - 'Topic :: Internet :: WWW/HTTP :: WSGI :: Application', - 'Topic :: Software Development :: Libraries :: Application Frameworks' - ], - include_package_data=True, # needed to include swagger-ui (see MANIFEST.in) - entry_points={'console_scripts': ['connexion = connexion.cli:main']} -) diff --git a/tests/test_cli.py b/tests/test_cli.py index 773815e14..5109f8d4f 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -2,6 +2,7 @@ from unittest.mock import MagicMock import connexion +import importlib_metadata import pytest from click.testing import CliRunner from connexion.cli import main @@ -51,7 +52,7 @@ def spec_file(): def test_print_version(): runner = CliRunner() result = runner.invoke(main, ["--version"], catch_exceptions=False) - assert f"Connexion {connexion.__version__}" in result.output + assert f"Connexion {importlib_metadata.version('connexion')}" in result.output def test_run_missing_spec(): diff --git a/tox.ini b/tox.ini index 180be736d..8edc74cb3 100644 --- a/tox.ini +++ b/tox.ini @@ -6,37 +6,35 @@ rst-roles=class,mod,obj max-line-length=137 extend-ignore=E203 -[isort] -profile = black - [tox] +isolated_build = True envlist = - {py37}-{min,pypi,dev} - {py38}-{min,pypi,dev} - {py39}-{min,pypi,dev} - {py310}-{min,pypi,dev} + {py37,py38,py39,py310}-{min,pypi} pre-commit - mypy [gh-actions] python = 3.7: py37-min,py37-pypi 3.8: py38-min,py38-pypi 3.9: py39-min,py39-pypi - 3.10: py310-min,py310-pypi,pre-commit,mypy + 3.10: py310-min,py310-pypi,pre-commit [testenv] setenv=PYTHONPATH = {toxinidir}:{toxinidir} -deps=pytest +deps= + poetry +allowlist_externals= + cp + sed + mv commands= - pip install Requirements-Builder - min: requirements-builder --level=min -o {toxworkdir}/requirements-min.txt setup.py - min: pip install --upgrade -r {toxworkdir}/requirements-min.txt - pypi: requirements-builder --level=pypi -o {toxworkdir}/requirements-pypi.txt setup.py - pypi: pip install --upgrade -r {toxworkdir}/requirements-pypi.txt - dev: requirements-builder --level=dev --req=requirements-devel.txt -o {toxworkdir}/requirements-dev.txt setup.py - dev: pip install --upgrade -r {toxworkdir}/requirements-dev.txt - python setup.py test + min: cp pyproject.toml .pyproject.toml + min: sed -i -E 's/"(\^|~|>=)([ 0-9])/"==\2/' pyproject.toml + poetry lock + poetry install --all-extras --with tests + poetry show + poetry run python -m pytest tests --cov connexion --cov-report term-missing + min: mv -f .pyproject.toml pyproject.toml [testenv:pre-commit] deps=pre-commit