Skip to content

Commit a6f4983

Browse files
authored
Merge pull request SCons#4554 from mwichmann/move-env-checker
Move environment var checker to SCons.Util
2 parents 10e00ec + 0fe8822 commit a6f4983

File tree

9 files changed

+77
-66
lines changed

9 files changed

+77
-66
lines changed

CHANGES.txt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,15 +86,19 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER
8686
updated in 4.6). All SCons usage except unit test was already fully
8787
consistent with a bool.
8888
- When a variable is added to a Variables object, it can now be flagged
89-
as "don't perform substitution" by setting the argument subst.
90-
This allows variables to contain characters which would otherwise
89+
as "don't perform substitution" by setting the argument subst.
90+
This allows variables to contain characters which would otherwise
9191
cause expansion. Fixes #4241.
9292
- The test runner now recognizes the unittest module's return code of 5,
9393
which means no tests were run. SCons/Script/MainTests.py currently
9494
has no tests, so this particular error code is expected - should not
9595
cause runtest to give up with an "unknown error code".
9696
- Updated the notes about reproducible builds with SCons and the example.
9797
- The Clone() method now respects the variables argument (fixes #3590)
98+
- is_valid_construction_var() (not part of the public API) moved from
99+
SCons.Environment to SCons.Util to avoid the chance of import loops. Variables
100+
and Environment both use the routine and Environment() uses a Variables()
101+
object so better to move to a safer location.
98102

99103

100104
RELEASE 4.7.0 - Sun, 17 Mar 2024 17:22:20 -0700

RELEASE.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,10 @@ DEVELOPMENT
107107
which means no tests were run. SCons/Script/MainTests.py currently
108108
has no tests, so this particular error code is expected - should not
109109
cause runtest to give up with an "unknown error code".
110-
110+
- is_valid_construction_var() (not part of the public API) moved from
111+
SCons.Environment to SCons.Util to avoid the chance of import loops. Variables
112+
and Environment both use the routine and Environment() uses a Variables()
113+
object so better to move to a safer location.
111114

112115
Thanks to the following contributors listed below for their contributions to this release.
113116
==========================================================================================

SCons/Environment.py

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
to_String_for_subst,
7777
uniquer_hashables,
7878
)
79+
from SCons.Util.envs import is_valid_construction_var
7980
from SCons.Util.sctyping import ExecutorType
8081

8182
class _Null:
@@ -510,13 +511,6 @@ def update(self, mapping) -> None:
510511
self.__setitem__(i, v)
511512

512513

