File size: 5,066 Bytes
838f737
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
from __future__ import annotations

import inspect
import platform
from collections.abc import Callable
from typing import TYPE_CHECKING, Any, ClassVar

from ..dist import Distribution
from ..warnings import SetuptoolsDeprecationWarning, SetuptoolsWarning

import distutils.command.install as orig
from distutils.errors import DistutilsArgError

if TYPE_CHECKING:
    # This is only used for a type-cast, don't import at runtime or it'll cause deprecation warnings
    from .easy_install import easy_install as easy_install_cls
else:
    easy_install_cls = None


def __getattr__(name: str):  # pragma: no cover
    if name == "_install":
        SetuptoolsDeprecationWarning.emit(
            "`setuptools.command._install` was an internal implementation detail "
            "that was left in for numpy<1.9 support.",
            due_date=(2025, 5, 2),  # Originally added on 2024-11-01
        )
        return orig.install
    raise AttributeError(f"module {__name__!r} has no attribute {name!r}")


class install(orig.install):
    """Use easy_install to install the package, w/dependencies"""

    distribution: Distribution  # override distutils.dist.Distribution with setuptools.dist.Distribution

    user_options = orig.install.user_options + [
        ('old-and-unmanageable', None, "Try not to use this!"),
        (
            'single-version-externally-managed',
            None,
            "used by system package builders to create 'flat' eggs",
        ),
    ]
    boolean_options = orig.install.boolean_options + [
        'old-and-unmanageable',
        'single-version-externally-managed',
    ]
    # Type the same as distutils.command.install.install.sub_commands
    # Must keep the second tuple item potentially None due to invariance
    new_commands: ClassVar[list[tuple[str, Callable[[Any], bool] | None]]] = [
        ('install_egg_info', lambda self: True),
        ('install_scripts', lambda self: True),
    ]
    _nc = dict(new_commands)

    def initialize_options(self):
        SetuptoolsDeprecationWarning.emit(
            "setup.py install is deprecated.",
            """
            Please avoid running ``setup.py`` directly.
            Instead, use pypa/build, pypa/installer or other
            standards-based tools.
            """,
            see_url="https://blog.ganssle.io/articles/2021/10/setup-py-deprecated.html",
            due_date=(2025, 10, 31),
        )

        super().initialize_options()
        self.old_and_unmanageable = None
        self.single_version_externally_managed = None

    def finalize_options(self) -> None:
        super().finalize_options()
        if self.root:
            self.single_version_externally_managed = True
        elif self.single_version_externally_managed:
            if not self.root and not self.record:
                raise DistutilsArgError(
                    "You must specify --record or --root when building system packages"
                )

    def handle_extra_path(self):
        if self.root or self.single_version_externally_managed:
            # explicit backward-compatibility mode, allow extra_path to work
            return orig.install.handle_extra_path(self)

        # Ignore extra_path when installing an egg (or being run by another
        # command without --root or --single-version-externally-managed
        self.path_file = None
        self.extra_dirs = ''
        return None

    @staticmethod
    def _called_from_setup(run_frame):
        """
        Attempt to detect whether run() was called from setup() or by another
        command.  If called by setup(), the parent caller will be the
        'run_command' method in 'distutils.dist', and *its* caller will be
        the 'run_commands' method.  If called any other way, the
        immediate caller *might* be 'run_command', but it won't have been
        called by 'run_commands'. Return True in that case or if a call stack
        is unavailable. Return False otherwise.
        """
        if run_frame is None:
            msg = "Call stack not available. bdist_* commands may fail."
            SetuptoolsWarning.emit(msg)
            if platform.python_implementation() == 'IronPython':
                msg = "For best results, pass -X:Frames to enable call stack."
                SetuptoolsWarning.emit(msg)
            return True

        frames = inspect.getouterframes(run_frame)
        for frame in frames[2:4]:
            (caller,) = frame[:1]
            info = inspect.getframeinfo(caller)
            caller_module = caller.f_globals.get('__name__', '')

            if caller_module == "setuptools.dist" and info.function == "run_command":
                # Starting from v61.0.0 setuptools overwrites dist.run_command
                continue

            return caller_module == 'distutils.dist' and info.function == 'run_commands'

        return False


# XXX Python 3.1 doesn't see _nc if this is inside the class
install.sub_commands = [
    cmd for cmd in orig.install.sub_commands if cmd[0] not in install._nc
] + install.new_commands