diff --git a/.github/workflows/unit-testing-and-coverage.yml b/.github/workflows/unit-testing-and-coverage.yml index e867f071..b71a630d 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: @@ -38,7 +36,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" @@ -53,7 +51,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: | @@ -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/README.rst b/README.rst index 2714318a..9da5f02e 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. diff --git a/aiosmtpd/__init__.py b/aiosmtpd/__init__.py index 8cb1d719..e1be46c0 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 405f1aed..65d8da9e 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) diff --git a/pyproject.toml b/pyproject.toml index 8731e605..e60189c2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,67 @@ +# region #### Project metadata ########## + +[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" + [build-system] requires = ["setuptools", "wheel"] build-backend = "setuptools.build_meta" +# endregion + +# region #### setuptools settings ########## + +[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 = [ @@ -82,3 +142,85 @@ 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 + + +[tool.pytype] +exclude = [ + "aiosmtpd/docs/_exts/*", + "_dump/*", + "aiosmtpd.egg-info/*", + "build/*", + "dist/*", + "Lib/*", + "Scripts/*", +] +disable = [ + "not-supported-yet", +] diff --git a/release.py b/release.py index e6313b3e..733fd65e 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!" @@ -116,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 diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index a00d13cf..00000000 --- a/setup.cfg +++ /dev/null @@ -1,135 +0,0 @@ -[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/* -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/setup.py b/setup.py deleted file mode 100644 index 60684932..00000000 --- a/setup.py +++ /dev/null @@ -1,3 +0,0 @@ -from setuptools import setup - -setup() diff --git a/tox.ini b/tox.ini index 211e78da..8a7939ee 100644 --- a/tox.ini +++ b/tox.ini @@ -54,11 +54,13 @@ 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. +# IMPORTANT 2: Do not add spaces around the version limiter! deps = + flake8-pyproject>=1.2.2 flake8-bugbear>=22.12.6 flake8-builtins>=2.0.1 flake8-coding>=1.3.2