513-
_is_valid_var = re.compile(r'[_a-zA-Z]\w*$')
514-
515-
def is_valid_construction_var(varstr: str) -> bool:
516-
"""Return True if *varstr* is a legitimate construction variable."""
517-
return bool(_is_valid_var.match(varstr))
518-
519-
520514
class SubstitutionEnvironment:
521515
"""Base class for different flavors of construction environments.
522516
@@ -605,7 +599,7 @@ def __setitem__(self, key, value):
605599
# key and we don't need to check. If we do check, using a
606600
# global, pre-compiled regular expression directly is more
607601
# efficient than calling another function or a method.
608-
if key not in self._dict and not _is_valid_var.match(key):
602+
if key not in self._dict and not is_valid_construction_var(key):
609603
raise UserError("Illegal construction variable `%s'" % key)
610604
self._dict[key] = value
611605

SCons/EnvironmentTests.py

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@
3838
NoSubstitutionProxy,
3939
OverrideEnvironment,
4040
SubstitutionEnvironment,
41-
is_valid_construction_var,
4241
)
4342
from SCons.Util import CLVar
4443
from SCons.SConsign import current_sconsign_filename
@@ -4142,40 +4141,6 @@ def test_subst_target_source(self) -> None:
41424141
x = proxy.subst_target_source(*args, **kw)
41434142
assert x == ' ttt sss ', x
41444143

4145-
class EnvironmentVariableTestCase(unittest.TestCase):
4146-
4147-
def test_is_valid_construction_var(self) -> None:
4148-
"""Testing is_valid_construction_var()"""
4149-
r = is_valid_construction_var("_a")
4150-
assert r, r
4151-
r = is_valid_construction_var("z_")
4152-
assert r, r
4153-
r = is_valid_construction_var("X_")
4154-
assert r, r
4155-
r = is_valid_construction_var("2a")
4156-
assert not r, r
4157-
r = is_valid_construction_var("a2_")
4158-
assert r, r
4159-
r = is_valid_construction_var("/")
4160-
assert not r, r
4161-
r = is_valid_construction_var("_/")
4162-
assert not r, r
4163-
r = is_valid_construction_var("a/")
4164-
assert not r, r
4165-
r = is_valid_construction_var(".b")
4166-
assert not r, r
4167-
r = is_valid_construction_var("_.b")
4168-
assert not r, r
4169-
r = is_valid_construction_var("b1._")
4170-
assert not r, r
4171-
r = is_valid_construction_var("-b")
4172-
assert not r, r
4173-
r = is_valid_construction_var("_-b")
4174-
assert not r, r
4175-
r = is_valid_construction_var("b1-_")
4176-
assert not r, r
4177-
4178-
41794144

41804145
if __name__ == "__main__":
41814146
unittest.main()

SCons/Util/UtilTests.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
to_bytes,
7474
to_str,
7575
)
76+
from SCons.Util.envs import is_valid_construction_var
7677
from SCons.Util.hashes import (
7778
_attempt_init_of_python_3_9_hash_object,
7879
_attempt_get_hash_function,
@@ -1206,6 +1207,41 @@ def test_default(self) -> None:
12061207
assert var is False, 'var should be False, not %s' % repr(var)
12071208

12081209

1210+
class EnvironmentVariableTestCase(unittest.TestCase):
1211+
1212+
def test_is_valid_construction_var(self) -> None:
1213+
"""Testing is_valid_construction_var()"""
1214+
r = is_valid_construction_var("_a")
1215+
assert r, r
1216+
r = is_valid_construction_var("z_")
1217+
assert r, r
1218+
r = is_valid_construction_var("X_")
1219+
assert r, r
1220+
r = is_valid_construction_var("2a")
1221+
assert not r, r
1222+
r = is_valid_construction_var("a2_")
1223+
assert r, r
1224+
r = is_valid_construction_var("/")
1225+
assert not r, r
1226+
r = is_valid_construction_var("_/")
1227+
assert not r, r
1228+
r = is_valid_construction_var("a/")
1229+
assert not r, r
1230+
r = is_valid_construction_var(".b")
1231+
assert not r, r
1232+
r = is_valid_construction_var("_.b")
1233+
assert not r, r
1234+
r = is_valid_construction_var("b1._")
1235+
assert not r, r
1236+
r = is_valid_construction_var("-b")
1237+
assert not r, r
1238+
r = is_valid_construction_var("_-b")
1239+
assert not r, r
1240+
r = is_valid_construction_var("b1-_")
1241+
assert not r, r
1242+
1243+
1244+
12091245
if __name__ == "__main__":
12101246
unittest.main()
12111247

SCons/Util/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@
107107
AppendPath,
108108
AddPathIfNotExists,
109109
AddMethod,
110+
is_valid_construction_var,
110111
)
111112
from .filelock import FileLock, SConsLockFailure
112113

SCons/Util/envs.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
that don't need the specifics of the Environment class.
1010
"""
1111

12+
import re
1213
import os
1314
from types import MethodType, FunctionType
1415
from typing import Union, Callable, Optional, Any
@@ -329,6 +330,12 @@ def AddMethod(obj, function: Callable, name: Optional[str] = None) -> None:
329330
setattr(obj, name, method)
330331

331332

333+
_is_valid_var_re = re.compile(r'[_a-zA-Z]\w*$')
334+
335+
def is_valid_construction_var(varstr: str) -> bool:
336+
"""Return True if *varstr* is a legitimate construction variable."""
337+
return bool(_is_valid_var_re.match(varstr))
338+
332339
# Local Variables:
333340
# tab-width:4
334341
# indent-tabs-mode:nil

SCons/Variables/__init__.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
from functools import cmp_to_key
2929
from typing import Callable, Dict, List, Optional, Sequence, Union
3030

