jpayne@68
|
1 """Provide basic warnings used by setuptools modules.
|
jpayne@68
|
2
|
jpayne@68
|
3 Using custom classes (other than ``UserWarning``) allow users to set
|
jpayne@68
|
4 ``PYTHONWARNINGS`` filters to run tests and prepare for upcoming changes in
|
jpayne@68
|
5 setuptools.
|
jpayne@68
|
6 """
|
jpayne@68
|
7
|
jpayne@68
|
8 from __future__ import annotations
|
jpayne@68
|
9
|
jpayne@68
|
10 import os
|
jpayne@68
|
11 import warnings
|
jpayne@68
|
12 from datetime import date
|
jpayne@68
|
13 from inspect import cleandoc
|
jpayne@68
|
14 from textwrap import indent
|
jpayne@68
|
15 from typing import TYPE_CHECKING, Tuple
|
jpayne@68
|
16
|
jpayne@68
|
17 if TYPE_CHECKING:
|
jpayne@68
|
18 from typing_extensions import TypeAlias
|
jpayne@68
|
19
|
jpayne@68
|
20 _DueDate: TypeAlias = Tuple[int, int, int] # time tuple
|
jpayne@68
|
21 _INDENT = 8 * " "
|
jpayne@68
|
22 _TEMPLATE = f"""{80 * '*'}\n{{details}}\n{80 * '*'}"""
|
jpayne@68
|
23
|
jpayne@68
|
24
|
jpayne@68
|
25 class SetuptoolsWarning(UserWarning):
|
jpayne@68
|
26 """Base class in ``setuptools`` warning hierarchy."""
|
jpayne@68
|
27
|
jpayne@68
|
28 @classmethod
|
jpayne@68
|
29 def emit(
|
jpayne@68
|
30 cls,
|
jpayne@68
|
31 summary: str | None = None,
|
jpayne@68
|
32 details: str | None = None,
|
jpayne@68
|
33 due_date: _DueDate | None = None,
|
jpayne@68
|
34 see_docs: str | None = None,
|
jpayne@68
|
35 see_url: str | None = None,
|
jpayne@68
|
36 stacklevel: int = 2,
|
jpayne@68
|
37 **kwargs,
|
jpayne@68
|
38 ) -> None:
|
jpayne@68
|
39 """Private: reserved for ``setuptools`` internal use only"""
|
jpayne@68
|
40 # Default values:
|
jpayne@68
|
41 summary_ = summary or getattr(cls, "_SUMMARY", None) or ""
|
jpayne@68
|
42 details_ = details or getattr(cls, "_DETAILS", None) or ""
|
jpayne@68
|
43 due_date = due_date or getattr(cls, "_DUE_DATE", None)
|
jpayne@68
|
44 docs_ref = see_docs or getattr(cls, "_SEE_DOCS", None)
|
jpayne@68
|
45 docs_url = docs_ref and f"https://setuptools.pypa.io/en/latest/{docs_ref}"
|
jpayne@68
|
46 see_url = see_url or getattr(cls, "_SEE_URL", None)
|
jpayne@68
|
47 due = date(*due_date) if due_date else None
|
jpayne@68
|
48
|
jpayne@68
|
49 text = cls._format(summary_, details_, due, see_url or docs_url, kwargs)
|
jpayne@68
|
50 if due and due < date.today() and _should_enforce():
|
jpayne@68
|
51 raise cls(text)
|
jpayne@68
|
52 warnings.warn(text, cls, stacklevel=stacklevel + 1)
|
jpayne@68
|
53
|
jpayne@68
|
54 @classmethod
|
jpayne@68
|
55 def _format(
|
jpayne@68
|
56 cls,
|
jpayne@68
|
57 summary: str,
|
jpayne@68
|
58 details: str,
|
jpayne@68
|
59 due_date: date | None = None,
|
jpayne@68
|
60 see_url: str | None = None,
|
jpayne@68
|
61 format_args: dict | None = None,
|
jpayne@68
|
62 ) -> str:
|
jpayne@68
|
63 """Private: reserved for ``setuptools`` internal use only"""
|
jpayne@68
|
64 today = date.today()
|
jpayne@68
|
65 summary = cleandoc(summary).format_map(format_args or {})
|
jpayne@68
|
66 possible_parts = [
|
jpayne@68
|
67 cleandoc(details).format_map(format_args or {}),
|
jpayne@68
|
68 (
|
jpayne@68
|
69 f"\nBy {due_date:%Y-%b-%d}, you need to update your project and remove "
|
jpayne@68
|
70 "deprecated calls\nor your builds will no longer be supported."
|
jpayne@68
|
71 if due_date and due_date > today
|
jpayne@68
|
72 else None
|
jpayne@68
|
73 ),
|
jpayne@68
|
74 (
|
jpayne@68
|
75 "\nThis deprecation is overdue, please update your project and remove "
|
jpayne@68
|
76 "deprecated\ncalls to avoid build errors in the future."
|
jpayne@68
|
77 if due_date and due_date < today
|
jpayne@68
|
78 else None
|
jpayne@68
|
79 ),
|
jpayne@68
|
80 (f"\nSee {see_url} for details." if see_url else None),
|
jpayne@68
|
81 ]
|
jpayne@68
|
82 parts = [x for x in possible_parts if x]
|
jpayne@68
|
83 if parts:
|
jpayne@68
|
84 body = indent(_TEMPLATE.format(details="\n".join(parts)), _INDENT)
|
jpayne@68
|
85 return "\n".join([summary, "!!\n", body, "\n!!"])
|
jpayne@68
|
86 return summary
|
jpayne@68
|
87
|
jpayne@68
|
88
|
jpayne@68
|
89 class InformationOnly(SetuptoolsWarning):
|
jpayne@68
|
90 """Currently there is no clear way of displaying messages to the users
|
jpayne@68
|
91 that use the setuptools backend directly via ``pip``.
|
jpayne@68
|
92 The only thing that might work is a warning, although it is not the
|
jpayne@68
|
93 most appropriate tool for the job...
|
jpayne@68
|
94
|
jpayne@68
|
95 See pypa/packaging-problems#558.
|
jpayne@68
|
96 """
|
jpayne@68
|
97
|
jpayne@68
|
98
|
jpayne@68
|
99 class SetuptoolsDeprecationWarning(SetuptoolsWarning):
|
jpayne@68
|
100 """
|
jpayne@68
|
101 Base class for warning deprecations in ``setuptools``
|
jpayne@68
|
102
|
jpayne@68
|
103 This class is not derived from ``DeprecationWarning``, and as such is
|
jpayne@68
|
104 visible by default.
|
jpayne@68
|
105 """
|
jpayne@68
|
106
|
jpayne@68
|
107
|
jpayne@68
|
108 def _should_enforce():
|
jpayne@68
|
109 enforce = os.getenv("SETUPTOOLS_ENFORCE_DEPRECATION", "false").lower()
|
jpayne@68
|
110 return enforce in ("true", "on", "ok", "1")
|