From 06d236045b6a69c94c68f255dc683219ec833c83 Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Fri, 7 Jun 2024 00:15:26 -0400 Subject: [PATCH 1/2] Delay imports of non-stdlib dependencies until time of use This is a bit of a hack, but we do this to ensure that when setuptools loads entrypoint based hooks it cannot (will not?) crash. The issue is that setuptools plugins are autoloaded, whether any given project uses them at all or not. So if setuptools-rust is installed, setuptools always tries to use it, and crashes if setuptools-rust is broken. Of course, setuptools-rust can't be broken, because it's a wonderful project. BUT. As it happens, third-party vendors providing setuptools-rust can get into a situation where multiple packages need to be installed, including setuptools-rust, and also build yet other packages from source. In the middle of this, setuptools-rust itself could be installed but in "half-configured" state, i.e. its dependencies were queued for afterwards due to complicated dependency graph magic. In such a scenario, it should be nominally all right to have an inert package installed, since if nothing actually uses setuptools-rust it doesn't need to *work* yet. And in fact, it is all right, as long as setuptools can import the autoloaded plugin hooks (and do nothing with them). Bug: https://bugs.gentoo.org/933553 Signed-off-by: Eli Schwartz --- setuptools_rust/extension.py | 7 ++++++- setuptools_rust/rustc_info.py | 8 ++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/setuptools_rust/extension.py b/setuptools_rust/extension.py index 2d6e5aa..9ba1cf5 100644 --- a/setuptools_rust/extension.py +++ b/setuptools_rust/extension.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import json import os import re @@ -14,11 +16,13 @@ from typing import ( NewType, Optional, Sequence, + TYPE_CHECKING, Union, cast, ) -from semantic_version import SimpleSpec +if TYPE_CHECKING: + from semantic_version import SimpleSpec from ._utils import format_called_process_error @@ -185,6 +189,7 @@ class RustExtension: if self.rust_version is None: return None try: + from semantic_version import SimpleSpec return SimpleSpec(self.rust_version) except ValueError: raise SetupError( diff --git a/setuptools_rust/rustc_info.py b/setuptools_rust/rustc_info.py index 070be0c..d1d4748 100644 --- a/setuptools_rust/rustc_info.py +++ b/setuptools_rust/rustc_info.py @@ -1,15 +1,19 @@ +from __future__ import annotations + import subprocess from setuptools.errors import PlatformError from functools import lru_cache -from typing import Dict, List, NewType, Optional +from typing import Dict, List, NewType, Optional, TYPE_CHECKING -from semantic_version import Version +if TYPE_CHECKING: + from semantic_version import Version def get_rust_version() -> Optional[Version]: # type: ignore[no-any-unimported] try: # first line of rustc -Vv is something like # rustc 1.61.0 (fe5b13d68 2022-05-18) + from semantic_version import Version return Version(_rust_version().split(" ")[1]) except (subprocess.CalledProcessError, OSError): return None -- 2.44.2 From a98e8a8d31d30c5d304e9ee7b48ba739946dea6f Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Fri, 7 Jun 2024 00:34:59 -0400 Subject: [PATCH 2/2] Try extra hard to pick up an existing tomli library from setuptools Since setuptools-rust already depends on setuptools, it is reasonable to assume that even if tomli isn't installed, setuptools is. And setuptools includes a vendored copy of tomli. If the copy in setuptools has been devendored, it will be available via "tomli". If it isn't devendored, it will be available via "setuptools.extern.tomli" unless setuptools changes their vendoring approach which has lasted many years so far. Either way, we are sure to have a fallback tomli without explicitly depending on one, which means one less dependency to install in the common case. Signed-off-by: Eli Schwartz --- pyproject.toml | 1 - setuptools_rust/setuptools_ext.py | 5 ++++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index cae0536..148d85b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,7 +26,6 @@ classifiers = [ dependencies = [ "setuptools>=62.4", "semantic_version>=2.8.2,<3", - 'tomli>=1.2.1; python_version<"3.11"' ] [project.entry-points."distutils.commands"] diff --git a/setuptools_rust/setuptools_ext.py b/setuptools_rust/setuptools_ext.py index d4a0204..0ea6f58 100644 --- a/setuptools_rust/setuptools_ext.py +++ b/setuptools_rust/setuptools_ext.py @@ -26,7 +26,10 @@ except ImportError: if sys.version_info[:2] >= (3, 11): from tomllib import load as toml_load else: - from tomli import load as toml_load + try: + from tomli import load as toml_load + except ImportError: + from setuptools.extern.tomli import load as toml_load logger = logging.getLogger(__name__) -- 2.44.2