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

Turn SCons.Variables.Variable into a dataclass #4658

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
7 changes: 7 additions & 0 deletions CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,13 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER
their values taken from the default in the variable description
(if a variable was set to the same value as the default in one
of the input sources, it is not included in this list).
- If a build Variable is created with no aliases, the name of the
Variable is no longer listed in its aliases. Internally, the name
and aliases are considered together anyway so this should not have
any effect except for being visible to custom help text formatters.
- A build Variable is now a dataclass, with initialization moving to
the automatically provided method; the Variables class no longer
writes directly to a Variable (makes static checkers happier).


RELEASE 4.8.1 - Tue, 03 Sep 2024 17:22:20 -0700
Expand Down
5 changes: 5 additions & 0 deletions RELEASE.txt
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@ CHANGED/ENHANCED EXISTING FUNCTIONALITY
(if a variable was set to the same value as the default in one
of the input sources, it is not included in this list).

- If a build Variable is created with no aliases, the name of the
Variable is no longer listed in its aliases. Internally, the name
and aliases are considered together anyway so this should not have
any effect except for being visible to custom help text formatters.

FIXES
-----

Expand Down
14 changes: 7 additions & 7 deletions SCons/Variables/VariablesTests.py
Original file line number Diff line number Diff line change
Expand Up @@ -550,7 +550,7 @@ def my_format(env, opt, help, default, actual, aliases) -> str:
check,
lambda x: int(x) + 12)

opts.Add('B',
opts.Add(['B', 'BOPTION'],
'b - alpha test',
"42",
check,
Expand All @@ -566,19 +566,19 @@ def my_format(env, opt, help, default, actual, aliases) -> str:
opts.Update(env, {})

expect = """\
ANSWER 42 54 THE answer to THE question ['ANSWER']
B 42 54 b - alpha test ['B']
A 42 54 a - alpha test ['A']
ANSWER 42 54 THE answer to THE question []
B 42 54 b - alpha test ['BOPTION']
A 42 54 a - alpha test []
"""

text = opts.GenerateHelpText(env)
with self.subTest():
self.assertEqual(expect, text)

expectAlpha = """\
A 42 54 a - alpha test ['A']
ANSWER 42 54 THE answer to THE question ['ANSWER']
B 42 54 b - alpha test ['B']
A 42 54 a - alpha test []
ANSWER 42 54 THE answer to THE question []
B 42 54 b - alpha test ['BOPTION']
"""
text = opts.GenerateHelpText(env, sort=cmp)
with self.subTest():
Expand Down
56 changes: 21 additions & 35 deletions SCons/Variables/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,9 @@
import os.path
import sys
from contextlib import suppress
from dataclasses import dataclass
from functools import cmp_to_key
from typing import Callable, Sequence
from typing import Any, Callable, Sequence

import SCons.Errors
import SCons.Util
Expand All @@ -53,22 +54,18 @@
"PathVariable",
]


@dataclass(order=True)
class Variable:
"""A Build Variable."""

__slots__ = ('key', 'aliases', 'help', 'default', 'validator', 'converter', 'do_subst')

def __lt__(self, other):
"""Comparison fuction so :class:`Variable` instances sort."""
return self.key < other.key

def __str__(self) -> str:
"""Provide a way to "print" a :class:`Variable` object."""
return (
f"({self.key!r}, {self.aliases}, "
f"help={self.help!r}, default={self.default!r}, "
f"validator={self.validator}, converter={self.converter})"
)
key: str
aliases: list[str]
help: str
default: Any
validator: Callable | None
converter: Callable | None
do_subst: bool


class Variables:
Expand Down Expand Up @@ -131,7 +128,7 @@ def __str__(self) -> str:
# lint: W0622: Redefining built-in 'help'
def _do_add(
self,
key: str | list[str],
key: str | Sequence[str],
help: str = "",
default=None,
validator: Callable | None = None,
Expand All @@ -146,30 +143,19 @@ def _do_add(
.. versionadded:: 4.8.0
*subst* keyword argument is now recognized.
"""
option = Variable()

# If we get a list or a tuple, we take the first element as the
# option key and store the remaining in aliases.
# aliases needs to be a list for later concatenation operations
if SCons.Util.is_Sequence(key):
option.key = key[0]
option.aliases = list(key[1:])
name, aliases = key[0], list(key[1:])
else:
option.key = key
# TODO: normalize to not include key in aliases. Currently breaks tests.
option.aliases = [key,]
if not option.key.isidentifier():
raise SCons.Errors.UserError(f"Illegal Variables key {option.key!r}")
option.help = help
option.default = default
option.validator = validator
option.converter = converter
option.do_subst = kwargs.pop("subst", True)
# TODO should any remaining kwargs be saved in the Variable?

name, aliases = key, []
if not name.isidentifier():
raise SCons.Errors.UserError(f"Illegal Variables key {name!r}")
do_subst = kwargs.pop("subst", True)
option = Variable(name, aliases, help, default, validator, converter, do_subst)
self.options.append(option)

# options might be added after the 'unknown' dict has been set up,
# so we remove the key and all its aliases from that dict
# options might be added after the 'unknown' dict has been set up:
# look for and remove the key and all its aliases from that dict
for alias in option.aliases + [option.key,]:
if alias in self.unknown:
del self.unknown[alias]
Expand Down