From 2a5d3d8d8653fa13933369570566377458255b37 Mon Sep 17 00:00:00 2001 From: Pandu POLUAN Date: Thu, 22 Dec 2022 04:08:38 +0700 Subject: [PATCH 1/8] Migrate from setup.{py,cfg} to pyproject.toml This also requires additional exclusions or pytype will get confused --- .../workflows/unit-testing-and-coverage.yml | 6 +- pyproject.toml | 56 ++++++++++++++++ release.py | 16 +++-- setup.cfg | 64 ++----------------- setup.py | 3 - 5 files changed, 76 insertions(+), 69 deletions(-) delete mode 100644 setup.py diff --git a/.github/workflows/unit-testing-and-coverage.yml b/.github/workflows/unit-testing-and-coverage.yml index e867f071b..3cf894660 100644 --- a/.github/workflows/unit-testing-and-coverage.yml +++ b/.github/workflows/unit-testing-and-coverage.yml @@ -38,7 +38,7 @@ jobs: # language=bash run: | python -m pip install --upgrade pip setuptools wheel - python setup.py develop + python -m pip install . # Common deps pip install colorama - name: "flake8 Style Checking" @@ -69,6 +69,8 @@ jobs: pip install dnspython argon2-cffi # Install pytype pip install pytype + # List files & dirs so if pytype blows up we can see what else to exclude + ls -la pytype --keep-going --jobs auto . - name: "Other QA Checks" shell: bash @@ -110,7 +112,7 @@ jobs: # Test deps pip install colorama "coverage>=7.0.1" coverage[toml] "coverage-conditional-plugin>=0.5.0" packaging pytest pytest-cov pytest-mock # Package deps - python setup.py develop + python -m pip install . - name: "Security checking" # language=bash run: | diff --git a/pyproject.toml b/pyproject.toml index 8731e6055..76d643b87 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,63 @@ +# region #### setuptools settings ########## + [build-system] requires = ["setuptools", "wheel"] build-backend = "setuptools.build_meta" +[project] +name = "aiosmtpd" +requires-python = ">=3.7" +dynamic = ["version"] +description = "aiosmtpd - asyncio based SMTP server" +readme = "DESCRIPTION.rst" +urls."Home Page" = "https://aiosmtpd.readthedocs.io/" +urls."Bug Tracker" = "https://github.com/aio-libs/aiosmtpd/issues" +urls."Documentation" = "https://aiosmtpd.readthedocs.io/" +urls."Source Code" = "https://github.com/aio-libs/aiosmtpd" +maintainers = [ + { name = "The aiosmtpd Developers", email = "aiosmtpd@googlegroups.com"} +] +keywords = [ "email", "smtpd", "smtp", "async"] +license.file = "LICENSE" +classifiers = [ + "License :: OSI Approved", + "License :: OSI Approved :: Apache Software License", + "Intended Audience :: Developers", + "Operating System :: Microsoft :: Windows", + "Operating System :: POSIX :: BSD :: FreeBSD", + "Operating System :: POSIX :: Linux", + "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", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", + "Topic :: Communications :: Email :: Mail Transport Agents", + "Framework :: AsyncIO", +] +dependencies = [ + "atpublic", + "attrs", + "typing-extensions ; python_version < '3.8'", +] + +[project.scripts] +aiosmtpd = "aiosmtpd.main:main" + +[tool.setuptools] +zip-safe = false + +[tool.setuptools.dynamic] +version = { attr = "aiosmtpd.__version__" } + +[tool.setuptools.packages.find] +where = ["."] +include = ["aiosmtpd*"] + +# endregion + [tool.pytest.ini_options] addopts = """--strict-markers -rfEX""" markers = [ diff --git a/release.py b/release.py index e6313b3e3..8b39dcff1 100755 --- a/release.py +++ b/release.py @@ -28,8 +28,12 @@ f"dist/aiosmtpd-{ver_str}-py3-none-any.whl", ] +RELEASE_TOOLKIT = ["setuptools", "wheel", "twine", "build"] + printfl("Updating release toolkit first...", end="") -run_hidden([sys.executable] + shlex.split("-m pip install -U setuptools wheel twine")) +run_hidden( + [sys.executable] + shlex.split("-m pip install -U") + RELEASE_TOOLKIT +) print() printfl("Checking extra toolkit...", end="") @@ -91,10 +95,12 @@ try: # Let's use *this* python to build, please - print("### setup.py sdist") - subprocess.run([sys.executable, "setup.py", "sdist"], check=True) - print("### setup.py sdist") - subprocess.run([sys.executable, "setup.py", "bdist_wheel"], check=True) + # print("### setup.py sdist") + # subprocess.run([sys.executable, "setup.py", "sdist"], check=True) + # print("### setup.py sdist") + # subprocess.run([sys.executable, "setup.py", "bdist_wheel"], check=True) + print("### build (sdist and wheel") + subprocess.run([sys.executable, "-m", "build"]) for f in DISTFILES: assert Path(f).exists(), f"{f} is missing!" diff --git a/setup.cfg b/setup.cfg index a00d13cfb..dea14ed3a 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,66 +1,12 @@ -[metadata] -name = aiosmtpd -version = attr: aiosmtpd.__version__ -description = aiosmtpd - asyncio based SMTP server -long_description = file: DESCRIPTION.rst -long_description_content_type = text/x-rst -url = https://aiosmtpd.readthedocs.io/ -project_urls = - Bug Tracker = https://github.com/aio-libs/aiosmtpd/issues - Documentation = https://aiosmtpd.readthedocs.io/ - Source Code = https://github.com/aio-libs/aiosmtpd -maintainer = The aiosmtpd Developers -maintainer_email = aiosmtpd@googlegroups.com -keywords = email, smtpd, smtp -license = Apache-2.0 -classifiers = - License :: OSI Approved - License :: OSI Approved :: Apache Software License - Intended Audience :: Developers - Operating System :: Microsoft :: Windows - Operating System :: POSIX :: BSD :: FreeBSD - Operating System :: POSIX :: Linux - 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 - Programming Language :: Python :: Implementation :: CPython - Programming Language :: Python :: Implementation :: PyPy - Topic :: Communications :: Email :: Mail Transport Agents - Framework :: AsyncIO - -[options] -zip_safe = false -python_requires = ~=3.7 -packages = find: -include_package_data = true -setup_requires = - setuptools -install_requires = - atpublic - attrs - typing-extensions ; python_version < '3.8' -tests_require = - tox - setuptools - -[options.packages.find] -exclude = - examples - -[options.entry_points] -console_scripts = - aiosmtpd = aiosmtpd.main:main - -[easy_install] -zip_ok = false - [pytype] exclude = aiosmtpd/docs/_exts/* _dump/* + aiosmtpd.egg-info/* + build/* + dist/* + Lib/* + Scripts/* disable = not-supported-yet diff --git a/setup.py b/setup.py deleted file mode 100644 index 606849326..000000000 --- a/setup.py +++ /dev/null @@ -1,3 +0,0 @@ -from setuptools import setup - -setup() From dbb327509270f20bef69c23cc17da9b88c1045e7 Mon Sep 17 00:00:00 2001 From: Pandu POLUAN Date: Thu, 22 Dec 2022 04:11:20 +0700 Subject: [PATCH 2/8] Force flake8 to use pyproject.toml using flake8-pyproject plugin --- .../workflows/unit-testing-and-coverage.yml | 4 +- pyproject.toml | 67 ++++++++++++++++++ setup.cfg | 70 ------------------- tox.ini | 1 + 4 files changed, 71 insertions(+), 71 deletions(-) diff --git a/.github/workflows/unit-testing-and-coverage.yml b/.github/workflows/unit-testing-and-coverage.yml index 3cf894660..7b295ffa1 100644 --- a/.github/workflows/unit-testing-and-coverage.yml +++ b/.github/workflows/unit-testing-and-coverage.yml @@ -53,7 +53,9 @@ jobs: "print(config['flake8_plugins']['deps']);" ) pip install "flake8>=5.0.4" $(python -c "${grab_f8_plugins[*]}") - python -m flake8 aiosmtpd setup.py housekeep.py release.py + echo "Running flake8 ... there will be no output if no errors:" + python -m flake8 aiosmtpd housekeep.py release.py + echo "flake8 done." - name: "Docs Checking" # language=bash run: | diff --git a/pyproject.toml b/pyproject.toml index 76d643b87..c6748046a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -138,3 +138,70 @@ known_local_folder = [ "aiosmtpd" ] combine_as_imports = true + + +[tool.flake8] +max-line-length = 88 +select = ["E", "F", "W", "C90", "C4", "MOD", "JS", "PIE", "PT", "SIM", "ECE", "C801", "DUO", "TAE", "ANN", "YTT", "N400"] +ignore = [ + # black conflicts with E123 & E133 + "E123", + "E133", + # W503 conflicts with PEP8... + "W503", + # W293 is a bit too noisy. Many files have been edited using editors that do not remove spaces from blank lines. + "W293", + # Sometimes spaces around colons improve readability + "E203", + # Sometimes we prefer the func()-based creation, not literal, for readability + "C408", + # Sometimes we need to catch Exception broadly + "PIE786", + # We don't really care about pytest.fixture vs pytest.fixture() + "PT001", + # Good idea, but too many changes. Remove this in the future, and create separate PR + "PT004", + # Sometimes exception needs to be explicitly raised in special circumstances, needing additional lines of code + "PT012", + # I still can't grok the need to annotate "self" or "cls" ... + "ANN101", + "ANN102", + # I don't think forcing annotation for *args and **kwargs is a wise idea... + "ANN002", + "ANN003", + # We have too many "if..elif..else: raise" structures that does not convert well to "error-first" design + "SIM106", + # We have too many 'Any' type annotations. + "ANN401", + # Classes for some reason aren't always just replaceable by modules. + "PIE798", + # It is cleaner sometimes to assign and return, especially when using 'await' expressions. + "PIE781", + # Use f'strings instead of % formatters, the performance impact isn't too bad and f'strings are awesome! + "PIE803", + # It is more readable to instantiate and add items on-by-one instead of all at once. + "PIE799", + # Explicit is better than implicit, range(0, val) is more explicit than range(val). + "PIE808", +] +per-file-ignores = [ + "aiosmtpd/tests/test_*:ANN001", + "aiosmtpd/tests/test_proxyprotocol.py:DUO102", + "aiosmtpd/docs/_exts/autoprogramm.py:C801", +] +# flake8-coding +no-accept-encodings = true +# flake8-copyright +copyright-check = true +# The number below was determined empirically by bisecting from 100 until no copyright-unnecessary files appear +copyright-min-file-size = 44 +copyright-author = "The aiosmtpd Developers" +# flake8-annotations-complexity +max-annotations-complexity = 4 +# flake8-annotations-coverage +min-coverage-percents = 12 +# flake8-annotations +mypy-init-return = true +suppress-none-returning = true +suppress-dummy-args = true +allow-untyped-defs = true diff --git a/setup.cfg b/setup.cfg index dea14ed3a..db8d8adf3 100644 --- a/setup.cfg +++ b/setup.cfg @@ -9,73 +9,3 @@ exclude = Scripts/* disable = not-supported-yet - -[build_sphinx] -source-dir = aiosmtpd/docs - -[flake8] -jobs = 1 -max-line-length = 88 -# "E,F,W,C90" are flake8 defaults -# For others, take a gander at tox.ini to see which prefix provided by who -select = E,F,W,C90,C4,MOD,JS,PIE,PT,SIM,ECE,C801,DUO,TAE,ANN,YTT,N400 -ignore = - # black conflicts with E123 & E133 - E123 - E133 - # W503 conflicts with PEP8... - W503 - # W293 is a bit too noisy. Many files have been edited using editors that do not remove spaces from blank lines. - W293 - # Sometimes spaces around colons improve readability - E203 - # Sometimes we prefer the func()-based creation, not literal, for readability - C408 - # Sometimes we need to catch Exception broadly - PIE786 - # We don't really care about pytest.fixture vs pytest.fixture() - PT001 - # Good idea, but too many changes. Remove this in the future, and create separate PR - PT004 - # Sometimes exception needs to be explicitly raised in special circumstances, needing additional lines of code - PT012 - # I still can't grok the need to annotate "self" or "cls" ... - ANN101 - ANN102 - # I don't think forcing annotation for *args and **kwargs is a wise idea... - ANN002 - ANN003 - # We have too many "if..elif..else: raise" structures that does not convert well to "error-first" design - SIM106 - # We have too many 'Any' type annotations. - ANN401 - # Classes for some reason aren't always just replaceable by modules. - PIE798 - # It is cleaner sometimes to assign and return, especially when using 'await' expressions. - PIE781 - # Use f'strings instead of % formatters, the performance impact isn't too bad and f'strings are awesome! - PIE803 - # It is more readable to instantiate and add items on-by-one instead of all at once. - PIE799 - # Explicit is better than implicit, range(0, val) is more explicit than range(val). - PIE808 -per-file-ignores = - aiosmtpd/tests/test_*:ANN001 - aiosmtpd/tests/test_proxyprotocol.py:DUO102 - aiosmtpd/docs/_exts/autoprogramm.py:C801 -# flake8-coding -no-accept-encodings = True -# flake8-copyright -copyright-check = True -# The number below was determined empirically by bisecting from 100 until no copyright-unnecessary files appear -copyright-min-file-size = 44 -copyright-author = The aiosmtpd Developers -# flake8-annotations-complexity -max-annotations-complexity = 4 -# flake8-annotations-coverage -min-coverage-percents = 12 -# flake8-annotations -mypy-init-return = True -suppress-none-returning = True -suppress-dummy-args = True -allow-untyped-defs = True diff --git a/tox.ini b/tox.ini index 211e78da2..507db37bf 100644 --- a/tox.ini +++ b/tox.ini @@ -59,6 +59,7 @@ passenv = # IMPORTANT: It's a good idea to restrict the version numbers of the plugins. Without version limits, GHCI's pip # sometimes simply gives up trying to figure the right deps, causing the test to fail. deps = + flake8-pyproject>=1.2.2 flake8-bugbear>=22.12.6 flake8-builtins>=2.0.1 flake8-coding>=1.3.2 From 3a756a721d24002e31a3172dcea1d9b425889b55 Mon Sep 17 00:00:00 2001 From: Pandu POLUAN Date: Thu, 22 Dec 2022 04:11:36 +0700 Subject: [PATCH 3/8] Additional comment w.r.t limiter spacing in tox.ini --- tox.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/tox.ini b/tox.ini index 507db37bf..7d9cea1e4 100644 --- a/tox.ini +++ b/tox.ini @@ -58,6 +58,7 @@ passenv = # always active. # IMPORTANT: It's a good idea to restrict the version numbers of the plugins. Without version limits, GHCI's pip # sometimes simply gives up trying to figure the right deps, causing the test to fail. +# IMPORTANT 2: Do not add spaces around the version limiter! deps = flake8-pyproject>=1.2.2 flake8-bugbear>=22.12.6 From 21700dce37d14ec6b3d6837486515f30bbce6b7d Mon Sep 17 00:00:00 2001 From: Pandu POLUAN Date: Thu, 22 Dec 2022 04:11:52 +0700 Subject: [PATCH 4/8] Minor improvement of release.py --- release.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.py b/release.py index 8b39dcff1..733fd65e9 100755 --- a/release.py +++ b/release.py @@ -122,7 +122,7 @@ if has_verify: print("Waiting for package to be received by PyPI...", end="") for i in range(10, 0, -1): - printfl(i, end="..") + printfl(i, end="..", flush=True) time.sleep(1.0) print() twine_verif = ["twine", "verify_upload"] + DISTFILES From 26f736f80a3ad6657a41c9321fd64e64d50cc338 Mon Sep 17 00:00:00 2001 From: Pandu POLUAN Date: Fri, 30 Dec 2022 18:42:31 +0700 Subject: [PATCH 5/8] Move project metadata to front, outside of setuptools part --- pyproject.toml | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index c6748046a..8cc968caf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,13 +1,9 @@ -# region #### setuptools settings ########## - -[build-system] -requires = ["setuptools", "wheel"] -build-backend = "setuptools.build_meta" +# region #### Project metadata ########## [project] name = "aiosmtpd" requires-python = ">=3.7" -dynamic = ["version"] +dynamic = [ "version" ] description = "aiosmtpd - asyncio based SMTP server" readme = "DESCRIPTION.rst" urls."Home Page" = "https://aiosmtpd.readthedocs.io/" @@ -17,7 +13,7 @@ urls."Source Code" = "https://github.com/aio-libs/aiosmtpd" maintainers = [ { name = "The aiosmtpd Developers", email = "aiosmtpd@googlegroups.com"} ] -keywords = [ "email", "smtpd", "smtp", "async"] +keywords = [ "email", "smtpd", "smtp", "async" ] license.file = "LICENSE" classifiers = [ "License :: OSI Approved", @@ -46,6 +42,14 @@ dependencies = [ [project.scripts] aiosmtpd = "aiosmtpd.main:main" +[build-system] +requires = ["setuptools", "wheel"] +build-backend = "setuptools.build_meta" + +# endregion + +# region #### setuptools settings ########## + [tool.setuptools] zip-safe = false From c9e1570594ec6d1f9e500eadcbcf90e7a9152191 Mon Sep 17 00:00:00 2001 From: Pandu POLUAN Date: Fri, 13 Jan 2023 15:46:25 +0700 Subject: [PATCH 6/8] Move pytype config to pyproject.toml ... and delete setup.cfg --- .github/workflows/unit-testing-and-coverage.yml | 2 -- pyproject.toml | 15 +++++++++++++++ setup.cfg | 11 ----------- tox.ini | 2 +- 4 files changed, 16 insertions(+), 14 deletions(-) delete mode 100644 setup.cfg diff --git a/.github/workflows/unit-testing-and-coverage.yml b/.github/workflows/unit-testing-and-coverage.yml index 7b295ffa1..b71a630d4 100644 --- a/.github/workflows/unit-testing-and-coverage.yml +++ b/.github/workflows/unit-testing-and-coverage.yml @@ -7,14 +7,12 @@ on: branches: [ "master" ] paths: - "aiosmtpd/**" - - "setup.cfg" # To monitor changes in dependencies - "pyproject.toml" # To monitor changes in dependencies # This is for PRs pull_request: branches: [ "master" ] paths: - "aiosmtpd/**" - - "setup.cfg" # To monitor changes in dependencies - "pyproject.toml" # To monitor changes in dependencies # Manual/on-demand workflow_dispatch: diff --git a/pyproject.toml b/pyproject.toml index 8cc968caf..e60189c29 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -209,3 +209,18 @@ mypy-init-return = true suppress-none-returning = true suppress-dummy-args = true allow-untyped-defs = true + + +[tool.pytype] +exclude = [ + "aiosmtpd/docs/_exts/*", + "_dump/*", + "aiosmtpd.egg-info/*", + "build/*", + "dist/*", + "Lib/*", + "Scripts/*", +] +disable = [ + "not-supported-yet", +] diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index db8d8adf3..000000000 --- a/setup.cfg +++ /dev/null @@ -1,11 +0,0 @@ -[pytype] -exclude = - aiosmtpd/docs/_exts/* - _dump/* - aiosmtpd.egg-info/* - build/* - dist/* - Lib/* - Scripts/* -disable = - not-supported-yet diff --git a/tox.ini b/tox.ini index 7d9cea1e4..8a7939ee3 100644 --- a/tox.ini +++ b/tox.ini @@ -54,7 +54,7 @@ passenv = [flake8_plugins] # This is a pseudo-section that feeds into [testenv:qa] and GA # Snippets of letters above these plugins are tests that need to be "select"-ed in flake8 config (in -# setup.cfg) to activate the respective plugins. If no snippet is given, that means the plugin is +# pyproject.toml) to activate the respective plugins. If no snippet is given, that means the plugin is # always active. # IMPORTANT: It's a good idea to restrict the version numbers of the plugins. Without version limits, GHCI's pip # sometimes simply gives up trying to figure the right deps, causing the test to fail. From 80c7bf5d7072005e69d82639322d179ddff7481a Mon Sep 17 00:00:00 2001 From: Pandu POLUAN Date: Fri, 13 Jan 2023 16:43:58 +0700 Subject: [PATCH 7/8] Update NEWS.rst + bump version --- aiosmtpd/__init__.py | 2 +- aiosmtpd/docs/NEWS.rst | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/aiosmtpd/__init__.py b/aiosmtpd/__init__.py index 8cb1d7196..e1be46c0e 100644 --- a/aiosmtpd/__init__.py +++ b/aiosmtpd/__init__.py @@ -4,7 +4,7 @@ import warnings -__version__ = "1.4.4" +__version__ = "1.5.0a1" def _get_or_new_eventloop() -> asyncio.AbstractEventLoop: diff --git a/aiosmtpd/docs/NEWS.rst b/aiosmtpd/docs/NEWS.rst index 405f1aed4..65d8da9e6 100644 --- a/aiosmtpd/docs/NEWS.rst +++ b/aiosmtpd/docs/NEWS.rst @@ -14,6 +14,7 @@ Fixed/Improved -------------- * All Controllers now have more rationale design, as they are now composited from a Base + a Mixin * A whole bunch of annotations +* Stop using ``setup.cfg`` and use ``pyproject.toml`` instead 1.4.4 (2023-01-13) From 75cc9d578f8efa4ba81e6cf9279da3f0fb4fc06d Mon Sep 17 00:00:00 2001 From: Pandu POLUAN Date: Fri, 13 Jan 2023 16:48:17 +0700 Subject: [PATCH 8/8] Update README.rst Because we no longer have `setup.py` Also add one line to ensure the latest version of pip and setuptools --- README.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 2714318a6..9da5f02ee 100644 --- a/README.rst +++ b/README.rst @@ -118,11 +118,12 @@ You can also request help by submitting a question on StackOverflow. Building ======== -You can install this package in a virtual environment like so:: +You can install this package -- after cloning -- in a virtual environment like so:: $ python3 -m venv /path/to/venv $ source /path/to/venv/bin/activate - $ python setup.py install + $ python -m pip install -U pip setuptools + $ python -m pip install . This will give you a command line script called ``aiosmtpd`` which implements the SMTP server. Use ``aiosmtpd --help`` for a quick reference.