Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Variables cleanup: ListVariable #4529

Merged
merged 1 commit into from
May 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 53 additions & 29 deletions SCons/Variables/ListVariable.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

"""Variable type for list Variables.
"""Variable type for List Variables.

A 'list' option may either be 'all', 'none' or a list of names
separated by comma. After the option has been processed, the option
A list variable may given as 'all', 'none' or a list of names
separated by comma. After the variable has been processed, the variable
value holds either the named list elements, all list elements or no
list elements at all.

Expand All @@ -41,7 +41,7 @@
elems=list_of_libs,
)
)
...
env = Environment(variables=opts)
for lib in list_of_libs:
if lib in env['shared']:
env.SharedObject(...)
Expand All @@ -53,14 +53,21 @@
# since elements can occur twice.

import collections
from typing import Tuple, Callable
from typing import Callable, List, Optional, Tuple, Union

import SCons.Util

__all__ = ['ListVariable',]


class _ListVariable(collections.UserList):
"""Internal class holding the data for a List Variable.

The initializer accepts two arguments, the list of actual values
given, and the list of allowable values. Not normally instantiated
by hand, but rather by the ListVariable converter function.
"""

def __init__(self, initlist=None, allowedElems=None) -> None:
if initlist is None:
initlist = []
Expand Down Expand Up @@ -88,19 +95,18 @@ def __lt__(self, other):
return NotImplemented

def __str__(self) -> str:
if not len(self):
if not self.data:
return 'none'
self.data.sort()
if self.data == self.allowedElems:
return 'all'
else:
return ','.join(self)
return ','.join(self)

def prepare_to_store(self):
return self.__str__()
return str(self)

def _converter(val, allowedElems, mapdict) -> _ListVariable:
""" """
"""Convert list variables."""
if val == 'none':
val = []
elif val == 'all':
Expand All @@ -111,39 +117,57 @@ def _converter(val, allowedElems, mapdict) -> _ListVariable:
notAllowed = [v for v in val if v not in allowedElems]
if notAllowed:
raise ValueError(
"Invalid value(s) for option: %s" % ','.join(notAllowed)
f"Invalid value(s) for option: {','.join(notAllowed)}"
)
return _ListVariable(val, allowedElems)


# def _validator(key, val, env) -> None:
# """ """
# # TODO: write validator for pgk list
# # TODO: write validator for list variable
# pass


def ListVariable(key, help, default, names, map={}) -> Tuple[str, str, str, None, Callable]:
"""Return a tuple describing a list SCons Variable.

The input parameters describe a 'list' option. Returns
a tuple including the correct converter and validator.
The result is usable for input to :meth:`Add`.

*help* will have text appended indicating the legal values
(not including any extra names from *map*).

*map* can be used to map alternative names to the ones in *names* -
that is, a form of alias.

A 'list' option may either be 'all', 'none' or a list of
names (separated by commas).
# lint: W0622: Redefining built-in 'help' (redefined-builtin)
# lint: W0622: Redefining built-in 'map' (redefined-builtin)
def ListVariable(
key,
help: str,
default: Union[str, List[str]],
names: List[str],
map: Optional[dict] = None,
) -> Tuple[str, str, str, None, Callable]:
"""Return a tuple describing a list variable.

The input parameters describe a list variable, where the values
can be one or more from *names* plus the special values ``all``
and ``none``.

Arguments:
key: the name of the list variable.
help: the basic help message. Will have text appended indicating
the allowable values (not including any extra names from *map*).
default: the default value(s) for the list variable. Can be
given as string (possibly comma-separated), or as a list of strings.
``all`` or ``none`` are allowed as *default*.
names: the allowable values. Must be a list of strings.
map: optional dictionary to map alternative names to the ones in
*names*, providing a form of alias. The converter will make
the replacement, names from *map* are not stored and will
not appear in the help message.

Returns:
A tuple including the correct converter and validator. The
result is usable as input to :meth:`~SCons.Variables.Variables.Add`.
"""
names_str = 'allowed names: %s' % ' '.join(names)
if map is None:
map = {}
names_str = f"allowed names: {' '.join(names)}"
if SCons.Util.is_List(default):
default = ','.join(default)
help = '\n '.join(
(help, '(all|none|comma-separated list of names)', names_str))
return (key, help, default, None, lambda val: _converter(val, names, map))
return key, help, default, None, lambda val: _converter(val, names, map)

# Local Variables:
# tab-width:4
Expand Down
6 changes: 1 addition & 5 deletions SCons/Variables/ListVariableTests.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,8 @@ def test_converter(self) -> None:
x = o.converter('three,ONE,TWO')
assert str(x) == 'all', x

caught = None
try:
with self.assertRaises(ValueError):
x = o.converter('no_match')
except ValueError:
caught = 1
assert caught, "did not catch expected ValueError"

def test_copy(self) -> None:
"""Test copying a ListVariable like an Environment would"""
Expand Down
4 changes: 0 additions & 4 deletions test/Variables/ListVariable.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,6 @@ def check(expect):

test.run(arguments='shared=foo,x11,,,bar', stderr=expect_stderr, status=2)



test.write('SConstruct', """
from SCons.Variables import ListVariable

Expand All @@ -174,8 +172,6 @@ def check(expect):
scons: Nothing to be done for `dummy'.
"""))



test.pass_test()

# Local Variables:
Expand Down
Loading