Skip to content

Commit 3292e6c

Browse files
authored
Mark constants in config as Final (#422)
1 parent 00cfa15 commit 3292e6c

File tree

8 files changed

+61
-60
lines changed

8 files changed

+61
-60
lines changed

bin/config.py

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,20 @@
55
import os
66
import re
77
from pathlib import Path
8-
from typing import Literal, Optional
8+
from typing import Final, Literal, Optional
99

1010
# return values
11-
RTV_AC = 42
12-
RTV_WA = 43
11+
RTV_AC: Final = 42
12+
RTV_WA: Final = 43
1313

14-
SUBMISSION_DIRS = [
14+
SUBMISSION_DIRS: Final = [
1515
"accepted",
1616
"wrong_answer",
1717
"time_limit_exceeded",
1818
"run_time_error",
1919
]
2020

21-
KNOWN_LICENSES = [
21+
KNOWN_LICENSES: Final = [
2222
"cc by-sa",
2323
"cc by",
2424
"cc0",
@@ -29,25 +29,25 @@
2929
]
3030

3131
# When --table is set, this threshold determines the number of identical profiles needed to get flagged.
32-
TABLE_THRESHOLD = 4
32+
TABLE_THRESHOLD: Final = 4
3333

34-
FILE_NAME_REGEX = "[a-zA-Z0-9][a-zA-Z0-9_.-]*[a-zA-Z0-9]"
35-
COMPILED_FILE_NAME_REGEX = re.compile(FILE_NAME_REGEX)
34+
FILE_NAME_REGEX: Final = "[a-zA-Z0-9][a-zA-Z0-9_.-]*[a-zA-Z0-9]"
35+
COMPILED_FILE_NAME_REGEX: Final = re.compile(FILE_NAME_REGEX)
3636

37-
KNOWN_TESTCASE_EXTENSIONS = [
37+
KNOWN_TESTCASE_EXTENSIONS: Final = [
3838
".in",
3939
".ans",
4040
".out",
4141
]
4242

43-
KNOWN_VISUALIZER_EXTENSIONS = [
43+
KNOWN_VISUALIZER_EXTENSIONS: Final = [
4444
".png",
4545
".jpg",
4646
".svg",
4747
".pdf",
4848
]
4949

50-
KNOWN_TEXT_DATA_EXTENSIONS = KNOWN_TESTCASE_EXTENSIONS + [
50+
KNOWN_TEXT_DATA_EXTENSIONS: Final = KNOWN_TESTCASE_EXTENSIONS + [
5151
".interaction",
5252
".hint",
5353
".desc",
@@ -56,32 +56,32 @@
5656
#'.args',
5757
]
5858

59-
KNOWN_DATA_EXTENSIONS = KNOWN_TEXT_DATA_EXTENSIONS + KNOWN_VISUALIZER_EXTENSIONS
59+
KNOWN_DATA_EXTENSIONS: Final = KNOWN_TEXT_DATA_EXTENSIONS + KNOWN_VISUALIZER_EXTENSIONS
6060

61-
INVALID_CASE_DIRECTORIES = [
61+
INVALID_CASE_DIRECTORIES: Final = [
6262
"invalid_inputs",
6363
"invalid_answers",
6464
"invalid_outputs",
6565
"bad",
6666
]
6767

6868

69-
SEED_DEPENDENCY_RETRIES = 10
69+
SEED_DEPENDENCY_RETRIES: Final = 10
7070

7171
# The root directory of the BAPCtools repository.
72-
tools_root = Path(__file__).resolve().parent.parent
72+
TOOLS_ROOT: Final = Path(__file__).resolve().parent.parent
7373

7474
# The directory from which BAPCtools is invoked.
75-
current_working_directory = Path.cwd().resolve()
75+
current_working_directory: Final = Path.cwd().resolve()
7676

7777
# Add third_party/ to the $PATH for checktestdata.
78-
os.environ["PATH"] += os.pathsep + str(tools_root / "third_party")
78+
os.environ["PATH"] += os.pathsep + str(TOOLS_ROOT / "third_party")
7979

8080
# Below here is some global state that will be filled in main().
8181

8282
args = argparse.Namespace()
8383

84-
default_args = {
84+
DEFAULT_ARGS: Final = {
8585
"jobs": (os.cpu_count() or 1) // 2,
8686
"time": 600, # Used for `bt fuzz`
8787
"verbose": 0,
@@ -93,19 +93,19 @@
9393
"""
9494
for cmd in $(bapctools --help | grep '^ {' | sed 's/ {//;s/}//;s/,/ /g') ; do bapctools $cmd --help ; done |& \
9595
grep '^ [^ ]' | sed 's/^ //' | cut -d ' ' -f 1 | sed -E 's/,//;s/^-?-?//;s/-/_/g' | sort -u | \
96-
grep -Ev '^(h|jobs|time|verbose)$' | sed "s/^/'/;s/$/',/" | tr '\n' ' ' | sed 's/^/args_list = [/;s/, $/]\n/'
96+
grep -Ev '^(h|jobs|time|verbose)$' | sed "s/^/'/;s/$/',/" | tr '\n' ' ' | sed 's/^/ARGS_LIST: Final = [/;s/, $/]\n/'
9797
"""
9898
# fmt: off
99-
args_list = ['1', 'add', 'all', 'answer', 'api', 'author', 'check_deterministic', 'clean', 'colors', 'contest', 'contest_id', 'contestname', 'cp', 'default_solution', 'depth', 'directory', 'error', 'force', 'force_build', 'input', 'interaction', 'interactive', 'invalid', 'kattis', 'language', 'memory', 'more', 'move_to', 'no_bar', 'no_generate', 'no_solution', 'no_solutions', 'no_testcase_sanity_checks', 'no_time_limit', 'no_validators', 'no_visualizer', 'open', 'order', 'order_from_ccs', 'overview', 'password', 'post_freeze', 'problem', 'problemname', 'remove', 'reorder', 'samples', 'sanitizer', 'skel', 'skip', 'sort', 'submissions', 'table', 'testcases', 'time_limit', 'timeout', 'token', 'tree', 'username', 'validation', 'watch', 'web', 'write']
99+
ARGS_LIST: Final = ['1', 'add', 'all', 'answer', 'api', 'author', 'check_deterministic', 'clean', 'colors', 'contest', 'contest_id', 'contestname', 'cp', 'default_solution', 'depth', 'directory', 'error', 'force', 'force_build', 'input', 'interaction', 'interactive', 'invalid', 'kattis', 'language', 'memory', 'more', 'move_to', 'no_bar', 'no_generate', 'no_solution', 'no_solutions', 'no_testcase_sanity_checks', 'no_time_limit', 'no_validators', 'no_visualizer', 'open', 'order', 'order_from_ccs', 'overview', 'password', 'post_freeze', 'problem', 'problemname', 'remove', 'reorder', 'samples', 'sanitizer', 'skel', 'skip', 'sort', 'submissions', 'table', 'testcases', 'time_limit', 'timeout', 'token', 'tree', 'username', 'validation', 'watch', 'web', 'write']
100100
# fmt: on
101101

102102

103103
def set_default_args():
104104
# Set default argument values.
105-
for arg in args_list:
105+
for arg in ARGS_LIST:
106106
if not hasattr(args, arg):
107107
setattr(args, arg, None)
108-
for arg, value in default_args.items():
108+
for arg, value in DEFAULT_ARGS.items():
109109
if not hasattr(args, arg):
110110
setattr(args, arg, value)
111111

@@ -124,5 +124,5 @@ def set_default_args():
124124

125125

126126
# Randomly generated uuid4 for BAPCtools
127-
BAPC_UUID = "8ee7605a-d1ce-47b3-be37-15de5acd757e"
128-
BAPC_UUID_PREFIX = 8
127+
BAPC_UUID: Final = "8ee7605a-d1ce-47b3-be37-15de5acd757e"
128+
BAPC_UUID_PREFIX: Final = 8

bin/generate.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from collections.abc import Callable
88
from colorama import Fore, Style
99
from pathlib import Path, PurePosixPath
10-
from typing import overload
10+
from typing import Final, overload
1111

1212
import config
1313
import parallel
@@ -40,7 +40,7 @@ def assert_type(name, obj, types, path=None):
4040
)
4141

4242

43-
UNIQUE_TESTCASE_KEYS = [
43+
UNIQUE_TESTCASE_KEYS: Final = [
4444
"copy",
4545
"generate",
4646
"retries",
@@ -88,8 +88,8 @@ def resolve_path(path, *, allow_absolute, allow_relative):
8888
# - SolutionInvocation
8989
# - VisualizerInvocation
9090
class Invocation:
91-
SEED_REGEX = re.compile(r"\{seed(:[0-9]+)?\}")
92-
NAME_REGEX = re.compile(r"\{name\}")
91+
SEED_REGEX: Final = re.compile(r"\{seed(:[0-9]+)?\}")
92+
NAME_REGEX: Final = re.compile(r"\{name\}")
9393

9494
# `string` is the name of the submission (relative to generators/ or absolute from the problem root) with command line arguments.
9595
# A direct path may also be given.
@@ -318,7 +318,7 @@ def __init__(self, generator_config):
318318
super().__init__(generator_config.problem, default_solution_path(generator_config))
319319

320320

321-
KNOWN_TESTCASE_KEYS = [
321+
KNOWN_TESTCASE_KEYS: Final = [
322322
"type",
323323
"generate",
324324
"copy",
@@ -328,8 +328,8 @@ def __init__(self, generator_config):
328328
"retries",
329329
"count",
330330
] + [e[1:] for e in config.KNOWN_TEXT_DATA_EXTENSIONS]
331-
RESERVED_TESTCASE_KEYS = ["data", "testdata.yaml", "include"]
332-
KNOWN_DIRECTORY_KEYS = [
331+
RESERVED_TESTCASE_KEYS: Final = ["data", "testdata.yaml", "include"]
332+
KNOWN_DIRECTORY_KEYS: Final = [
333333
"type",
334334
"data",
335335
"testdata.yaml",
@@ -339,9 +339,9 @@ def __init__(self, generator_config):
339339
"random_salt",
340340
"retries",
341341
]
342-
RESERVED_DIRECTORY_KEYS = ["command"]
343-
KNOWN_ROOT_KEYS = ["generators", "parallel"]
344-
DEPRECATED_ROOT_KEYS = ["gitignore_generated"]
342+
RESERVED_DIRECTORY_KEYS: Final = ["command"]
343+
KNOWN_ROOT_KEYS: Final = ["generators", "parallel"]
344+
DEPRECATED_ROOT_KEYS: Final = ["gitignore_generated"]
345345

346346

347347
# Holds all inheritable configuration options. Currently:
@@ -372,7 +372,7 @@ def parse_random_salt(p, x, path):
372372
return ""
373373
return x
374374

375-
INHERITABLE_KEYS = [
375+
INHERITABLE_KEYS: Final = [
376376
# True: use an AC submission by default when the solution: key is not present.
377377
("solution", True, parse_solution),
378378
("visualizer", None, parse_visualizer),
@@ -1413,7 +1413,7 @@ def parse_generators(generators_yaml):
14131413
return generators
14141414

14151415
# Only used at the root directory level.
1416-
ROOT_KEYS = [
1416+
ROOT_KEYS: Final = [
14171417
("generators", dict[Path, list[Path]](), parse_generators),
14181418
]
14191419

bin/interactive.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import subprocess
44
import sys
55
import threading
6-
from typing import Literal, Optional, TYPE_CHECKING
6+
from typing import Final, Literal, Optional, TYPE_CHECKING
77

88
import config
99
from util import *
@@ -13,7 +13,7 @@
1313
if TYPE_CHECKING:
1414
from run import Run
1515

16-
BUFFER_SIZE = 2**20
16+
BUFFER_SIZE: Final = 2**20
1717

1818

1919
# Return a ExecResult object amended with verdict.

bin/latex.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ def make_environment() -> dict[str, str]:
221221
Path.cwd(),
222222
Path.cwd() / "solve_stats",
223223
Path.cwd() / "solve_stats" / "activity",
224-
config.tools_root / "latex",
224+
config.TOOLS_ROOT / "latex",
225225
]
226226
texinputs = ""
227227
for p in latex_paths:
@@ -371,7 +371,7 @@ def build_problem_pdf(
371371

372372
local_data = Path(main_file)
373373
copy_and_substitute(
374-
local_data if local_data.is_file() else config.tools_root / "latex" / main_file,
374+
local_data if local_data.is_file() else config.TOOLS_ROOT / "latex" / main_file,
375375
builddir / main_file,
376376
problem_data(problem, language),
377377
)
@@ -419,7 +419,7 @@ def find_logo() -> Path:
419419
logo = Path(directory + "logo." + extension)
420420
if logo.exists():
421421
return logo
422-
return config.tools_root / "latex" / "images" / "logo-not-found.pdf"
422+
return config.TOOLS_ROOT / "latex" / "images" / "logo-not-found.pdf"
423423

424424

425425
def build_contest_pdf(
@@ -461,7 +461,7 @@ def build_contest_pdf(
461461
(
462462
local_contest_data
463463
if local_contest_data.is_file()
464-
else config.tools_root / "latex" / "contest_data.tex"
464+
else config.TOOLS_ROOT / "latex" / "contest_data.tex"
465465
),
466466
builddir / "contest_data.tex",
467467
config_data,
@@ -482,7 +482,7 @@ def build_contest_pdf(
482482
per_problem_data_tex = (
483483
local_per_problem_data
484484
if local_per_problem_data.is_file()
485-
else config.tools_root / "latex" / f"contest-{build_type.value}.tex"
485+
else config.TOOLS_ROOT / "latex" / f"contest-{build_type.value}.tex"
486486
).read_text()
487487

488488
for prob in problems:

bin/problem.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
from collections.abc import Callable
77
from pathlib import Path
8-
from typing import Any, Literal, Optional, TYPE_CHECKING
8+
from typing import Any, Final, Literal, Optional, TYPE_CHECKING
99

1010
if TYPE_CHECKING: # Prevent circular import: https://stackoverflow.com/a/39757388
1111
from program import Program
@@ -155,8 +155,8 @@ def is_legacy(self):
155155

156156
# A problem.
157157
class Problem:
158-
_SHORTNAME_REGEX_STRING = "^[a-z0-9]+$"
159-
_SHORTNAME_REGEX = re.compile(_SHORTNAME_REGEX_STRING)
158+
_SHORTNAME_REGEX_STRING: Final = "^[a-z0-9]+$"
159+
_SHORTNAME_REGEX: Final = re.compile(_SHORTNAME_REGEX_STRING)
160160

161161
def __init__(self, path: Path, tmpdir: Path, label: Optional[str] = None):
162162
# The problem name/shortname, which is the name of the directory and used as a display name.
@@ -678,7 +678,7 @@ def _validators(
678678
if cls == validate.OutputValidator and problem.settings.validation == "default":
679679
if paths:
680680
error("Validation is default but custom output validator exists (ignoring it)")
681-
paths = [config.tools_root / "support" / "default_output_validator.cpp"]
681+
paths = [config.TOOLS_ROOT / "support" / "default_output_validator.cpp"]
682682

683683
# TODO: Instead of checking file contents, maybe specify this in generators.yaml?
684684
def has_constraints_checking(f):

bin/program.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import stat
44
import subprocess
55
import threading
6-
from typing import TYPE_CHECKING
6+
from typing import Final, TYPE_CHECKING
77

88
from colorama import Fore
99

@@ -12,7 +12,7 @@
1212
if TYPE_CHECKING: # Prevent circular import: https://stackoverflow.com/a/39757388
1313
from problem import Problem
1414

15-
EXTRA_LANGUAGES = """
15+
EXTRA_LANGUAGES: Final = """
1616
checktestdata:
1717
name: 'Checktestdata'
1818
priority: 1
@@ -33,7 +33,7 @@
3333
run: '{run}'
3434
"""
3535

36-
SANITIZER_FLAGS = """
36+
SANITIZER_FLAGS: Final = """
3737
cpp:
3838
compile: -fsanitize=undefined,address
3939
"""
@@ -53,7 +53,7 @@ def languages():
5353
if Path("languages.yaml").is_file():
5454
_languages = read_yaml(Path("languages.yaml"))
5555
else:
56-
_languages = read_yaml(config.tools_root / "config/languages.yaml")
56+
_languages = read_yaml(config.TOOLS_ROOT / "config/languages.yaml")
5757

5858
# Add custom languages.
5959
extra_langs = parse_yaml(EXTRA_LANGUAGES)
@@ -289,7 +289,7 @@ def _get_language(self, bar: ProgressBar):
289289
self.tmpdir / "build" if (self.tmpdir / "build") in self.input_files else ""
290290
),
291291
"run": self.tmpdir / "run",
292-
"viva_jar": config.tools_root / "third_party/viva/viva.jar",
292+
"viva_jar": config.TOOLS_ROOT / "third_party/viva/viva.jar",
293293
}
294294

295295
return True

bin/skel.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -106,15 +106,15 @@ def new_contest():
106106
rights_owner = _ask_variable_string("rights owner", "author")
107107
title = title.replace("_", "-")
108108

109-
skeldir = config.tools_root / "skel/contest"
109+
skeldir = config.TOOLS_ROOT / "skel/contest"
110110
log(f"Copying {skeldir} to {dirname}.")
111111
copytree_and_substitute(
112112
skeldir, Path(dirname), locals(), exist_ok=False, preserve_symlinks=False
113113
)
114114

115115

116116
def get_skel_dir(target_dir):
117-
skeldir = config.tools_root / "skel/problem"
117+
skeldir = config.TOOLS_ROOT / "skel/problem"
118118
preserve_symlinks = False
119119
if (target_dir / "skel/problem").is_dir():
120120
skeldir = target_dir / "skel/problem"
@@ -316,16 +316,16 @@ def create_gitlab_jobs(contest, problems):
316316
def problem_source_dir(problem):
317317
return problem.path.resolve().relative_to(Path("..").resolve())
318318

319-
header_yml = (config.tools_root / "skel/gitlab_ci/header.yaml").read_text()
319+
header_yml = (config.TOOLS_ROOT / "skel/gitlab_ci/header.yaml").read_text()
320320
print(substitute(header_yml, locals()))
321321

322-
contest_yml = (config.tools_root / "skel/gitlab_ci/contest.yaml").read_text()
322+
contest_yml = (config.TOOLS_ROOT / "skel/gitlab_ci/contest.yaml").read_text()
323323
changes = ""
324324
for problem in problems:
325325
changes += " - " + str(problem_source_dir(problem)) + "/problem_statement/**/*\n"
326326
print(substitute(contest_yml, locals()))
327327

328-
problem_yml = (config.tools_root / "skel/gitlab_ci/problem.yaml").read_text()
328+
problem_yml = (config.TOOLS_ROOT / "skel/gitlab_ci/problem.yaml").read_text()
329329
for problem_obj in problems:
330330
changesdir = problem_source_dir(problem_obj)
331331
problem = problem_obj.name

0 commit comments

Comments
 (0)