Skip to content

Commit

Permalink
Add basic UV support (#160)
Browse files Browse the repository at this point in the history
* Migrate pyproject.toml to UV

* replace black/isort/flake8 with ruff

* ruff format

* feature: Add basic support for `pyproject.toml` that uses Uv to prevent it causing errors

* Updated PR references in 1 changelogs.

skip-checks: true

* test 3.13

---------

Co-authored-by: GitHub Action <[email protected]>
  • Loading branch information
NiklasRosenstein and GitHub Action authored Jan 2, 2025
1 parent f0faa88 commit fd98bc4
Show file tree
Hide file tree
Showing 20 changed files with 1,329 additions and 92 deletions.
6 changes: 6 additions & 0 deletions .changelog/_unreleased.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[[entries]]
id = "95676706-7b7b-40f3-99ac-b7149e2f81b5"
type = "feature"
description = "Add basic support for `pyproject.toml` that uses Uv to prevent it causing errors"
author = "@NiklasRosenstein"
pr = "https://github.com/NiklasRosenstein/slap/pull/160"
4 changes: 2 additions & 2 deletions .github/workflows/python.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-22.04
strategy:
matrix:
python-version: ["3.10", "3.11", "3.12"]
python-version: ["3.10", "3.11", "3.12", "3.13"]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
Expand All @@ -26,7 +26,7 @@ jobs:
runs-on: ubuntu-22.04
strategy:
matrix:
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"]
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
Expand Down
144 changes: 70 additions & 74 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,63 +1,49 @@
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
build-backend = "pdm.backend"
requires = ["pdm-backend"]

[tool.poetry]
name = "slap-cli"
version = "1.14.2"
description = "Slap is a command-line utility for developing Python applications."
authors = ["Niklas Rosenstein <[email protected]>"]
license = "MIT"
packages = [{ include = "slap", from = "src" }]
[project]
authors = [
{name = "Niklas Rosenstein", email = "[email protected]"},
]
classifiers = [
"Development Status :: 3 - Alpha",
"Environment :: Console",
"Programming Language :: Python :: 3.10",
]
dependencies = [
"beautifulsoup4<5.0.0,>=4.10.0",
"cleo>=1.0.0a4",
"databind<5.0.0,>=4.4.0",
"flit<4.0.0,>=3.6.0",
"poetry-core<1.10,>=1.9",
"ptyprocess<1.0.0,>=0.7.0",
"pygments<3.0.0,>=2.11.2",
"PyYAML>=6.0",
"requests<3.0.0,>=2.27.1",
"setuptools>=39.1.0",
"tomli<3.0.0,>=2.0.0",
"tomlkit<1.0.0,>=0.12.1",
"twine<6.0.0,>=5.0.0",
"tqdm<5.0.0,>=4.64.0",
"build<2.0.0,>=1.0.0",
"nr-python-environment<1.0.0,>=0.1.4",
"gitpython<4.0.0,>=3.1.31",
"nr-stream<2.0.0,>=1.1.5",
"uv<1.0.0,>=0.2.0",
]
description = "Slap is a command-line utility for developing Python applications."
license = {text = "MIT"}
name = "slap-cli"
requires-python = "<4,>=3.10"
version = "1.14.2"

[tool.poetry.urls]
[project.urls]
Documentation = "https://niklasrosenstein.github.io/slap/"
Homepage = "https://github.com/NiklasRosenstein/slap"
Repository = "https://github.com/NiklasRosenstein/slap.git"

[tool.poetry.dependencies]
python = ">=3.10,<3.13"
beautifulsoup4 = "^4.10.0"
cleo = ">=1.0.0a4"
"databind" = "^4.4.0"
flit = "^3.6.0"
poetry-core = ">=1.9,<1.10"
ptyprocess = "^0.7.0"
pygments = "^2.11.2"
PyYAML = ">=6.0"
requests = "^2.27.1"
setuptools = ">=39.1.0" # Needed for setuptools backend
tomli = "^2.0.0"
tomlkit = "^0.12.1"
twine = "^5.0.0"
tqdm = "^4.64.0"
build = "^1.0.0"
"nr.python.environment" = "^0.1.4"
gitpython = "^3.1.31"
"nr.stream" = "^1.1.5"
uv = "^0.2.0"

[tool.poetry.dev-dependencies]
black = "^24.1.0"
flake8 = "^7.0.0"
isort = "^5.13.1"
mypy = "^1.8.0"
pytest = "^8.0.0"
types-beautifulsoup4 = "^4.10.0"
types-pygments = "^2.9.16"
types-PyYAML = "^6.0.3"
types-requests = "^2.27.7"
types-termcolor = "^1.1.3"

[tool.poetry.scripts]
slap = "slap.__main__:main"

[tool.poetry.plugins."slap.plugins.application"]
[project.entry-points."slap.plugins.application"]
add = "slap.ext.application.add:AddCommandPlugin"
changelog = "slap.ext.application.changelog:ChangelogCommandPlugin"
check = "slap.ext.application.check:CheckCommandPlugin"
Expand All @@ -73,71 +59,81 @@ run = "slap.ext.application.run:RunCommandPlugin"
test = "slap.ext.application.test:TestCommandPlugin"
venv = "slap.ext.application.venv:VenvPlugin"

[tool.poetry.plugins."slap.plugins.repository_ci"]
[project.entry-points."slap.plugins.repository_ci"]
github-actions = "slap.ext.repository_ci.github_actions:GithubActionsRepositoryCIPlugin"

[tool.poetry.plugins."slap.plugins.check"]
[project.entry-points."slap.plugins.check"]
changelog = "slap.ext.checks.changelog:ChangelogValidationCheckPlugin"
general = "slap.ext.checks.general:GeneralChecksPlugin"
poetry = "slap.ext.checks.poetry:PoetryChecksPlugin"
release = "slap.ext.checks.release:ReleaseChecksPlugin"

[tool.poetry.plugins."slap.plugins.release"]
[project.entry-points."slap.plugins.release"]
changelog_release = "slap.ext.release.changelog:ChangelogReleasePlugin"
source_code_version = "slap.ext.release.source_code_version:SourceCodeVersionReferencesPlugin"

[tool.poetry.plugins."slap.plugins.version_incrementing_rule"]
[project.entry-points."slap.plugins.version_incrementing_rule"]
major = "slap.ext.version_incrementing_rule:major"
premajor = "slap.ext.version_incrementing_rule:premajor"
minor = "slap.ext.version_incrementing_rule:minor"
preminor = "slap.ext.version_incrementing_rule:preminor"
patch = "slap.ext.version_incrementing_rule:patch"
premajor = "slap.ext.version_incrementing_rule:premajor"
preminor = "slap.ext.version_incrementing_rule:preminor"
prepatch = "slap.ext.version_incrementing_rule:prepatch"
prerelease = "slap.ext.version_incrementing_rule:prerelease"

[tool.poetry.plugins."slap.plugins.project"]
[project.entry-points."slap.plugins.project"]
flit = "slap.ext.project_handlers.flit:FlitProjectHandler"
poetry = "slap.ext.project_handlers.poetry:PoetryProjectHandler"
setuptools = "slap.ext.project_handlers.setuptools:SetuptoolsProjectHandler"
uv = "slap.ext.project_handlers.uv:UvProjectHandler"

[tool.poetry.plugins."slap.plugins.repository"]
[project.entry-points."slap.plugins.repository"]
default = "slap.ext.repository_handlers.default:DefaultRepositoryHandler"

[tool.poetry.plugins."slap.plugins.repository_host"]
[project.entry-points."slap.plugins.repository_host"]
github = "slap.ext.repository_hosts.github:GithubRepositoryHost"

[project.scripts]
slap = "slap.__main__:main"

[tool.slap]
typed = true

[tool.slap.test]
mypy = "dmypy run src"
check = "slap check"
mypy = "dmypy run src"
pytest = "pytest tests/ -vv"
check = "slap check"
isort = "isort src/ tests/ --check-only"
black = "black src/ tests/ --check"
flake8 = "flake8 src/ tests/"
ruff-format = "ruff format --check"
ruff-lint = "ruff check"

[tool.slap.run]
"docs:build" = "slap run --use-venv docs -- bash -xc 'export PATH=\"$(slap venv -p)/bin:${PATH}\" && cd docs && mksync -i docs/changelog.md && mkdocs build'"
"docs:dev" = "slap run --use-venv docs -- bash -xc 'export PATH=\"$(slap venv -p)/bin:${PATH}\" && cd docs && mksync -i docs/changelog.md && mkdocs serve'"
"docs:install" = "slap venv -c docs --python python3.10 && slap run --use-venv docs -- pip install -r docs/requirements.txt"
"docs:build" = "slap run --use-venv docs -- bash -xc 'export PATH=\"$(slap venv -p)/bin:${PATH}\" && cd docs && mksync -i docs/changelog.md && mkdocs build'"
"docs:dev" = "slap run --use-venv docs -- bash -xc 'export PATH=\"$(slap venv -p)/bin:${PATH}\" && cd docs && mksync -i docs/changelog.md && mkdocs serve'"
fmt = "isort src/ tests/ && black src/ tests"
fmt = "ruff format ."

[tool.mypy]
pretty = true
warn_redundant_casts = true
#warn_unused_ignores = true
exclude = "src/slap/templates/.*"
namespace_packages = true
show_error_codes = true
show_error_context = true
warn_no_return = true
warn_unreachable = true
show_error_context = true
show_error_codes = true
namespace_packages = true
exclude = "src/slap/templates/.*"

[tool.black]
[tool.ruff]
line-length = 120

[tool.isort]
profile = "black"
line_length = 120
combine_as_imports = true
[tool.uv]
dev-dependencies = [
"mypy<2.0.0,>=1.8.0",
"pytest<9.0.0,>=8.0.0",
"ruff>=0.8.5",
"types-beautifulsoup4<5.0.0,>=4.10.0",
"types-pygments<3.0.0,>=2.9.16",
"types-PyYAML<7.0.0,>=6.0.3",
"types-requests<3.0.0,>=2.27.7",
"types-termcolor<2.0.0,>=1.1.3",
]
2 changes: 1 addition & 1 deletion src/slap/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
""" Slap is a command-line utility for developing Python applications. """
"""Slap is a command-line utility for developing Python applications."""

__version__ = "1.14.2"
4 changes: 2 additions & 2 deletions src/slap/application.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
""" With the application object we manage the CLI commands and other types of plugins as well as access to the Slap
user and project configuration. """
"""With the application object we manage the CLI commands and other types of plugins as well as access to the Slap
user and project configuration."""

from __future__ import annotations

Expand Down
2 changes: 1 addition & 1 deletion src/slap/ext/application/report.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
""" Commands that produce reports. """
"""Commands that produce reports."""

import json
import logging
Expand Down
2 changes: 1 addition & 1 deletion src/slap/ext/project_handlers/base.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
""" Implements the default package detection plugin. """
"""Implements the default package detection plugin."""

from __future__ import annotations

Expand Down
2 changes: 1 addition & 1 deletion src/slap/ext/project_handlers/flit.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
""" Project handler for projects using the Flit build system. """
"""Project handler for projects using the Flit build system."""

from __future__ import annotations

Expand Down
2 changes: 1 addition & 1 deletion src/slap/ext/project_handlers/poetry.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
""" Project handler for projects using the Poetry build system. """
"""Project handler for projects using the Poetry build system."""

from __future__ import annotations

Expand Down
2 changes: 1 addition & 1 deletion src/slap/ext/project_handlers/setuptools.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
""" Project handler for projects using the Setuptools build system. """
"""Project handler for projects using the Setuptools build system."""

from __future__ import annotations

Expand Down
64 changes: 64 additions & 0 deletions src/slap/ext/project_handlers/uv.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
"""Project handler for projects using the Poetry build system."""

from __future__ import annotations

import logging
import typing as t

from slap.ext.project_handlers.base import PyprojectHandler
from slap.project import Dependencies, Project
from slap.python.dependency import VersionSpec

if t.TYPE_CHECKING:
from slap.python.dependency import Dependency

logger = logging.getLogger(__name__)


class UvProjectHandler(PyprojectHandler):
# ProjectHandlerPlugin

def matches_project(self, project: Project) -> bool:
if not project.pyproject_toml.exists():
return False
if (project.directory / "uv.lock").exists():
return True
if project.pyproject_toml.get("tool", {}).get("uv") is not None:
return True
return False

def get_dist_name(self, project: Project) -> str | None:
return project.pyproject_toml.get("project", {}).get("name")

def get_readme(self, project: Project) -> str | None:
return project.pyproject_toml.get("project", {}).get("readme") or super().get_readme(project)

def get_dependencies(self, project: Project) -> Dependencies:
from slap.install.installer import Indexes
from slap.python.dependency import PypiDependency, parse_dependencies

python_version = project.pyproject_toml.get("project", {}).get("python")
dependencies = parse_dependencies(project.pyproject_toml.get("project", {}).get("dependencies", []))
dev_dependencies = parse_dependencies(
project.pyproject_toml.get("tool", {}).get("uv", {}).get("dev-dependencies", [])
)

# TODO: Support index-url / extra-index-urls options.
# TODO: Support dependency groups.

return Dependencies(
python=VersionSpec(python_version) if python_version else None,
run=dependencies,
dev=dev_dependencies,
extra={},
build=PypiDependency.parse_list(project.pyproject_toml.get("build-system", {}).get("requires", [])),
indexes=Indexes(),
)

def get_add_dependency_toml_location_and_config(
self,
project: Project,
dependency: Dependency,
where: str,
) -> tuple[list[str], list | dict]:
raise NotImplementedError("Uv project handler does not support adding dependencies")
2 changes: 1 addition & 1 deletion src/slap/install/installer.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
""" Provides an installer for dependencies. """
"""Provides an installer for dependencies."""

from __future__ import annotations

Expand Down
10 changes: 9 additions & 1 deletion src/slap/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,15 @@ def _get_packages(self) -> list[Package] | None:

if not self.is_python_project:
return []
packages = self.handler().get_packages(self)
try:
packages = self.handler().get_packages(self)
except NotImplementedError:
logger.warning(
"Project handler <obj>%s</obj> does not support package detection for project <subj>%s</subj>",
self.handler(),
self,
)
packages = []
if packages:
logger.debug(
"Detected packages for project <subj>%s</subj> by package detector <obj>%s</obj>: <val>%s></val>",
Expand Down
2 changes: 1 addition & 1 deletion src/slap/templates/poetry/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ description = ""
authors = ["{author_name} <{author_email}>"]
license = "{license}"
readme = "README.md"
packages = [{{ include = "{path}", from = "src" }}]
packages = [{ include = "{path}", from = "src" }]
classifiers = []
keywords = []

Expand Down
1 change: 0 additions & 1 deletion src/slap/util/git.py
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,6 @@ def describe(
contains: bool = False,
commitish: t.Optional[str] = None,
) -> t.Optional[str]:

command = ["git", "describe"]
if all:
command.append("--all")
Expand Down
2 changes: 1 addition & 1 deletion src/slap/util/logging.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
""" Provides a logging formatter that understands color hints in the message and decorates it with """
"""Provides a logging formatter that understands color hints in the message and decorates it with"""

from __future__ import annotations

Expand Down
2 changes: 1 addition & 1 deletion src/slap/util/plugins.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
""" Helpers to implement a plugin infrastructure in Python. """
"""Helpers to implement a plugin infrastructure in Python."""

from __future__ import annotations

Expand Down
2 changes: 1 addition & 1 deletion src/slap/util/toml_file.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
""" Represents a mutable TOML configuration file in memory. """
"""Represents a mutable TOML configuration file in memory."""

import typing as t
from pathlib import Path
Expand Down
Loading

0 comments on commit fd98bc4

Please sign in to comment.