1313 # Using file=sys.stderr prints to the error stream (usually prints red)
1414 print("This game requires Arcade 3.0.0+ to run!", file=sys.stderr)
1515
16+ The ``VERSION`` constant in this module will be loaded from a file in the
17+ same directory. It will contain the following:
1618
17- Arcade contributors will benefit from understanding how and why
18- this file loads and converts the contents of the ``VERSION`` file.
19+ #. major
20+ #. minor
21+ #. point
22+ #. (Optional) one and _only_ one of:
1923
20- After a release build succeeds, GitHub's CI is configured to do
21- the following:
22-
23- #. Push the package files to PyPI
24- #. Call the ``remorses/bump-version@js`` action to auto-increment
25- Arcade's version on the development branch
26-
27- This is where an edge case arises:
28-
29- #. Our CI expects ``3.1.0-dev.1`` for dev preview builds
30- #. Python expects ``3.1.0.dev1`` for dev preview builds
31-
32- The ``VERSION`` file in this file's directory stores the version
33- in the form the GH Action prefers. This allows it to auto-increment
34- the version number on the ``development`` branch after we make an
35- Arcade release to PyPI.
36-
37- The auto-bump action is configured by the following file:
38- https://github.com/pythonarcade/arcade/blob/development/.github/workflows/bump_version.yml
39-
40- As an example, the GH action would auto-increment a dev preview's
41- version after releasing the 5th dev preview of ``3.1.0`` by updating
42- the ``VERSION`` file from this:
43-
44- .. code-block::
45-
46- 3.1.0-dev.5
47-
48- ...to this:
49-
50- .. code-block::
51-
52- 3.1.0-dev.6
24+ * .dev{DEV_PREVIEW_NUMBER}
25+ * rc{RC_NUMBER}
5326
5427"""
5528
6336_HERE = Path (__file__ ).parent
6437
6538# Grab version numbers + optional dev point preview
66- # Assumes $MAJOR.$MINOR.$POINT format with optional -dev$DEV_PREVIEW
39+ # Assumes:
40+ # {MAJOR}.{MINOR}.{POINT} format
41+ # optional: one and ONLY one of:
42+ # 1. dev{DEV_PREVIEW}
43+ # 2. rc{RC_NUMBER}
6744# Q: Why did you use regex?!
6845# A: If the dev_preview field is invalid, the whole match fails instantly
69- _VERSION_REGEX = re .compile (
46+ _VERSION_REGEX : Final [ re . Pattern ] = re .compile (
7047 r"""
7148 # First three version number fields
7249 (?P<major>[0-9]+)
73- \.(?P<minor>[ 0-9]+ )
74- \.(?P<point>[ 0-9]+ )
75- # Optional dev preview suffix
50+ \.(?P<minor>0|[1-9][ 0-9]* )
51+ \.(?P<point>0|[1-9][ 0-9]* )
52+ # Optional and mutually exclusive: dev preview or rc number
7653 (?:
77- - dev # Dev prefix as a literal
78- \. # Point
79- (?P<dev_preview>[ 0-9]+) # Dev preview number
54+ \.(?P<dev_preview> dev(?:0|[1-9][0-9]*))
55+ | # XOR: can't be both a preview and an rc
56+ (?P<rc_number>rc(?:0|[1-9][ 0-9]*))
8057 )?
8158 """ ,
8259 re .X ,
8360)
8461
8562
86- def _parse_python_friendly_version (version_for_github_actions : str ) -> str :
87- """Convert a GitHub CI version string to a Python-friendly one.
63+ def _parse_python_friendly_version (
64+ raw_version : str ,
65+ pattern : re .Pattern [str ] = _VERSION_REGEX
66+ ) -> str :
67+ """Read a GitHub CI version string to a Python-friendly one.
8868
8969 For example, ``3.1.0-dev.1`` would become ``3.1.0.dev1``.
9070
9171 Args:
92- version_for_github_actions :
72+ raw_version :
9373 A raw GitHub CI version string, as read from a file.
9474 Returns:
9575 A Python-friendly version string.
9676 """
9777 # Quick preflight check: we don't support tuple format here!
98- if not isinstance (version_for_github_actions , str ):
99- raise TypeError (
100- f"Expected a string of the format MAJOR.MINOR.POINT"
101- f"or MAJOR.MINOR.POINT-dev.DEV_PREVIEW,"
102- f"not { version_for_github_actions !r} "
103- )
78+ problem = None
79+ if not isinstance (raw_version , str ):
80+ problem = TypeError
81+ elif (match := pattern .fullmatch (raw_version )) is None :
82+ problem = ValueError
83+ if problem :
84+ raise problem (
85+ f"{ raw_version = !r} not a str of the format MAJOR.MINOR"
86+ f"POINT with at most one of dev{{DEV_PREVIEW}} or"
87+ f"rc{{RC_NUMBER}}," )
88+
89+ # Build final output, including a dev preview version if present
90+ group_dict : dict [str , str | None ] = match .groupdict () # type: ignore
91+ parts : list [str ] = [group_dict [k ] for k in ('major' , 'minor' , 'point' )] # type: ignore
92+ dev_preview , rc_number = (group_dict [k ] for k in ('dev_preview' , 'rc_number' ))
10493
105- # Attempt to extract our raw data
106- match = _VERSION_REGEX .fullmatch (version_for_github_actions .strip ())
107- if match is None :
108- raise ValueError (
109- f"String does not appear to be a version number: { version_for_github_actions !r} "
110- )
94+ if dev_preview and rc_number :
95+ raise ValueError (f"Can't have both { dev_preview = !r} and { rc_number = !r} " )
96+ elif dev_preview :
97+ parts .append (dev_preview )
11198
112- # Build final output, including a dev preview version if present
113- group_dict = match .groupdict ()
114- major , minor , point , dev_preview = group_dict .values ()
115- parts = [major , minor , point ]
116- if dev_preview is not None :
117- parts .append (f"dev{ dev_preview } " )
11899 joined = "." .join (parts )
100+ if rc_number :
101+ joined += rc_number
119102
120103 return joined
121104
122105
123- def _parse_py_version_from_github_ci_file (
106+ def _parse_py_version_from_file (
124107 version_path : str | Path = _HERE / "VERSION" , write_errors_to = sys .stderr
125108) -> str :
126- """Parse a Python-friendly version from a ``bump-version``-compatible file .
109+ """Read & validate the VERSION file as from a limited subset .
127110
128111 On failure, it will:
129112
130113 #. Print an error to stderr
131114 #. Return "0.0.0"
115+ #. (Indirectly) cause any PyPI uploads to fail
132116
133117 Args:
134118 version_path:
@@ -152,7 +136,7 @@ def _parse_py_version_from_github_ci_file(
152136 return data
153137
154138
155- VERSION : Final [str ] = _parse_py_version_from_github_ci_file ()
139+ VERSION : Final [str ] = _parse_py_version_from_file ()
156140"""A Python-friendly version string.
157141
158142This value is converted from the GitHub-style ``VERSION`` file at the
0 commit comments