diff --git a/.gitattributes b/.gitattributes index 4630853702..c6426a5028 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,3 @@ # force LF for pyproject to make hashFiles in CI consistent (windows <3) # (see https://github.com/actions/runner/issues/498) -pyproject.toml text eol=lf +pyproject.toml text eol=lf export-subst diff --git a/.github/workflows/lint-test.yml b/.github/workflows/lint-test.yml index a0476bba59..36400b0a61 100644 --- a/.github/workflows/lint-test.yml +++ b/.github/workflows/lint-test.yml @@ -157,6 +157,7 @@ jobs: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false + fetch-depth: '0' - name: Set up environment id: setup-env @@ -244,6 +245,7 @@ jobs: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false + fetch-depth: '0' - name: Set up environment id: setup diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index e0c75d95f4..74185d32d9 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -19,6 +19,7 @@ jobs: steps: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: + fetch-depth: '0' persist-credentials: false - name: Set up environment diff --git a/.gitignore b/.gitignore index 3c66053d3d..aff22edfdd 100644 --- a/.gitignore +++ b/.gitignore @@ -31,5 +31,6 @@ venvs/ .coverage* coverage.xml __pypackages__/ +disnake/_version.py .python-version uv.lock diff --git a/.readthedocs.yml b/.readthedocs.yml index 1e48672de0..0038de6296 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -8,6 +8,8 @@ build: tools: python: "3.9" jobs: + post_checkout: + - git fetch --tags || true create_environment: - asdf plugin add uv - asdf install uv latest diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index da756d1d7b..0000000000 --- a/MANIFEST.in +++ /dev/null @@ -1,9 +0,0 @@ -include README.md -include LICENSE -include disnake/bin/* -include disnake/py.typed -include disnake/ext/commands/py.typed -include disnake/ext/tasks/py.typed -global-exclude *.py[cod] -exclude uv.lock -exclude noxfile.py diff --git a/changelog/1323.misc.rst b/changelog/1323.misc.rst new file mode 100644 index 0000000000..d6b1d715ff --- /dev/null +++ b/changelog/1323.misc.rst @@ -0,0 +1 @@ +Use hatchling and versioningit for building disnake rather than using setuptools. diff --git a/disnake/__init__.py b/disnake/__init__.py index 92eae6bec7..fb27d3703b 100644 --- a/disnake/__init__.py +++ b/disnake/__init__.py @@ -14,14 +14,17 @@ __author__ = "Rapptz, EQUENOS" __license__ = "MIT" __copyright__ = "Copyright 2015-present Rapptz, 2021-present EQUENOS" -__version__ = "2.12.0a" __path__ = __import__("pkgutil").extend_path(__path__, __name__) import logging -from typing import Literal, NamedTuple from . import abc as abc, opus as opus, ui as ui, utils as utils # explicitly re-export modules +from ._version import ( + VersionInfo, # pyright: ignore[reportUnusedImport] # noqa: F401 + __version__, # noqa: F401 + version_info, # pyright: ignore[reportUnusedImport] # noqa: F401 +) from .activity import * from .app_commands import * from .appinfo import * @@ -77,17 +80,4 @@ from .welcome_screen import * from .widget import * - -class VersionInfo(NamedTuple): - major: int - minor: int - micro: int - releaselevel: Literal["alpha", "beta", "candidate", "final"] - serial: int - - -# fmt: off -version_info: VersionInfo = VersionInfo(major=2, minor=12, micro=0, releaselevel="alpha", serial=0) -# fmt: on - logging.getLogger(__name__).addHandler(logging.NullHandler()) diff --git a/disnake/_version.pyi b/disnake/_version.pyi new file mode 100644 index 0000000000..a935e0ebb4 --- /dev/null +++ b/disnake/_version.pyi @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: MIT + +from typing import Literal, NamedTuple + +__version__: str + +class VersionInfo(NamedTuple): + major: int + minor: int + micro: int + releaselevel: Literal["alpha", "beta", "candidate", "final"] + serial: int + +version_info: VersionInfo diff --git a/docs/conf.py b/docs/conf.py index 935e922039..bc94383baf 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -12,6 +12,7 @@ # All configuration values have a default; values that are commented out # serve to show the default. +import importlib.metadata import importlib.util import inspect import os @@ -20,6 +21,7 @@ import sys from typing import Any, Dict, Optional +import versioningit from sphinx.application import Sphinx # If extensions (or modules to document with autodoc) are in another directory, @@ -106,15 +108,16 @@ # |version| and |release|, also used in various other places throughout the # built documents. # +# The full version, including alpha/beta/rc tags. +release = importlib.metadata.version("disnake") # The short X.Y version. +version = ".".join(release.split(".")[:2]) -version = "" -with open("../disnake/__init__.py") as f: - version = re.search(r'^__version__\s*=\s*[\'"]([^\'"]*)[\'"]', f.read(), re.MULTILINE).group(1) # type: ignore - -# The full version, including alpha/beta/rc tags. -release = version +next_version = versioningit.get_next_version(os.path.abspath("..")) +rst_prolog += f""" +.. |next_version| replace:: {next_version} +""" _IS_READTHEDOCS = bool(os.getenv("READTHEDOCS")) diff --git a/docs/whats_new.rst b/docs/whats_new.rst index 3f0cafccaf..d964efb579 100644 --- a/docs/whats_new.rst +++ b/docs/whats_new.rst @@ -13,7 +13,7 @@ Changelog This page keeps a detailed human friendly rendering of what's new and changed in specific versions. Please see :ref:`version_guarantees` for more information. -.. towncrier-draft-entries:: |release| [UNRELEASED] +.. towncrier-draft-entries:: |next_version| [UNRELEASED] .. towncrier release notes start diff --git a/noxfile.py b/noxfile.py index 33d2512934..25dd47c6b7 100755 --- a/noxfile.py +++ b/noxfile.py @@ -77,12 +77,12 @@ def __post_init__(self) -> None: ExecutionGroup( sessions=("pyright",), python=python, - pyright_paths=("disnake", "tests", "examples", "noxfile.py", "setup.py"), + pyright_paths=("disnake", "tests", "examples", "noxfile.py"), project=True, # FIXME: orjson doesn't yet support python 3.14, remove once we migrate to uv and have version-specific locks extras=("speed", "voice") if python not in EXPERIMENTAL_PYTHON_VERSIONS else ("voice",), groups=("test", "nox"), - dependencies=("setuptools", "pytz", "requests"), # needed for type checking + dependencies=("pytz", "requests"), # needed for type checking ) for python in ALL_PYTHONS ), @@ -95,18 +95,20 @@ def __post_init__(self) -> None: # codemodding and pyright ExecutionGroup( sessions=("codemod", "autotyping", "pyright"), - pyright_paths=("scripts",), + pyright_paths=("scripts/codemods", "scripts/ci"), groups=("codemod",), ), # the other sessions, they don't need pyright, but they need to run ExecutionGroup( - sessions=("lint", "slotscheck", "check-manifest"), + sessions=("lint", "slotscheck"), groups=("tools",), ), # build ExecutionGroup( - sessions=("build",), + sessions=("build", "pyright"), + pyright_paths=("scripts/versioning.py",), groups=("build",), + dependencies=(PYPROJECT["build-system"]["requires"]), ), ## testing *( @@ -254,13 +256,6 @@ def lint(session: nox.Session) -> None: session.run("prek", "run", "--all-files", *session.posargs) -@nox.session(name="check-manifest") -def check_manifest(session: nox.Session) -> None: - """Run check-manifest.""" - install_deps(session) - session.run("check-manifest", "-v") - - @nox.session(python=get_version_for_session("slotscheck")) def slotscheck(session: nox.Session) -> None: """Run slotscheck.""" @@ -268,7 +263,7 @@ def slotscheck(session: nox.Session) -> None: session.run("python", "-m", "slotscheck", "--verbose", "-m", "disnake") -@nox.session(requires=["check-manifest"]) +@nox.session() def build(session: nox.Session) -> None: """Build a dist.""" install_deps(session) diff --git a/pyproject.toml b/pyproject.toml index 28e6b509e0..93b47d2d12 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: MIT [build-system] -requires = ["setuptools>=61"] -build-backend = "setuptools.build_meta" +requires = ["hatchling", "versioningit>=3.3.0,<4.0", "packaging"] +build-backend = "hatchling.build" [project] name = "disnake" @@ -64,6 +64,7 @@ docs = [ "towncrier==23.6.0", "sphinx-notfound-page==0.8.3", "sphinxext-opengraph==0.9.1", + "versioningit>=3.3.0", ] [dependency-groups] @@ -86,7 +87,6 @@ ruff = [ tools = [ "prek>=0.2.0", "slotscheck~=0.16.4", - "check-manifest==0.49", { include-group = "ruff" }, ] changelog = [ @@ -116,13 +116,58 @@ build = [ "twine>=6.1.0", ] -[tool.setuptools.packages.find] -where = ["."] -include = ["disnake*"] - [tool.uv] required-version = ">=0.8.4" +[tool.hatch.build] +include = [ + "disnake/", +] +artifacts = ["disnake/_version.py"] + +[tool.hatch.build.targets.sdist] +include = [ + "scripts/versioning.py" +] + +[tool.hatch.version] +source = "versioningit" + +[tool.versioningit] +default-version = "0.0.0" + +[tool.versioningit.vcs] +method = "git-archive" +describe-subst = "$Format:%(describe:tags,match=v*)$" + +[tool.versioningit.format] +distance = "{base_version}+{distance}.{vcs}{rev}" +dirty = "{base_version}+d{build_date:%Y%m%d}" +distance-dirty = "{base_version}.a{distance}+{vcs}{rev}.d{build_date:%Y%m%d}" + +[tool.versioningit.template-fields] +method = { module = "scripts.versioning", value = "template_fields"} + +[tool.versioningit.write] +file = "disnake/_version.py" +template = """ +# SPDX-License-Identifier: MIT + +from typing import Literal, NamedTuple + +__version__ = "{version}" + + +class VersionInfo(NamedTuple): + major: int + minor: int + micro: int + releaselevel: Literal["alpha", "beta", "candidate", "final"] + serial: int + +version_info: VersionInfo = VersionInfo{version_tuple} +""" + [tool.ruff] line-length = 100 @@ -415,23 +460,3 @@ exclude_lines = [ "^\\s*raise NotImplementedError$", "^\\s*\\.\\.\\.$", ] - - -[tool.check-manifest] -ignore = [ - # CI - ".pre-commit-config.yaml", - ".readthedocs.yml", - ".libcst.codemod.yaml", - "noxfile.py", - # docs - "CONTRIBUTING.md", - "RELEASE.md", - "assets/**", - "changelog/**", - "docs/**", - "examples/**", - # tests - "tests/**", - "scripts/**", -] diff --git a/scripts/versioning.py b/scripts/versioning.py new file mode 100644 index 0000000000..0a405ff1f4 --- /dev/null +++ b/scripts/versioning.py @@ -0,0 +1,54 @@ +# SPDX-License-Identifier: MIT + +import copy +from typing import Any, Dict, Optional + +import packaging.version +import versioningit + + +def template_fields( + *, + version: str, + description: Optional[versioningit.VCSDescription], + base_version: Optional[str], + next_version: Optional[str], + params: Dict[str, Any], +) -> Dict[str, Any]: + """Implements the ``"basic"`` ``template-fields`` method""" + params = copy.deepcopy(params) + parsed_version = packaging.version.parse(version) + fields: Dict[str, Any] = {} + if description is not None: + fields.update(description.fields) + fields["branch"] = description.branch + if base_version is not None: + fields["base_version"] = base_version + if next_version is not None: + fields["next_version"] = next_version + fields["version"] = version + + releaselevels = { + "a": "alpha", + "b": "beta", + "rc": "candidate", + "": "final", + } + + if parsed_version.pre: + releaselevel = releaselevels.get(parsed_version.pre[0], "final") + else: + releaselevel = "final" + + fields["version_tuple"] = ( + parsed_version.major, + parsed_version.minor, + parsed_version.micro, + releaselevel, + parsed_version.dev or 0, + ) + try: + fields["normalized_version"] = str(packaging.version.Version(version)) + except ValueError: + fields["normalized_version"] = version + return fields diff --git a/setup.py b/setup.py deleted file mode 100644 index 4a49d78f69..0000000000 --- a/setup.py +++ /dev/null @@ -1,37 +0,0 @@ -# SPDX-License-Identifier: MIT - -import re - -from setuptools import setup - -version = "" -with open("disnake/__init__.py", encoding="utf-8") as f: - version = re.search(r'^__version__\s*=\s*[\'"]([^\'"]*)[\'"]', f.read(), re.MULTILINE).group(1) # type: ignore - -if not version: - msg = "version is not set" - raise RuntimeError(msg) - -if version.endswith(("a", "b", "rc")): - # append version identifier based on commit count - try: - import subprocess # noqa: TID251 - - p = subprocess.Popen( - ["git", "rev-list", "--count", "HEAD"], stdout=subprocess.PIPE, stderr=subprocess.PIPE - ) - out, err = p.communicate() - if out: - version += out.decode("utf-8").strip() - p = subprocess.Popen( - ["git", "rev-parse", "--short", "HEAD"], stdout=subprocess.PIPE, stderr=subprocess.PIPE - ) - out, err = p.communicate() - if out: - version += "+g" + out.decode("utf-8").strip() - except Exception: - pass - -setup( - version=version, -)