31-
import SCons.Environment
3231
import SCons.Errors
3332
import SCons.Util
3433
import SCons.Warnings
@@ -70,13 +69,15 @@ class Variables:
7069
files: string or list of strings naming variable config scripts
7170
(default ``None``)
7271
args: dictionary to override values set from *files*. (default ``None``)
73-
is_global: if true, return a global singleton Variables object instead
74-
of a fresh instance. Currently inoperable (default ``False``)
72+
is_global: if true, return a global singleton :class:`Variables` object
73+
instead of a fresh instance. Currently inoperable (default ``False``)
7574
7675
.. versionchanged:: 4.8.0
77-
The default for *is_global* changed to ``False`` (previously
78-
``True`` but it had no effect due to an implementation error).
79-
*is_global* is deprecated.
76+
The default for *is_global* changed to ``False`` (previously
77+
``True`` but it had no effect due to an implementation error).
78+
79+
.. deprecated:: 4.8.0
80+
*is_global* is deprecated.
8081
"""
8182

8283
def __init__(
@@ -130,7 +131,7 @@ def _do_add(
130131
option.key = key
131132
# TODO: normalize to not include key in aliases. Currently breaks tests.
132133
option.aliases = [key,]
133-
if not SCons.Environment.is_valid_construction_var(option.key):
134+
if not SCons.Util.is_valid_construction_var(option.key):
134135
raise SCons.Errors.UserError(f"Illegal Variables key {option.key!r}")
135136
option.help = help
136137
option.default = default

bench/env.__setitem__.py

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
# __COPYRIGHT__
22
#
33
# Benchmarks for testing various possible implementations of the
4-
# env.__setitem__() method(s) in the src/engine/SCons/Environment.py
5-
# module.
4+
# env.__setitem__() method(s) in the SCons/Environment.py module.
65

76
from __future__ import print_function
87

@@ -25,10 +24,10 @@ def __init__(self, name, num, init, statement):
2524
self.name = name
2625
self.statement = statement
2726
self.__result = None
28-
27+
2928
def timeit(self):
3029
self.__result = self.__timer.timeit(self.__num)
31-
30+
3231
def getResult(self):
3332
return self.__result
3433

@@ -62,8 +61,9 @@ def times(num=1000000, init='', title='Results:', **statements):
6261

6362
import SCons.Errors
6463
import SCons.Environment
64+
import SCons.Util
6565

66-
is_valid_construction_var = SCons.Environment.is_valid_construction_var
66+
is_valid_construction_var = SCons.Util.is_valid_construction_var
6767
global_valid_var = re.compile(r'[_a-zA-Z]\w*$')
6868

6969
# The classes with different __setitem__() implementations that we're
@@ -80,7 +80,7 @@ def times(num=1000000, init='', title='Results:', **statements):
8080
#
8181
# The env_Original subclass contains the original implementation (which
8282
# actually had the is_valid_construction_var() function in SCons.Util
83-
# originally).
83+
# originally). Update: it has moved back, to avoid import loop with Variables.
8484
#
8585
# The other subclasses (except for env_Best) each contain *one*
8686
# significant change from the env_Original implementation. The doc string
@@ -116,7 +116,7 @@ def __setitem__(self, key, value):
116116
if special:
117117
special(self, key, value)
118118
else:
119-
if not SCons.Environment.is_valid_construction_var(key):
119+
if not SCons.Util.is_valid_construction_var(key):
120120
raise SCons.Errors.UserError("Illegal construction variable `%s'" % key)
121121
self._dict[key] = value
122122

@@ -176,7 +176,7 @@ def __setitem__(self, key, value):
176176
if key in self._special_set:
177177
self._special_set[key](self, key, value)
178178
else:
179-
if not SCons.Environment.is_valid_construction_var(key):
179+
if not SCons.Util.is_valid_construction_var(key):
180180
raise SCons.Errors.UserError("Illegal construction variable `%s'" % key)
181181
self._dict[key] = value
182182

@@ -186,7 +186,7 @@ def __setitem__(self, key, value):
186186
if key in ('BUILDERS', 'SCANNERS', 'TARGET', 'TARGETS', 'SOURCE', 'SOURCES'):
187187
self._special_set[key](self, key, value)
188188
else:
189-
if not SCons.Environment.is_valid_construction_var(key):
189+
if not SCons.Util.is_valid_construction_var(key):
190190
raise SCons.Errors.UserError("Illegal construction variable `%s'" % key)
191191
self._dict[key] = value
192192

@@ -196,7 +196,7 @@ def __setitem__(self, key, value):
196196
if key in ['BUILDERS', 'SCANNERS', 'TARGET', 'TARGETS', 'SOURCE', 'SOURCES']:
197197
self._special_set[key](self, key, value)
198198
else:
199-
if not SCons.Environment.is_valid_construction_var(key):
199+
if not SCons.Util.is_valid_construction_var(key):
200200
raise SCons.Errors.UserError("Illegal construction variable `%s'" % key)
201201
self._dict[key] = value
202202

@@ -206,7 +206,7 @@ def __setitem__(self, key, value):
206206
if key in self._special_set_keys:
207207
self._special_set[key](self, key, value)
208208
else:
209-
if not SCons.Environment.is_valid_construction_var(key):
209+
if not SCons.Util.is_valid_construction_var(key):
210210
raise SCons.Errors.UserError("Illegal construction variable `%s'" % key)
211211
self._dict[key] = value
212212

@@ -220,7 +220,7 @@ def __setitem__(self, key, value):
220220
try:
221221
self._dict[key]
222222
except KeyError:
223-
if not SCons.Environment.is_valid_construction_var(key):
223+
if not SCons.Util.is_valid_construction_var(key):
224224
raise SCons.Errors.UserError("Illegal construction variable `%s'" % key)
225225
self._dict[key] = value
226226

@@ -232,7 +232,7 @@ def __setitem__(self, key, value):
232232
special(self, key, value)
233233
else:
234234
if key not in self._dict \
235-
and not SCons.Environment.is_valid_construction_var(key):
235+
and not SCons.Util.is_valid_construction_var(key):
236236
raise SCons.Errors.UserError("Illegal construction variable `%s'" % key)
237237
self._dict[key] = value
238238

0 commit comments

Comments
 (0)