Fix CI failures
1 |
"""
|
|
2 |
Provides a base class for a 'dummy' setup.py command that has no functionality
|
|
3 |
(probably due to a missing requirement). This dummy command can raise an
|
|
4 |
exception when it is run, explaining to the user what dependencies must be met
|
|
5 |
to use this command.
|
|
6 |
|
|
7 |
The reason this is at all tricky is that we want the command to be able to
|
|
8 |
provide this message even when the user passes arguments to the command. If we
|
|
9 |
don't know ahead of time what arguments the command can take, this is
|
|
10 |
difficult, because distutils does not allow unknown arguments to be passed to a
|
|
11 |
setup.py command. This hacks around that restriction to provide a useful error
|
|
12 |
message even when a user passes arguments to the dummy implementation of a
|
|
13 |
command.
|
|
14 |
|
|
15 |
Use this like:
|
|
16 |
|
|
17 |
try:
|
|
18 |
from some_dependency import SetupCommand
|
|
19 |
except ImportError:
|
|
20 |
from ._dummy import _DummyCommand
|
|
21 |
|
|
22 |
class SetupCommand(_DummyCommand):
|
|
23 |
description = \
|
|
24 |
'Implementation of SetupCommand from some_dependency; '
|
|
25 |
'some_dependency must be installed to run this command'
|
|
26 |
|
|
27 |
# This is the message that will be raised when a user tries to
|
|
28 |
# run this command--define it as a class attribute.
|
|
29 |
error_msg = \
|
|
30 |
"The 'setup_command' command requires the some_dependency "
|
|
31 |
"package to be installed and importable."
|
|
32 |
"""
|
|
33 |
|
|
34 | 20 |
import sys |
35 | 20 |
from setuptools import Command |
36 | 20 |
from distutils.errors import DistutilsArgError |
37 | 20 |
from textwrap import dedent |
38 |
|
|
39 |
|
|
40 | 20 |
class _DummyCommandMeta(type): |
41 |
"""
|
|
42 |
Causes an exception to be raised on accessing attributes of a command class
|
|
43 |
so that if ``./setup.py command_name`` is run with additional command-line
|
|
44 |
options we can provide a useful error message instead of the default that
|
|
45 |
tells users the options are unrecognized.
|
|
46 |
"""
|
|
47 |
|
|
48 | 20 |
def __init__(cls, name, bases, members): |
49 | 20 |
if bases == (Command, object): |
50 |
# This is the _DummyCommand base class, presumably
|
|
51 | 20 |
return
|
52 |
|
|
53 | 20 |
if not hasattr(cls, 'description'): |
54 |
raise TypeError( |
|
55 |
"_DummyCommand subclass must have a 'description' "
|
|
56 |
"attribute.") |
|
57 |
|
|
58 | 20 |
if not hasattr(cls, 'error_msg'): |
59 |
raise TypeError( |
|
60 |
"_DummyCommand subclass must have an 'error_msg' "
|
|
61 |
"attribute.") |
|
62 |
|
|
63 | 20 |
def __getattribute__(cls, attr): |
64 | 20 |
if attr in ('description', 'error_msg') or attr.startswith('_'): |
65 |
# Allow cls.description to work so that `./setup.py
|
|
66 |
# --help-commands` still works
|
|
67 | 20 |
return super(_DummyCommandMeta, cls).__getattribute__(attr) |
68 |
|
|
69 |
raise DistutilsArgError(cls.error_msg) |
|
70 |
|
|
71 |
|
|
72 | 20 |
class _DummyCommand(Command, object, metaclass=_DummyCommandMeta): |
73 | 20 |
pass
|
Read our documentation on viewing source code .