diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index b6f83d037..6e15485d7 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -19,7 +19,7 @@ jobs: - uses: actions/setup-python@v6 with: python-version: "3.13" - - run: pip install -r requirements.txt + - run: pip install --group lint -e . - run: pre-commit run --all-files - run: mypy kopf --strict - run: | @@ -51,7 +51,7 @@ jobs: with: python-version: ${{ matrix.python-version }} - - run: pip install -r requirements.txt + - run: pip install --group test -e . - run: pip install -e .[${{ matrix.install-extras }}] if: ${{ matrix.install-extras }} - run: pytest --color=yes --timeout=2 @@ -95,7 +95,7 @@ jobs: - run: sudo apt-get update && sudo apt-get install libxml2-dev libxslt-dev - run: pip install --upgrade pip wheel setuptools - - run: pip install -r requirements.txt + - run: pip install --group test -e . - run: pip install -e .[${{ matrix.install-extras }}] if: ${{ matrix.install-extras }} - run: pytest --color=yes --timeout=2 --no-cov @@ -117,7 +117,7 @@ jobs: with: version: ${{ matrix.k3s }} github-token: ${{ secrets.GITHUB_TOKEN }} - - run: pip install -r requirements.txt -r examples/requirements.txt + - run: pip install --group test -e . -r examples/requirements.txt - run: pytest --color=yes --timeout=30 --only-e2e coveralls-finish: diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 2fe25fb2c..5f1502e60 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -19,8 +19,8 @@ jobs: - uses: actions/setup-python@v6 with: python-version: "3.13" - - run: pip install --upgrade pip setuptools wheel twine - - run: python setup.py sdist bdist_wheel + - run: pip install --upgrade pip build + - run: python -m build # includes sdist & wheel by default - uses: pypa/gh-action-pypi-publish@release/v1 with: skip_existing: true diff --git a/.github/workflows/thorough.yaml b/.github/workflows/thorough.yaml index 61f88a899..4daf22615 100644 --- a/.github/workflows/thorough.yaml +++ b/.github/workflows/thorough.yaml @@ -23,7 +23,7 @@ jobs: - uses: actions/setup-python@v6 with: python-version: "3.13" - - run: pip install -r requirements.txt + - run: pip install --group lint -e . - run: pre-commit run --all-files - run: mypy kopf --strict - run: | @@ -55,7 +55,7 @@ jobs: with: python-version: ${{ matrix.python-version }} - - run: pip install -r requirements.txt + - run: pip install --group test -e . - run: pip install -e .[${{ matrix.install-extras }}] if: ${{ matrix.install-extras }} - run: pytest --color=yes --timeout=2 @@ -99,7 +99,7 @@ jobs: - run: sudo apt-get update && sudo apt-get install libxml2-dev libxslt-dev - run: pip install --upgrade pip wheel setuptools - - run: pip install -r requirements.txt + - run: pip install --group test -e . - run: pip install -e .[${{ matrix.install-extras }}] if: ${{ matrix.install-extras }} - run: pytest --color=yes --timeout=2 --no-cov @@ -121,7 +121,7 @@ jobs: with: version: ${{ matrix.k3s }} github-token: ${{ secrets.GITHUB_TOKEN }} - - run: pip install -r requirements.txt -r examples/requirements.txt + - run: pip install --group test -e . -r examples/requirements.txt - run: pytest --color=yes --timeout=30 --only-e2e full-scale: @@ -140,7 +140,7 @@ jobs: with: python-version: "3.13" - run: tools/install-minikube.sh - - run: pip install -r requirements.txt -r examples/requirements.txt + - run: pip install --group test -e . -r examples/requirements.txt - run: pytest --color=yes --timeout=30 --only-e2e coveralls-finish: diff --git a/.isort.cfg b/.isort.cfg deleted file mode 100644 index 3b3d09d8f..000000000 --- a/.isort.cfg +++ /dev/null @@ -1,11 +0,0 @@ -[settings] -line_length = 100 -multi_line_output = 11 -balanced_wrapping = true -combine_as_imports = true -case_sensitive = true - -known_first_party = kopf - -filter_files = true -skip_glob = examples/*.py diff --git a/.readthedocs.yaml b/.readthedocs.yaml index dc7361790..78beee6d1 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -6,10 +6,10 @@ build: os: ubuntu-24.04 tools: python: "3" -python: - install: - - requirements: requirements.txt - - requirements: docs/requirements.txt + jobs: + install: + - pip install --upgrade pip + - pip install --group docs -e . sphinx: configuration: docs/conf.py builder: "dirhtml" diff --git a/LICENSE b/LICENSE index 18bcd1c67..56b4464b5 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2020 Sergey Vasilyev +Copyright (c) 2020-2025 Sergey Vasilyev Copyright (c) 2019-2020 Zalando SE Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/docs/requirements.txt b/docs/requirements.txt deleted file mode 100644 index c3fbdce11..000000000 --- a/docs/requirements.txt +++ /dev/null @@ -1,7 +0,0 @@ -# Everything needed to build the docs. -# The runtime dependencies of the framework, as if via `pip install kopf`. --e . -sphinx>=2.0.0 -sphinx-autobuild -sphinx-autodoc-typehints -sphinx_rtd_theme>=0.5 diff --git a/examples/README.md b/examples/README.md index fc23c3141..148b47a53 100644 --- a/examples/README.md +++ b/examples/README.md @@ -9,5 +9,5 @@ kubectl apply -f crd.yaml Also, some libraries are needed for some operators and handlers: ```bash -pip install -r requirements.txt +pip install --group test -e . ``` diff --git a/kopf/__init__.py b/kopf/__init__.py index 83bc3a12b..e5d043321 100644 --- a/kopf/__init__.py +++ b/kopf/__init__.py @@ -38,7 +38,9 @@ Logger, ) from kopf._cogs.helpers.versions import ( - version as __version__, + __version__, + __version_tuple__, + __commit_id__, ) from kopf._cogs.structs.bodies import ( RawEventType, diff --git a/kopf/_cogs/helpers/.gitignore b/kopf/_cogs/helpers/.gitignore new file mode 100644 index 000000000..d36bde021 --- /dev/null +++ b/kopf/_cogs/helpers/.gitignore @@ -0,0 +1,2 @@ +# Auto-generated by setuptools-scm on builds & pip install. Configured in pyproject.toml. +versions.py diff --git a/kopf/_cogs/helpers/versions.py b/kopf/_cogs/helpers/versions.py deleted file mode 100644 index efb5f7200..000000000 --- a/kopf/_cogs/helpers/versions.py +++ /dev/null @@ -1,22 +0,0 @@ -""" -Detecting the framework's own version. - -The codebase does not contain the version directly, as it would require -code changes on every release. Kopf's releases depend on tagging rather -than in-code version bumps (Kopf's authour believes that versions belong -to the versioning system, not to the codebase). - -The version is determined only once at startup when the code is loaded. -""" -version: str | None = None - -try: - import importlib.metadata -except ImportError: - pass -else: - try: - name, *_ = __name__.split('.') # usually "kopf", unless renamed/forked. - version = importlib.metadata.version(name) - except Exception: - pass # installed as an egg, from git, etc. diff --git a/mypy.ini b/mypy.ini deleted file mode 100644 index fc40ca5e0..000000000 --- a/mypy.ini +++ /dev/null @@ -1,3 +0,0 @@ -[mypy] -warn_unused_configs = True -ignore_missing_imports = True diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 000000000..9f7fbf4b7 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,128 @@ +[build-system] +requires = ["setuptools", "setuptools-scm>=8.1"] +build-backend = "setuptools.build_meta" + +[project] +name = "kopf" +description = "Kubernetes Operator Pythonic Framework (Kopf)" +keywords = ["kubernetes", "operator", "framework", "python", "k8s"] +authors = [{name = "Sergey Vasilyev", email = "nolar@nolar.info"}] +maintainers = [{name = "Sergey Vasilyev", email = "nolar@nolar.info"}] +license = "MIT" +readme = "README.md" +classifiers = [ + "Intended Audience :: Developers", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", + "Topic :: Software Development :: Libraries", +] +requires-python = ">=3.10" +dependencies = [ + "python-json-logger", # 0.05 MB + "iso8601", # 0.07 MB + "pyyaml", # 0.90 MB + "click>=8.2.0", # 0.60 MB + "aiohttp", # 7.80 MB + "aiohttp>=3.9.0; python_version >= '3.12'", +] +dynamic = ["version"] # taken from git tags + +[project.urls] +homepage = "https://github.com/nolar/kopf" +repository = "https://github.com/nolar/kopf" +documentation = "https://kopf.readthedocs.io" + +[project.scripts] +kopf = "kopf.cli:main" + +[project.optional-dependencies] +full-auth = [ + "pykube-ng", # 4.90 MB + "kubernetes", # 40.0 MB (!) +] +uvloop = [ + "uvloop", # 9.00 MB + "uvloop>=0.18.0; python_version>='3.12'", +] +dev = [ + # NB: oscrypto is pinned for Ubuntu 24.04+ in dependency-group - read the details there. + "oscrypto", # 2.80 MB (smaller than cryptography: 8.7 MB) + "certbuilder", # +0.1 MB (2.90 MB if alone) + "certvalidator", # +0.1 MB (2.90 MB if alone) + "pyngrok", # 1.00 MB + a downloaded binary +] + +[dependency-groups] +docs = [ + "sphinx>=2.0.0", + "sphinx-autobuild", + "sphinx-autodoc-typehints", + "sphinx_rtd_theme>=0.5", +] +test = [ + "aresponses", + "astpath[xpath]", + "certbuilder", + "certvalidator", + "codecov", + "coverage", + "coveralls", + "freezegun", + "lxml", + "pyngrok", + "pytest>=6.0.0", + "pytest-aiohttp", + "pytest-asyncio", + "pytest-cov", + "pytest-mock", + "pytest-timeout", + "types-pyyaml", + "types-setuptools", + + # Enforce the hotfix for Ubuntu 24.04 in CI. Otherwise, we are stuck in Ubuntu 22.04. + # The bugfix is merged but not released: https://github.com/wbond/oscrypto/issues/78 + # Pinning this in the final operators is the decision of the operator developers, + # including the protocols of accessing the repo or vendoring the dependency code. + # The dev-mode dependency is used ONLY with a temporary insecure self-signed CA for simplicity, + # and ONLY with Ubuntu 24.04+. Therefore, it is not pinned in the main dependencies (e.g., works fine in 22.04). + # In the worst case, configure the operator with a self-signed CA made in the OpenSSL CLI. + "oscrypto @ git+https://github.com/wbond/oscrypto.git@1547f535001ba568b239b8797465536759c742a3", +] +lint = [ + {include-group = "test"}, + "mypy==1.19.0", + "import-linter", + "isort", + "pre-commit", +] + +[tool.setuptools_scm] +version_file = "kopf/_cogs/helpers/versions.py" + +[tool.mypy] +warn_unused_configs = true +ignore_missing_imports = true + +[tool.pytest] +minversion = "9.0" +asyncio_mode = "auto" +asyncio_default_fixture_loop_scope = "function" +addopts = ["--strict-markers"] + +[tool.isort] +line_length = 100 +multi_line_output = 11 +balanced_wrapping = true +combine_as_imports = true +case_sensitive = true +known_first_party = ["kopf"] +filter_files = true +skip_glob = ["examples/*.py"] diff --git a/pytest.ini b/pytest.ini deleted file mode 100644 index e961ed799..000000000 --- a/pytest.ini +++ /dev/null @@ -1,5 +0,0 @@ -[pytest] -asyncio_mode = auto -asyncio_default_fixture_loop_scope = function -addopts = - --strict-markers diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 75588af15..000000000 --- a/requirements.txt +++ /dev/null @@ -1,35 +0,0 @@ -# Everything needed to develop (test, debug) the framework. -# The runtime dependencies of the framework, as if via `pip install kopf`. --e . -aresponses -astpath[xpath] -certbuilder -certvalidator -codecov -coverage -coveralls -freezegun - -# Enforce the hotfix for Ubuntu 24.04 in CI. Otherwise, we are stuck in Ubuntu 22.04. -# The bugfix is merged but not released: https://github.com/wbond/oscrypto/issues/78 -# Pinning this in the end operators is the decision of the operator developers, -# including the protocols of accessing the repo or vendoring the dependency code. -# The dev-mode dependency is used ONLY with an temporary & insecure self-signed CA for simplicity, -# and ONLY with Ubuntu 24.04+. Therefore, it is not pinned in setup.py (e.g., works fine in 22.04). -# In the worst case, configure the operator with a self-signed CA made in the OpenSSL CLI manually. -git+https://github.com/wbond/oscrypto.git@1547f535001ba568b239b8797465536759c742a3 - -import-linter -isort -lxml -mypy==1.18.2 -pre-commit -pyngrok -pytest>=6.0.0 -pytest-aiohttp -pytest-asyncio -pytest-cov -pytest-mock -pytest-timeout -types-PyYAML -types-setuptools diff --git a/setup.py b/setup.py deleted file mode 100644 index 2cea7ac7a..000000000 --- a/setup.py +++ /dev/null @@ -1,85 +0,0 @@ -import os.path - -from setuptools import find_packages, setup - -with open(os.path.join(os.path.dirname(__file__), 'README.md')) as f: - LONG_DESCRIPTION = f.read() - DESCRIPTION = LONG_DESCRIPTION.splitlines()[0].lstrip('#').strip() - -PROJECT_URLS = { - 'Documentation': 'https://kopf.readthedocs.io', - 'Bug Tracker': 'https://github.com/nolar/kopf/issues', - 'Source Code': 'https://github.com/nolar/kopf', -} - -setup( - name='kopf', - use_scm_version=True, - - url=PROJECT_URLS['Source Code'], - project_urls=PROJECT_URLS, - description=DESCRIPTION, - long_description=LONG_DESCRIPTION, - long_description_content_type='text/markdown', - author='Sergey Vasilyev', - author_email='nolar@nolar.info', - maintainer='Sergey Vasilyev', - maintainer_email='nolar@nolar.info', - keywords=['kubernetes', 'operator', 'framework', 'python', 'k8s'], - license='MIT', - classifiers = [ - 'Intended Audience :: Developers', - 'License :: OSI Approved :: MIT License', - 'Operating System :: OS Independent', - 'Programming Language :: Python', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.10', - 'Programming Language :: Python :: 3.11', - 'Programming Language :: Python :: 3.12', - 'Programming Language :: Python :: 3.13', - 'Programming Language :: Python :: 3 :: Only', - 'Programming Language :: Python :: Implementation :: CPython', - 'Programming Language :: Python :: Implementation :: PyPy', - 'Topic :: Software Development :: Libraries', - ], - - zip_safe=True, - packages=find_packages(), - include_package_data=True, - entry_points={ - 'console_scripts': [ - 'kopf = kopf.cli:main', - ], - }, - - python_requires='>=3.10', - setup_requires=[ - 'setuptools_scm', - ], - install_requires=[ - 'python-json-logger', # 0.05 MB - 'iso8601', # 0.07 MB - 'click>=8.2.0', # 0.60 MB - 'aiohttp', # 7.80 MB - 'aiohttp>=3.9.0; python_version>="3.12"', - 'pyyaml', # 0.90 MB - ], - extras_require={ - 'full-auth': [ - 'pykube-ng', # 4.90 MB - 'kubernetes', # 40.0 MB (!) - ], - 'uvloop': [ - 'uvloop', # 9.00 MB - 'uvloop>=0.18.0; python_version>="3.12"', - ], - 'dev': [ - # NB: oscrypto is pinned for Ubuntu 24.04+ in requirements.txt - read the details there. - 'oscrypto', # 2.80 MB (smaller than cryptography: 8.7 MB) - 'certbuilder', # +0.1 MB (2.90 MB if alone) - 'certvalidator', # +0.1 MB (2.90 MB if alone) - 'pyngrok', # 1.00 MB + downloaded binary - ], - }, - package_data={"kopf": ["py.typed"]}, -)