siliconcompiler 0.32.3__py3-none-any.whl → 0.33.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- siliconcompiler/__init__.py +19 -2
- siliconcompiler/_common.py +5 -0
- siliconcompiler/_metadata.py +1 -1
- siliconcompiler/apps/sc.py +2 -2
- siliconcompiler/apps/sc_install.py +10 -3
- siliconcompiler/apps/sc_issue.py +1 -1
- siliconcompiler/apps/sc_remote.py +10 -5
- siliconcompiler/apps/sc_show.py +2 -2
- siliconcompiler/apps/utils/replay.py +5 -3
- siliconcompiler/asic.py +120 -0
- siliconcompiler/checklist.py +150 -0
- siliconcompiler/core.py +299 -299
- siliconcompiler/flowgraph.py +803 -515
- siliconcompiler/fpga.py +84 -0
- siliconcompiler/metric.py +479 -0
- siliconcompiler/optimizer/vizier.py +2 -3
- siliconcompiler/package/__init__.py +29 -6
- siliconcompiler/pdk.py +415 -0
- siliconcompiler/record.py +453 -0
- siliconcompiler/remote/client.py +15 -5
- siliconcompiler/remote/schema.py +116 -112
- siliconcompiler/remote/server.py +9 -6
- siliconcompiler/report/dashboard/cli/__init__.py +14 -721
- siliconcompiler/report/dashboard/cli/board.py +899 -0
- siliconcompiler/report/dashboard/web/__init__.py +10 -10
- siliconcompiler/report/dashboard/web/components/__init__.py +5 -4
- siliconcompiler/report/dashboard/web/components/flowgraph.py +3 -3
- siliconcompiler/report/dashboard/web/components/graph.py +6 -3
- siliconcompiler/report/dashboard/web/state.py +1 -1
- siliconcompiler/report/dashboard/web/utils/__init__.py +4 -3
- siliconcompiler/report/html_report.py +2 -3
- siliconcompiler/report/report.py +22 -11
- siliconcompiler/report/summary_image.py +1 -1
- siliconcompiler/report/summary_table.py +3 -3
- siliconcompiler/report/utils.py +21 -14
- siliconcompiler/scheduler/__init__.py +234 -1206
- siliconcompiler/scheduler/run_node.py +2 -1
- siliconcompiler/scheduler/send_messages.py +11 -5
- siliconcompiler/scheduler/slurm.py +11 -44
- siliconcompiler/scheduler/taskscheduler.py +320 -0
- siliconcompiler/schema/__init__.py +19 -2
- siliconcompiler/schema/baseschema.py +493 -0
- siliconcompiler/schema/cmdlineschema.py +250 -0
- siliconcompiler/{sphinx_ext → schema/docs}/__init__.py +3 -1
- siliconcompiler/{sphinx_ext → schema/docs}/dynamicgen.py +63 -81
- siliconcompiler/{sphinx_ext → schema/docs}/schemagen.py +73 -85
- siliconcompiler/{sphinx_ext → schema/docs}/utils.py +12 -13
- siliconcompiler/schema/editableschema.py +136 -0
- siliconcompiler/schema/journalingschema.py +238 -0
- siliconcompiler/schema/namedschema.py +41 -0
- siliconcompiler/schema/packageschema.py +101 -0
- siliconcompiler/schema/parameter.py +791 -0
- siliconcompiler/schema/parametertype.py +323 -0
- siliconcompiler/schema/parametervalue.py +736 -0
- siliconcompiler/schema/safeschema.py +37 -0
- siliconcompiler/schema/schema_cfg.py +109 -1789
- siliconcompiler/schema/utils.py +5 -68
- siliconcompiler/schema_obj.py +119 -0
- siliconcompiler/tool.py +1416 -0
- siliconcompiler/tools/_common/__init__.py +6 -10
- siliconcompiler/tools/_common/asic.py +5 -5
- siliconcompiler/tools/_common/sdc/sc_constraints.sdc +1 -1
- siliconcompiler/tools/bluespec/convert.py +9 -8
- siliconcompiler/tools/builtin/_common.py +9 -2
- siliconcompiler/tools/builtin/concatenate.py +7 -3
- siliconcompiler/tools/builtin/minimum.py +7 -2
- siliconcompiler/tools/builtin/mux.py +8 -2
- siliconcompiler/tools/builtin/nop.py +7 -2
- siliconcompiler/tools/builtin/verify.py +11 -5
- siliconcompiler/tools/chisel/convert.py +10 -10
- siliconcompiler/tools/genfasm/bitstream.py +3 -3
- siliconcompiler/tools/ghdl/convert.py +1 -1
- siliconcompiler/tools/icarus/compile.py +4 -4
- siliconcompiler/tools/icepack/bitstream.py +6 -1
- siliconcompiler/tools/klayout/convert_drc_db.py +5 -0
- siliconcompiler/tools/klayout/drc.py +2 -2
- siliconcompiler/tools/klayout/klayout_export.py +0 -1
- siliconcompiler/tools/klayout/klayout_show.py +6 -6
- siliconcompiler/tools/klayout/klayout_utils.py +15 -22
- siliconcompiler/tools/netgen/count_lvs.py +2 -2
- siliconcompiler/tools/netgen/lvs.py +1 -1
- siliconcompiler/tools/nextpnr/apr.py +6 -1
- siliconcompiler/tools/nextpnr/nextpnr.py +4 -4
- siliconcompiler/tools/openroad/_apr.py +15 -2
- siliconcompiler/tools/openroad/rdlroute.py +3 -3
- siliconcompiler/tools/openroad/scripts/apr/postamble.tcl +1 -1
- siliconcompiler/tools/openroad/scripts/apr/preamble.tcl +5 -5
- siliconcompiler/tools/openroad/scripts/apr/sc_antenna_repair.tcl +2 -2
- siliconcompiler/tools/openroad/scripts/apr/sc_clock_tree_synthesis.tcl +2 -2
- siliconcompiler/tools/openroad/scripts/apr/sc_detailed_placement.tcl +2 -2
- siliconcompiler/tools/openroad/scripts/apr/sc_detailed_route.tcl +2 -2
- siliconcompiler/tools/openroad/scripts/apr/sc_endcap_tapcell_insertion.tcl +2 -2
- siliconcompiler/tools/openroad/scripts/apr/sc_fillercell_insertion.tcl +2 -2
- siliconcompiler/tools/openroad/scripts/apr/sc_fillmetal_insertion.tcl +2 -2
- siliconcompiler/tools/openroad/scripts/apr/sc_global_placement.tcl +2 -2
- siliconcompiler/tools/openroad/scripts/apr/sc_global_route.tcl +2 -2
- siliconcompiler/tools/openroad/scripts/apr/sc_init_floorplan.tcl +3 -9
- siliconcompiler/tools/openroad/scripts/apr/sc_macro_placement.tcl +3 -3
- siliconcompiler/tools/openroad/scripts/apr/sc_metrics.tcl +2 -2
- siliconcompiler/tools/openroad/scripts/apr/sc_pin_placement.tcl +2 -2
- siliconcompiler/tools/openroad/scripts/apr/sc_power_grid.tcl +2 -2
- siliconcompiler/tools/openroad/scripts/apr/sc_repair_design.tcl +2 -2
- siliconcompiler/tools/openroad/scripts/apr/sc_repair_timing.tcl +2 -2
- siliconcompiler/tools/openroad/scripts/apr/sc_write_data.tcl +2 -2
- siliconcompiler/tools/openroad/scripts/common/procs.tcl +75 -1
- siliconcompiler/tools/openroad/scripts/common/read_input_files.tcl +1 -7
- siliconcompiler/tools/openroad/scripts/common/screenshot.tcl +2 -2
- siliconcompiler/tools/openroad/scripts/common/write_images.tcl +28 -3
- siliconcompiler/tools/openroad/scripts/sc_rcx.tcl +1 -1
- siliconcompiler/tools/openroad/scripts/sc_rdlroute.tcl +3 -3
- siliconcompiler/tools/openroad/scripts/sc_show.tcl +6 -6
- siliconcompiler/tools/opensta/scripts/sc_timing.tcl +10 -0
- siliconcompiler/tools/opensta/timing.py +11 -0
- siliconcompiler/tools/slang/__init__.py +13 -13
- siliconcompiler/tools/slang/elaborate.py +6 -6
- siliconcompiler/tools/slang/lint.py +1 -3
- siliconcompiler/tools/surelog/parse.py +4 -4
- siliconcompiler/tools/sv2v/convert.py +20 -3
- siliconcompiler/tools/verilator/compile.py +2 -2
- siliconcompiler/tools/verilator/verilator.py +3 -3
- siliconcompiler/tools/vpr/_xml_constraint.py +8 -8
- siliconcompiler/tools/vpr/place.py +1 -1
- siliconcompiler/tools/vpr/route.py +4 -4
- siliconcompiler/tools/vpr/screenshot.py +1 -1
- siliconcompiler/tools/vpr/show.py +5 -5
- siliconcompiler/tools/vpr/vpr.py +24 -24
- siliconcompiler/tools/xdm/convert.py +2 -2
- siliconcompiler/tools/xyce/simulate.py +1 -1
- siliconcompiler/tools/yosys/prepareLib.py +2 -2
- siliconcompiler/tools/yosys/sc_synth_asic.tcl +111 -63
- siliconcompiler/tools/yosys/screenshot.py +1 -1
- siliconcompiler/tools/yosys/syn_asic.py +7 -7
- siliconcompiler/toolscripts/_tools.json +12 -10
- siliconcompiler/toolscripts/rhel8/install-chisel.sh +9 -2
- siliconcompiler/toolscripts/rhel8/install-icarus.sh +10 -3
- siliconcompiler/toolscripts/rhel8/install-klayout.sh +8 -1
- siliconcompiler/toolscripts/rhel8/install-magic.sh +9 -2
- siliconcompiler/toolscripts/rhel8/install-montage.sh +1 -1
- siliconcompiler/toolscripts/rhel8/install-netgen.sh +9 -2
- siliconcompiler/toolscripts/rhel8/install-slang.sh +11 -4
- siliconcompiler/toolscripts/rhel8/install-surelog.sh +9 -2
- siliconcompiler/toolscripts/rhel8/install-sv2v.sh +11 -4
- siliconcompiler/toolscripts/rhel8/install-verible.sh +11 -3
- siliconcompiler/toolscripts/rhel8/install-verilator.sh +10 -3
- siliconcompiler/toolscripts/rhel8/install-xyce.sh +15 -10
- siliconcompiler/toolscripts/rhel9/install-chisel.sh +9 -2
- siliconcompiler/toolscripts/rhel9/install-ghdl.sh +9 -2
- siliconcompiler/toolscripts/rhel9/install-gtkwave.sh +10 -3
- siliconcompiler/toolscripts/rhel9/install-icarus.sh +10 -3
- siliconcompiler/toolscripts/rhel9/install-klayout.sh +8 -1
- siliconcompiler/toolscripts/rhel9/install-magic.sh +9 -2
- siliconcompiler/toolscripts/rhel9/install-montage.sh +1 -1
- siliconcompiler/toolscripts/rhel9/install-netgen.sh +9 -2
- siliconcompiler/toolscripts/rhel9/install-openroad.sh +16 -3
- siliconcompiler/toolscripts/rhel9/install-opensta.sh +17 -5
- siliconcompiler/toolscripts/rhel9/install-slang.sh +11 -4
- siliconcompiler/toolscripts/rhel9/install-surelog.sh +9 -2
- siliconcompiler/toolscripts/rhel9/install-sv2v.sh +11 -4
- siliconcompiler/toolscripts/rhel9/install-verible.sh +11 -3
- siliconcompiler/toolscripts/rhel9/install-verilator.sh +10 -3
- siliconcompiler/toolscripts/rhel9/install-vpr.sh +9 -2
- siliconcompiler/toolscripts/rhel9/install-xdm.sh +10 -2
- siliconcompiler/toolscripts/rhel9/install-xyce.sh +15 -10
- siliconcompiler/toolscripts/rhel9/install-yosys-moosic.sh +9 -2
- siliconcompiler/toolscripts/rhel9/install-yosys-parmys.sh +10 -3
- siliconcompiler/toolscripts/rhel9/install-yosys-slang.sh +10 -2
- siliconcompiler/toolscripts/rhel9/install-yosys.sh +9 -2
- siliconcompiler/toolscripts/ubuntu20/install-bambu.sh +10 -2
- siliconcompiler/toolscripts/ubuntu20/install-bluespec.sh +10 -3
- siliconcompiler/toolscripts/ubuntu20/install-chisel.sh +9 -2
- siliconcompiler/toolscripts/ubuntu20/install-ghdl.sh +9 -2
- siliconcompiler/toolscripts/ubuntu20/install-gtkwave.sh +9 -2
- siliconcompiler/toolscripts/ubuntu20/install-icarus.sh +9 -2
- siliconcompiler/toolscripts/ubuntu20/install-icepack.sh +9 -2
- siliconcompiler/toolscripts/ubuntu20/install-klayout.sh +8 -1
- siliconcompiler/toolscripts/ubuntu20/install-magic.sh +9 -2
- siliconcompiler/toolscripts/ubuntu20/install-montage.sh +1 -1
- siliconcompiler/toolscripts/ubuntu20/install-netgen.sh +9 -2
- siliconcompiler/toolscripts/ubuntu20/install-nextpnr.sh +9 -2
- siliconcompiler/toolscripts/ubuntu20/install-openroad.sh +16 -3
- siliconcompiler/toolscripts/ubuntu20/install-opensta.sh +16 -5
- siliconcompiler/toolscripts/ubuntu20/install-slang.sh +11 -4
- siliconcompiler/toolscripts/ubuntu20/install-slurm.sh +9 -2
- siliconcompiler/toolscripts/ubuntu20/install-surelog.sh +10 -2
- siliconcompiler/toolscripts/ubuntu20/install-sv2v.sh +11 -4
- siliconcompiler/toolscripts/ubuntu20/install-verible.sh +11 -3
- siliconcompiler/toolscripts/ubuntu20/install-verilator.sh +9 -2
- siliconcompiler/toolscripts/ubuntu20/install-xdm.sh +10 -2
- siliconcompiler/toolscripts/ubuntu20/install-xyce.sh +13 -8
- siliconcompiler/toolscripts/ubuntu20/install-yosys-moosic.sh +9 -2
- siliconcompiler/toolscripts/ubuntu20/install-yosys.sh +9 -2
- siliconcompiler/toolscripts/ubuntu22/install-bambu.sh +10 -2
- siliconcompiler/toolscripts/ubuntu22/install-bluespec.sh +10 -3
- siliconcompiler/toolscripts/ubuntu22/install-chisel.sh +9 -2
- siliconcompiler/toolscripts/ubuntu22/install-ghdl.sh +9 -2
- siliconcompiler/toolscripts/ubuntu22/install-gtkwave.sh +9 -2
- siliconcompiler/toolscripts/ubuntu22/install-icarus.sh +9 -2
- siliconcompiler/toolscripts/ubuntu22/install-icepack.sh +9 -2
- siliconcompiler/toolscripts/ubuntu22/install-klayout.sh +8 -1
- siliconcompiler/toolscripts/ubuntu22/install-magic.sh +9 -2
- siliconcompiler/toolscripts/ubuntu22/install-montage.sh +1 -1
- siliconcompiler/toolscripts/ubuntu22/install-netgen.sh +9 -2
- siliconcompiler/toolscripts/ubuntu22/install-nextpnr.sh +9 -2
- siliconcompiler/toolscripts/ubuntu22/install-openroad.sh +16 -3
- siliconcompiler/toolscripts/ubuntu22/install-opensta.sh +17 -5
- siliconcompiler/toolscripts/ubuntu22/install-slang.sh +11 -4
- siliconcompiler/toolscripts/ubuntu22/install-slurm.sh +9 -2
- siliconcompiler/toolscripts/ubuntu22/install-surelog.sh +10 -2
- siliconcompiler/toolscripts/ubuntu22/install-sv2v.sh +11 -4
- siliconcompiler/toolscripts/ubuntu22/install-verible.sh +11 -3
- siliconcompiler/toolscripts/ubuntu22/install-verilator.sh +9 -2
- siliconcompiler/toolscripts/ubuntu22/install-vpr.sh +9 -4
- siliconcompiler/toolscripts/ubuntu22/install-xdm.sh +10 -2
- siliconcompiler/toolscripts/ubuntu22/install-xyce.sh +13 -8
- siliconcompiler/toolscripts/ubuntu22/install-yosys-moosic.sh +9 -2
- siliconcompiler/toolscripts/ubuntu22/install-yosys-parmys.sh +10 -3
- siliconcompiler/toolscripts/ubuntu22/install-yosys-slang.sh +10 -2
- siliconcompiler/toolscripts/ubuntu22/install-yosys.sh +9 -2
- siliconcompiler/toolscripts/ubuntu24/install-bambu.sh +12 -4
- siliconcompiler/toolscripts/ubuntu24/install-bluespec.sh +10 -3
- siliconcompiler/toolscripts/ubuntu24/install-chisel.sh +9 -2
- siliconcompiler/toolscripts/ubuntu24/install-ghdl.sh +9 -2
- siliconcompiler/toolscripts/ubuntu24/install-gtkwave.sh +9 -2
- siliconcompiler/toolscripts/ubuntu24/install-icarus.sh +9 -2
- siliconcompiler/toolscripts/ubuntu24/install-icepack.sh +9 -2
- siliconcompiler/toolscripts/ubuntu24/install-klayout.sh +8 -1
- siliconcompiler/toolscripts/ubuntu24/install-magic.sh +9 -2
- siliconcompiler/toolscripts/ubuntu24/install-montage.sh +1 -1
- siliconcompiler/toolscripts/ubuntu24/install-netgen.sh +9 -2
- siliconcompiler/toolscripts/ubuntu24/install-nextpnr.sh +9 -2
- siliconcompiler/toolscripts/ubuntu24/install-openroad.sh +16 -3
- siliconcompiler/toolscripts/ubuntu24/install-opensta.sh +17 -5
- siliconcompiler/toolscripts/ubuntu24/install-slang.sh +11 -4
- siliconcompiler/toolscripts/ubuntu24/install-slurm.sh +9 -2
- siliconcompiler/toolscripts/ubuntu24/install-surelog.sh +10 -2
- siliconcompiler/toolscripts/ubuntu24/install-sv2v.sh +11 -4
- siliconcompiler/toolscripts/ubuntu24/install-verible.sh +11 -3
- siliconcompiler/toolscripts/ubuntu24/install-verilator.sh +9 -2
- siliconcompiler/toolscripts/ubuntu24/install-vpr.sh +9 -4
- siliconcompiler/toolscripts/ubuntu24/install-xdm.sh +10 -2
- siliconcompiler/toolscripts/ubuntu24/install-xyce.sh +13 -8
- siliconcompiler/toolscripts/ubuntu24/install-yosys-moosic.sh +9 -2
- siliconcompiler/toolscripts/ubuntu24/install-yosys-parmys.sh +10 -3
- siliconcompiler/toolscripts/ubuntu24/install-yosys-slang.sh +10 -2
- siliconcompiler/toolscripts/ubuntu24/install-yosys.sh +9 -2
- siliconcompiler/utils/__init__.py +19 -112
- siliconcompiler/utils/flowgraph.py +244 -0
- siliconcompiler/{issue.py → utils/issue.py} +18 -25
- siliconcompiler/utils/logging.py +3 -4
- {siliconcompiler-0.32.3.dist-info → siliconcompiler-0.33.1.dist-info}/METADATA +9 -8
- siliconcompiler-0.33.1.dist-info/RECORD +488 -0
- {siliconcompiler-0.32.3.dist-info → siliconcompiler-0.33.1.dist-info}/WHEEL +1 -1
- {siliconcompiler-0.32.3.dist-info → siliconcompiler-0.33.1.dist-info}/entry_points.txt +8 -8
- siliconcompiler/schema/schema_obj.py +0 -1936
- siliconcompiler/toolscripts/ubuntu20/install-vpr.sh +0 -29
- siliconcompiler/toolscripts/ubuntu20/install-yosys-parmys.sh +0 -61
- siliconcompiler-0.32.3.dist-info/RECORD +0 -470
- /siliconcompiler/{templates → data/templates}/__init__.py +0 -0
- /siliconcompiler/{templates → data/templates}/email/__init__.py +0 -0
- /siliconcompiler/{templates → data/templates}/email/general.j2 +0 -0
- /siliconcompiler/{templates → data/templates}/email/summary.j2 +0 -0
- /siliconcompiler/{templates → data/templates}/issue/README.txt +0 -0
- /siliconcompiler/{templates → data/templates}/issue/__init__.py +0 -0
- /siliconcompiler/{templates → data/templates}/issue/run.sh +0 -0
- /siliconcompiler/{templates → data/templates}/replay/replay.py.j2 +0 -0
- /siliconcompiler/{templates → data/templates}/replay/replay.sh.j2 +0 -0
- /siliconcompiler/{templates → data/templates}/replay/requirements.txt +0 -0
- /siliconcompiler/{templates → data/templates}/replay/setup.sh +0 -0
- /siliconcompiler/{templates → data/templates}/report/__init__.py +0 -0
- /siliconcompiler/{templates → data/templates}/report/bootstrap.min.css +0 -0
- /siliconcompiler/{templates → data/templates}/report/bootstrap.min.js +0 -0
- /siliconcompiler/{templates → data/templates}/report/bootstrap_LICENSE.md +0 -0
- /siliconcompiler/{templates → data/templates}/report/sc_report.j2 +0 -0
- /siliconcompiler/{templates → data/templates}/slurm/__init__.py +0 -0
- /siliconcompiler/{templates → data/templates}/slurm/run.sh +0 -0
- /siliconcompiler/{templates → data/templates}/tcl/__init__.py +0 -0
- /siliconcompiler/{templates → data/templates}/tcl/manifest.tcl.j2 +0 -0
- /siliconcompiler/{units.py → utils/units.py} +0 -0
- {siliconcompiler-0.32.3.dist-info → siliconcompiler-0.33.1.dist-info}/licenses/LICENSE +0 -0
- {siliconcompiler-0.32.3.dist-info → siliconcompiler-0.33.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,791 @@
|
|
|
1
|
+
# Copyright 2025 Silicon Compiler Authors. All Rights Reserved.
|
|
2
|
+
|
|
3
|
+
# NOTE: this file cannot rely on any third-party dependencies, including other
|
|
4
|
+
# SC dependencies outside of its directory, since it may be used by tool drivers
|
|
5
|
+
# that have isolated Python environments.
|
|
6
|
+
|
|
7
|
+
import argparse
|
|
8
|
+
import copy
|
|
9
|
+
import re
|
|
10
|
+
import shlex
|
|
11
|
+
|
|
12
|
+
from enum import Enum
|
|
13
|
+
|
|
14
|
+
from .parametervalue import NodeValue, DirectoryNodeValue, FileNodeValue, NodeListValue
|
|
15
|
+
from .parametertype import NodeType, NodeEnumType
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class Scope(Enum):
|
|
19
|
+
'''
|
|
20
|
+
Enum for scope Schema parameters
|
|
21
|
+
'''
|
|
22
|
+
GLOBAL = 'global'
|
|
23
|
+
JOB = 'job'
|
|
24
|
+
SCRATCH = 'scratch'
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class PerNode(Enum):
|
|
28
|
+
'''
|
|
29
|
+
Enum for pernode Schema parameters
|
|
30
|
+
'''
|
|
31
|
+
NEVER = 'never'
|
|
32
|
+
OPTIONAL = 'optional'
|
|
33
|
+
REQUIRED = 'required'
|
|
34
|
+
|
|
35
|
+
def is_never(self):
|
|
36
|
+
'''
|
|
37
|
+
Returns true is this is 'never'
|
|
38
|
+
'''
|
|
39
|
+
return self == PerNode.NEVER
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class Parameter:
|
|
43
|
+
'''
|
|
44
|
+
Leaf nodes in the schema. This holds all the information for a given keypath.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
type (str): type for the parameter, see
|
|
48
|
+
:class:`.parametertype.NodeType` for supported types.
|
|
49
|
+
require (bool): require field
|
|
50
|
+
defvalue (any): defvalue field
|
|
51
|
+
scope (:class:`.Scope`): scope field
|
|
52
|
+
copy (bool): copy field
|
|
53
|
+
lock (bool): bool field
|
|
54
|
+
hashalgo (str): hashalgo field
|
|
55
|
+
notes (str): notes field
|
|
56
|
+
unit (str): unit field
|
|
57
|
+
shorthelp (str): shorthelp field
|
|
58
|
+
switch (list of str): switch field
|
|
59
|
+
example (list of str): example field
|
|
60
|
+
help (str): help field
|
|
61
|
+
pernode (:class:`.PerNode`): pernode field
|
|
62
|
+
'''
|
|
63
|
+
|
|
64
|
+
GLOBAL_KEY = 'global'
|
|
65
|
+
|
|
66
|
+
def __init__(self,
|
|
67
|
+
type,
|
|
68
|
+
require=False,
|
|
69
|
+
defvalue=None,
|
|
70
|
+
scope=Scope.JOB,
|
|
71
|
+
copy=False,
|
|
72
|
+
lock=False,
|
|
73
|
+
hashalgo='sha256',
|
|
74
|
+
notes=None,
|
|
75
|
+
unit=None,
|
|
76
|
+
shorthelp=None,
|
|
77
|
+
switch=None,
|
|
78
|
+
example=None,
|
|
79
|
+
help=None,
|
|
80
|
+
pernode=PerNode.NEVER):
|
|
81
|
+
|
|
82
|
+
self.__type = NodeType.parse(type)
|
|
83
|
+
self.__scope = Scope(scope)
|
|
84
|
+
self.__lock = lock
|
|
85
|
+
self.__require = require
|
|
86
|
+
|
|
87
|
+
if switch is None:
|
|
88
|
+
switch = []
|
|
89
|
+
elif isinstance(switch, str):
|
|
90
|
+
switch = [switch]
|
|
91
|
+
self.__switch = switch
|
|
92
|
+
|
|
93
|
+
self.__shorthelp = shorthelp
|
|
94
|
+
|
|
95
|
+
if example is None:
|
|
96
|
+
example = []
|
|
97
|
+
elif isinstance(example, str):
|
|
98
|
+
example = [example]
|
|
99
|
+
self.__example = example
|
|
100
|
+
|
|
101
|
+
self.__help = help
|
|
102
|
+
|
|
103
|
+
self.__notes = notes
|
|
104
|
+
|
|
105
|
+
if self.__type == 'bool':
|
|
106
|
+
if defvalue is None:
|
|
107
|
+
defvalue = False
|
|
108
|
+
|
|
109
|
+
self.__pernode = PerNode(pernode)
|
|
110
|
+
|
|
111
|
+
self.__setdefvalue(defvalue)
|
|
112
|
+
|
|
113
|
+
self.__node = {}
|
|
114
|
+
|
|
115
|
+
self.__unit = None
|
|
116
|
+
if unit is not None and \
|
|
117
|
+
(NodeType.contains(self.__type, 'int') or NodeType.contains(self.__type, 'float')):
|
|
118
|
+
self.__unit = str(unit)
|
|
119
|
+
|
|
120
|
+
self.__hashalgo = None
|
|
121
|
+
self.__copy = None
|
|
122
|
+
if NodeType.contains(self.__type, 'dir') or NodeType.contains(self.__type, 'file'):
|
|
123
|
+
self.__hashalgo = str(hashalgo)
|
|
124
|
+
self.__copy = bool(copy)
|
|
125
|
+
|
|
126
|
+
def __setdefvalue(self, defvalue):
|
|
127
|
+
if NodeType.contains(self.__type, 'file'):
|
|
128
|
+
base = FileNodeValue(defvalue)
|
|
129
|
+
if isinstance(self.__type, list):
|
|
130
|
+
self.__defvalue = NodeListValue(base)
|
|
131
|
+
else:
|
|
132
|
+
self.__defvalue = base
|
|
133
|
+
elif NodeType.contains(self.__type, 'dir'):
|
|
134
|
+
base = DirectoryNodeValue(defvalue)
|
|
135
|
+
if isinstance(self.__type, list):
|
|
136
|
+
self.__defvalue = NodeListValue(base)
|
|
137
|
+
else:
|
|
138
|
+
self.__defvalue = base
|
|
139
|
+
else:
|
|
140
|
+
if isinstance(self.__type, list):
|
|
141
|
+
self.__defvalue = NodeListValue(NodeValue(self.__type[0]))
|
|
142
|
+
if defvalue:
|
|
143
|
+
self.__defvalue.set(defvalue)
|
|
144
|
+
else:
|
|
145
|
+
self.__defvalue = NodeValue(self.__type, value=defvalue)
|
|
146
|
+
|
|
147
|
+
def __str__(self):
|
|
148
|
+
return str(self.getvalues())
|
|
149
|
+
|
|
150
|
+
def get(self, field='value', step=None, index=None):
|
|
151
|
+
"""
|
|
152
|
+
Returns the value in a parameter field.
|
|
153
|
+
|
|
154
|
+
Args:
|
|
155
|
+
field (str): Parameter field to fetch.
|
|
156
|
+
step (str): Step name to access for parameters that may be specified
|
|
157
|
+
on a per-node basis.
|
|
158
|
+
index (str): Index name to access for parameters that may be specified
|
|
159
|
+
on a per-node basis.
|
|
160
|
+
|
|
161
|
+
Returns:
|
|
162
|
+
Field value for the parameter.
|
|
163
|
+
|
|
164
|
+
Examples:
|
|
165
|
+
>>> value = param.get()
|
|
166
|
+
Returns the value stored in the parameter.
|
|
167
|
+
"""
|
|
168
|
+
|
|
169
|
+
self.__assert_step_index(field, step, index)
|
|
170
|
+
|
|
171
|
+
if field in self.__defvalue.fields:
|
|
172
|
+
if isinstance(index, int):
|
|
173
|
+
index = str(index)
|
|
174
|
+
|
|
175
|
+
try:
|
|
176
|
+
return self.__node[step][index].get(field=field)
|
|
177
|
+
except KeyError:
|
|
178
|
+
if self.__pernode == PerNode.REQUIRED:
|
|
179
|
+
return self.__defvalue.get(field=field)
|
|
180
|
+
|
|
181
|
+
try:
|
|
182
|
+
return self.__node[step][Parameter.GLOBAL_KEY].get(field=field)
|
|
183
|
+
except KeyError:
|
|
184
|
+
pass
|
|
185
|
+
|
|
186
|
+
try:
|
|
187
|
+
return self.__node[Parameter.GLOBAL_KEY][Parameter.GLOBAL_KEY].get(field=field)
|
|
188
|
+
except KeyError:
|
|
189
|
+
return self.__defvalue.get(field=field)
|
|
190
|
+
elif field == "type":
|
|
191
|
+
return NodeType.encode(self.__type)
|
|
192
|
+
elif field == "scope":
|
|
193
|
+
return self.__scope
|
|
194
|
+
elif field == "lock":
|
|
195
|
+
return self.__lock
|
|
196
|
+
elif field == "switch":
|
|
197
|
+
return copy.deepcopy(self.__switch)
|
|
198
|
+
elif field == "shorthelp":
|
|
199
|
+
return self.__shorthelp
|
|
200
|
+
elif field == "example":
|
|
201
|
+
return copy.deepcopy(self.__example)
|
|
202
|
+
elif field == "help":
|
|
203
|
+
return self.__help
|
|
204
|
+
elif field == "notes":
|
|
205
|
+
return self.__notes
|
|
206
|
+
elif field == "pernode":
|
|
207
|
+
return self.__pernode
|
|
208
|
+
elif field == "unit":
|
|
209
|
+
return self.__unit
|
|
210
|
+
elif field == "hashalgo":
|
|
211
|
+
return self.__hashalgo
|
|
212
|
+
elif field == "copy":
|
|
213
|
+
return self.__copy
|
|
214
|
+
elif field == "require":
|
|
215
|
+
return self.__require
|
|
216
|
+
|
|
217
|
+
raise ValueError(f'"{field}" is not a valid field')
|
|
218
|
+
|
|
219
|
+
def __assert_step_index(self, field, step, index):
|
|
220
|
+
if field not in self.__defvalue.fields:
|
|
221
|
+
if step is not None or index is not None:
|
|
222
|
+
raise KeyError(
|
|
223
|
+
'step and index are only valid for'
|
|
224
|
+
f': {", ".join([field for field in self.__defvalue.fields if field])}')
|
|
225
|
+
return
|
|
226
|
+
|
|
227
|
+
if self.__pernode == PerNode.NEVER and (step is not None or index is not None):
|
|
228
|
+
raise KeyError('use of step and index are not valid')
|
|
229
|
+
|
|
230
|
+
if self.__pernode == PerNode.REQUIRED and (step is None or index is None):
|
|
231
|
+
raise KeyError('step and index are required')
|
|
232
|
+
|
|
233
|
+
if step is None and index is not None:
|
|
234
|
+
raise KeyError('step is required if index is provided')
|
|
235
|
+
|
|
236
|
+
# Step and index for default should be accessed set_/get_default
|
|
237
|
+
if step == 'default':
|
|
238
|
+
raise KeyError('illegal step name: default is reserved')
|
|
239
|
+
|
|
240
|
+
if index == 'default':
|
|
241
|
+
raise KeyError('illegal index name: default is reserved')
|
|
242
|
+
|
|
243
|
+
def set(self, value, field='value', step=None, index=None, clobber=True):
|
|
244
|
+
'''
|
|
245
|
+
Sets a parameter field.
|
|
246
|
+
|
|
247
|
+
Args:
|
|
248
|
+
value (any): Value to set.
|
|
249
|
+
field (str): Parameter field to set.
|
|
250
|
+
clobber (bool): Existing value is overwritten if True.
|
|
251
|
+
step (str): Step name to set for parameters that may be specified
|
|
252
|
+
on a per-node basis.
|
|
253
|
+
index (str): Index name to set for parameters that may be specified
|
|
254
|
+
on a per-node basis.
|
|
255
|
+
|
|
256
|
+
Examples:
|
|
257
|
+
>>> param.set('top')
|
|
258
|
+
Sets the value to 'top'
|
|
259
|
+
'''
|
|
260
|
+
|
|
261
|
+
if field != "lock":
|
|
262
|
+
if self.__lock:
|
|
263
|
+
return False
|
|
264
|
+
|
|
265
|
+
if self.is_set(step, index) and not clobber:
|
|
266
|
+
return False
|
|
267
|
+
|
|
268
|
+
self.__assert_step_index(field, step, index)
|
|
269
|
+
|
|
270
|
+
if field in self.__defvalue.fields:
|
|
271
|
+
if isinstance(index, int):
|
|
272
|
+
index = str(index)
|
|
273
|
+
|
|
274
|
+
step = step if step is not None else Parameter.GLOBAL_KEY
|
|
275
|
+
index = index if index is not None else Parameter.GLOBAL_KEY
|
|
276
|
+
|
|
277
|
+
if step not in self.__node:
|
|
278
|
+
self.__node[step] = {}
|
|
279
|
+
if index not in self.__node[step]:
|
|
280
|
+
self.__node[step][index] = self.__defvalue.copy()
|
|
281
|
+
|
|
282
|
+
return self.__node[step][index].set(value, field=field)
|
|
283
|
+
elif field == "type":
|
|
284
|
+
self.__type = NodeType.normalize(value, "str")
|
|
285
|
+
elif field == "scope":
|
|
286
|
+
if isinstance(value, Scope):
|
|
287
|
+
self.__scope = value
|
|
288
|
+
else:
|
|
289
|
+
self.__scope = Scope(NodeType.normalize(value,
|
|
290
|
+
NodeEnumType(*[v.value for v in Scope])))
|
|
291
|
+
elif field == "lock":
|
|
292
|
+
self.__lock = NodeType.normalize(value, "bool")
|
|
293
|
+
elif field == "switch":
|
|
294
|
+
self.__switch = NodeType.normalize(value, ["str"])
|
|
295
|
+
elif field == "shorthelp":
|
|
296
|
+
self.__shorthelp = NodeType.normalize(value, "str")
|
|
297
|
+
elif field == "example":
|
|
298
|
+
self.__example = NodeType.normalize(value, ["str"])
|
|
299
|
+
elif field == "help":
|
|
300
|
+
self.__help = NodeType.normalize(value, "str")
|
|
301
|
+
elif field == "notes":
|
|
302
|
+
self.__notes = NodeType.normalize(value, "str")
|
|
303
|
+
elif field == "pernode":
|
|
304
|
+
if isinstance(value, PerNode):
|
|
305
|
+
self.__pernode = value
|
|
306
|
+
else:
|
|
307
|
+
self.__pernode = PerNode(NodeType.normalize(value,
|
|
308
|
+
NodeEnumType(
|
|
309
|
+
*[v.value for v in PerNode])))
|
|
310
|
+
elif field == "unit":
|
|
311
|
+
self.__unit = NodeType.normalize(value, "str")
|
|
312
|
+
elif field == "hashalgo":
|
|
313
|
+
self.__hashalgo = NodeType.normalize(value, "str")
|
|
314
|
+
elif field == "copy":
|
|
315
|
+
self.__copy = NodeType.normalize(value, "bool")
|
|
316
|
+
elif field == "require":
|
|
317
|
+
self.__require = NodeType.normalize(value, "bool")
|
|
318
|
+
else:
|
|
319
|
+
raise ValueError(f'"{field}" is not a valid field')
|
|
320
|
+
|
|
321
|
+
return True
|
|
322
|
+
|
|
323
|
+
def add(self, value, field='value', step=None, index=None):
|
|
324
|
+
'''
|
|
325
|
+
Adds item(s) to a list.
|
|
326
|
+
|
|
327
|
+
Args:
|
|
328
|
+
value (any): Value to add.
|
|
329
|
+
field (str): Parameter field to modify.
|
|
330
|
+
step (str): Step name to modify for parameters that may be specified
|
|
331
|
+
on a per-node basis.
|
|
332
|
+
index (str): Index name to modify for parameters that may be specified
|
|
333
|
+
on a per-node basis.
|
|
334
|
+
|
|
335
|
+
Examples:
|
|
336
|
+
>>> param.add('hello.v')
|
|
337
|
+
Adds the file 'hello.v' the parameter.
|
|
338
|
+
'''
|
|
339
|
+
|
|
340
|
+
if self.__lock:
|
|
341
|
+
return False
|
|
342
|
+
|
|
343
|
+
self.__assert_step_index(field, step, index)
|
|
344
|
+
|
|
345
|
+
if field in self.__defvalue.fields:
|
|
346
|
+
if not self.is_list() and field == 'value':
|
|
347
|
+
raise ValueError("add can only be used on lists")
|
|
348
|
+
|
|
349
|
+
if isinstance(index, int):
|
|
350
|
+
index = str(index)
|
|
351
|
+
|
|
352
|
+
step = step if step is not None else Parameter.GLOBAL_KEY
|
|
353
|
+
index = index if index is not None else Parameter.GLOBAL_KEY
|
|
354
|
+
|
|
355
|
+
if step not in self.__node:
|
|
356
|
+
self.__node[step] = {}
|
|
357
|
+
if index not in self.__node[step]:
|
|
358
|
+
self.__node[step][index] = self.__defvalue.copy()
|
|
359
|
+
|
|
360
|
+
return self.__node[step][index].add(value, field=field)
|
|
361
|
+
elif field == "switch":
|
|
362
|
+
self.__switch.extend(NodeType.normalize(value, ["str"]))
|
|
363
|
+
elif field == "example":
|
|
364
|
+
self.__example.extend(NodeType.normalize(value, ["str"]))
|
|
365
|
+
else:
|
|
366
|
+
raise ValueError(f'"{field}" is not a valid field')
|
|
367
|
+
|
|
368
|
+
return True
|
|
369
|
+
|
|
370
|
+
def unset(self, step=None, index=None):
|
|
371
|
+
'''
|
|
372
|
+
Unsets a schema parameter.
|
|
373
|
+
|
|
374
|
+
This method effectively undoes any previous calls to :meth:`set()` made to
|
|
375
|
+
the given keypath and step/index. For parameters with required or no
|
|
376
|
+
per-node values, unsetting a parameter always causes it to revert to its
|
|
377
|
+
default value, and future calls to :meth:`set()` with ``clobber=False`` will
|
|
378
|
+
once again be able to modify the value.
|
|
379
|
+
|
|
380
|
+
If you unset a particular step/index for a parameter with optional
|
|
381
|
+
per-node values, note that the newly returned value will be the global
|
|
382
|
+
value if it has been set. To completely return the parameter to its
|
|
383
|
+
default state, the global value has to be unset as well.
|
|
384
|
+
|
|
385
|
+
``unset()`` has no effect if called on a parameter that has not been
|
|
386
|
+
previously set.
|
|
387
|
+
|
|
388
|
+
Args:
|
|
389
|
+
step (str): Step name to unset for parameters that may be specified
|
|
390
|
+
on a per-node basis.
|
|
391
|
+
index (str): Index name to unset for parameters that may be specified
|
|
392
|
+
on a per-node basis.
|
|
393
|
+
'''
|
|
394
|
+
|
|
395
|
+
if self.__lock:
|
|
396
|
+
return False
|
|
397
|
+
|
|
398
|
+
if isinstance(index, int):
|
|
399
|
+
index = str(index)
|
|
400
|
+
|
|
401
|
+
step = step if step is not None else Parameter.GLOBAL_KEY
|
|
402
|
+
index = index if index is not None else Parameter.GLOBAL_KEY
|
|
403
|
+
|
|
404
|
+
try:
|
|
405
|
+
del self.__node[step][index]
|
|
406
|
+
except KeyError:
|
|
407
|
+
# If this key doesn't exist, silently continue - it was never set
|
|
408
|
+
pass
|
|
409
|
+
|
|
410
|
+
return True
|
|
411
|
+
|
|
412
|
+
def getdict(self, include_default=True):
|
|
413
|
+
"""
|
|
414
|
+
Returns a schema dictionary.
|
|
415
|
+
|
|
416
|
+
Args:
|
|
417
|
+
include_default (boolean): If true will include default values
|
|
418
|
+
|
|
419
|
+
Returns:
|
|
420
|
+
A schema dictionary
|
|
421
|
+
|
|
422
|
+
Examples:
|
|
423
|
+
>>> param.getdict()
|
|
424
|
+
Returns the complete dictionary for the parameter
|
|
425
|
+
"""
|
|
426
|
+
|
|
427
|
+
dictvals = {
|
|
428
|
+
"type": NodeType.encode(self.__type),
|
|
429
|
+
"require": self.__require,
|
|
430
|
+
"scope": self.__scope.value,
|
|
431
|
+
"lock": self.__lock,
|
|
432
|
+
"switch": self.__switch.copy(),
|
|
433
|
+
"shorthelp": self.__shorthelp,
|
|
434
|
+
"example": self.__example.copy(),
|
|
435
|
+
"help": self.__help,
|
|
436
|
+
"notes": self.__notes,
|
|
437
|
+
"pernode": self.__pernode.value,
|
|
438
|
+
"node": {}
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
for step in self.__node:
|
|
442
|
+
dictvals["node"][step] = {}
|
|
443
|
+
for index, val in self.__node[step].items():
|
|
444
|
+
dictvals["node"][step][index] = val.getdict()
|
|
445
|
+
|
|
446
|
+
if include_default:
|
|
447
|
+
dictvals["node"].setdefault("default", {})["default"] = self.__defvalue.getdict()
|
|
448
|
+
|
|
449
|
+
if self.__unit:
|
|
450
|
+
dictvals["unit"] = self.__unit
|
|
451
|
+
if self.__hashalgo:
|
|
452
|
+
dictvals["hashalgo"] = self.__hashalgo
|
|
453
|
+
if self.__copy is not None:
|
|
454
|
+
dictvals["copy"] = self.__copy
|
|
455
|
+
return dictvals
|
|
456
|
+
|
|
457
|
+
@classmethod
|
|
458
|
+
def from_dict(cls, manifest, keypath, version):
|
|
459
|
+
'''
|
|
460
|
+
Create a new parameter based on the provided dictionary.
|
|
461
|
+
|
|
462
|
+
Args:
|
|
463
|
+
manifest (dict): Manifest to decide.
|
|
464
|
+
keypath (list of str): Path to the current keypath.
|
|
465
|
+
version (packaging.Version): Version of the dictionary schema
|
|
466
|
+
'''
|
|
467
|
+
|
|
468
|
+
# create a dummy param
|
|
469
|
+
param = cls("str")
|
|
470
|
+
param._from_dict(manifest, keypath, version)
|
|
471
|
+
return param
|
|
472
|
+
|
|
473
|
+
def _from_dict(self, manifest, keypath, version):
|
|
474
|
+
'''
|
|
475
|
+
Copies the information from the manifest into this parameter.
|
|
476
|
+
|
|
477
|
+
Args:
|
|
478
|
+
manifest (dict): Manifest to decide.
|
|
479
|
+
keypath (list of str): Path to the current keypath.
|
|
480
|
+
version (packaging.Version): Version of the dictionary schema
|
|
481
|
+
'''
|
|
482
|
+
|
|
483
|
+
if self.__lock:
|
|
484
|
+
return
|
|
485
|
+
|
|
486
|
+
if version and version > (0, 50, 0):
|
|
487
|
+
self.__type = NodeType.parse(manifest["type"])
|
|
488
|
+
else:
|
|
489
|
+
if "enum" in manifest:
|
|
490
|
+
self.__type = NodeType.parse(
|
|
491
|
+
re.sub("enum", f"<{','.join(manifest['enum'])}>", manifest['type']))
|
|
492
|
+
else:
|
|
493
|
+
self.__type = NodeType.parse(manifest["type"])
|
|
494
|
+
|
|
495
|
+
self.__require = manifest.get("require", self.__require)
|
|
496
|
+
self.__scope = Scope(manifest.get("scope", self.__scope))
|
|
497
|
+
self.__lock = manifest.get("lock", self.__lock)
|
|
498
|
+
self.__switch = manifest.get("switch", self.__switch)
|
|
499
|
+
self.__shorthelp = manifest.get("shorthelp", self.__shorthelp)
|
|
500
|
+
self.__example = manifest.get("example", self.__example)
|
|
501
|
+
self.__help = manifest.get("help", self.__help)
|
|
502
|
+
self.__notes = manifest.get("notes", self.__notes)
|
|
503
|
+
self.__pernode = PerNode(manifest.get("pernode", self.__pernode))
|
|
504
|
+
self.__node = {}
|
|
505
|
+
|
|
506
|
+
self.__unit = manifest.get("unit", self.__unit)
|
|
507
|
+
self.__hashalgo = manifest.get("hashalgo", self.__hashalgo)
|
|
508
|
+
self.__copy = manifest.get("copy", self.__copy)
|
|
509
|
+
|
|
510
|
+
requires_set = NodeType.contains(self.__type, tuple) or NodeType.contains(self.__type, set)
|
|
511
|
+
|
|
512
|
+
try:
|
|
513
|
+
defvalue = manifest["node"]["default"]["default"]["value"]
|
|
514
|
+
del manifest["node"]["default"]
|
|
515
|
+
except KeyError:
|
|
516
|
+
defvalue = None
|
|
517
|
+
|
|
518
|
+
if requires_set:
|
|
519
|
+
self.__setdefvalue(NodeType.normalize(defvalue, self.__type))
|
|
520
|
+
else:
|
|
521
|
+
self.__setdefvalue(defvalue)
|
|
522
|
+
|
|
523
|
+
for step, indexdata in manifest["node"].items():
|
|
524
|
+
self.__node[step] = {}
|
|
525
|
+
for index, nodedata in indexdata.items():
|
|
526
|
+
value = self.__defvalue.copy()
|
|
527
|
+
value._from_dict(nodedata, keypath, version)
|
|
528
|
+
self.__node[step][index] = value
|
|
529
|
+
|
|
530
|
+
if requires_set:
|
|
531
|
+
for step, indexdata in self.__node.items():
|
|
532
|
+
for param in indexdata.values():
|
|
533
|
+
value = param.get()
|
|
534
|
+
param.set(value)
|
|
535
|
+
|
|
536
|
+
def gettcl(self, step=None, index=None):
|
|
537
|
+
"""
|
|
538
|
+
Returns a tcl string for this parameter.
|
|
539
|
+
|
|
540
|
+
Args:
|
|
541
|
+
step (str): Step name to unset for parameters that may be specified
|
|
542
|
+
on a per-node basis.
|
|
543
|
+
index (str): Index name to unset for parameters that may be specified
|
|
544
|
+
on a per-node basis.
|
|
545
|
+
"""
|
|
546
|
+
|
|
547
|
+
if self.__pernode == PerNode.REQUIRED and (step is None or index is None):
|
|
548
|
+
return None
|
|
549
|
+
if not self.__pernode.is_never():
|
|
550
|
+
value = self.get(step=step, index=index)
|
|
551
|
+
else:
|
|
552
|
+
value = self.get()
|
|
553
|
+
|
|
554
|
+
return NodeType.to_tcl(value, self.__type)
|
|
555
|
+
|
|
556
|
+
def getvalues(self, return_defvalue=True):
|
|
557
|
+
"""
|
|
558
|
+
Returns all values (global and pernode) associated with a particular parameter.
|
|
559
|
+
|
|
560
|
+
Returns a list of tuples of the form (value, step, index). The list is
|
|
561
|
+
in no particular order. For the global value, step and index are None.
|
|
562
|
+
If return_defvalue is True, the default parameter value is added to the
|
|
563
|
+
list in place of a global value if a global value is not set.
|
|
564
|
+
"""
|
|
565
|
+
|
|
566
|
+
vals = []
|
|
567
|
+
has_global = False
|
|
568
|
+
for step in self.__node:
|
|
569
|
+
for index in self.__node[step]:
|
|
570
|
+
step_arg = None if step == Parameter.GLOBAL_KEY else step
|
|
571
|
+
index_arg = None if index == Parameter.GLOBAL_KEY else index
|
|
572
|
+
if step_arg is None and index_arg is None:
|
|
573
|
+
has_global = True
|
|
574
|
+
vals.append((self.__node[step][index].get(), step_arg, index_arg))
|
|
575
|
+
|
|
576
|
+
if (self.__pernode != PerNode.REQUIRED) and not has_global and return_defvalue:
|
|
577
|
+
vals.append((self.__defvalue.get(), None, None))
|
|
578
|
+
|
|
579
|
+
return vals
|
|
580
|
+
|
|
581
|
+
def copy(self, key=None):
|
|
582
|
+
"""
|
|
583
|
+
Returns a copy of this parameter.
|
|
584
|
+
|
|
585
|
+
Args:
|
|
586
|
+
key (list of str): keypath to this schema
|
|
587
|
+
"""
|
|
588
|
+
|
|
589
|
+
return copy.deepcopy(self)
|
|
590
|
+
|
|
591
|
+
# Utility functions
|
|
592
|
+
def is_list(self):
|
|
593
|
+
"""
|
|
594
|
+
Returns true is this parameter is a list type
|
|
595
|
+
"""
|
|
596
|
+
|
|
597
|
+
return isinstance(self.__type, list)
|
|
598
|
+
|
|
599
|
+
def is_empty(self):
|
|
600
|
+
'''
|
|
601
|
+
Utility function to check key for an empty value.
|
|
602
|
+
'''
|
|
603
|
+
|
|
604
|
+
empty = (None, [])
|
|
605
|
+
|
|
606
|
+
values = self.getvalues()
|
|
607
|
+
return all([value in empty for value, _, _ in values])
|
|
608
|
+
|
|
609
|
+
def is_set(self, step=None, index=None):
|
|
610
|
+
'''
|
|
611
|
+
Returns whether a user has set a value for this parameter.
|
|
612
|
+
|
|
613
|
+
A value counts as set if a user has set a global value OR a value for
|
|
614
|
+
the provided step/index.
|
|
615
|
+
'''
|
|
616
|
+
if Parameter.GLOBAL_KEY in self.__node and \
|
|
617
|
+
Parameter.GLOBAL_KEY in self.__node[Parameter.GLOBAL_KEY] and \
|
|
618
|
+
self.__node[Parameter.GLOBAL_KEY][Parameter.GLOBAL_KEY]:
|
|
619
|
+
# global value is set
|
|
620
|
+
return True
|
|
621
|
+
|
|
622
|
+
if step is None:
|
|
623
|
+
return False
|
|
624
|
+
if index is None:
|
|
625
|
+
index = Parameter.GLOBAL_KEY
|
|
626
|
+
|
|
627
|
+
return step in self.__node and \
|
|
628
|
+
index in self.__node[step] and \
|
|
629
|
+
self.__node[step][index]
|
|
630
|
+
|
|
631
|
+
@property
|
|
632
|
+
def default(self):
|
|
633
|
+
"""
|
|
634
|
+
Gets a copy of the default value.
|
|
635
|
+
"""
|
|
636
|
+
return self.__defvalue.copy()
|
|
637
|
+
|
|
638
|
+
def add_commandline_arguments(self, argparser, *keypath, switchlist=None):
|
|
639
|
+
'''
|
|
640
|
+
Adds commandline arguments for this parameter.
|
|
641
|
+
|
|
642
|
+
Args:
|
|
643
|
+
argparser (argparse.ArgumentParser): argument parser to add switches to
|
|
644
|
+
keypath (list of str): keypath where this parameter is located.
|
|
645
|
+
switchlist (list of str): if provided will limited the switched added to
|
|
646
|
+
those in this list
|
|
647
|
+
|
|
648
|
+
Returns:
|
|
649
|
+
dest (str): key for argument parsing to lookup values in.
|
|
650
|
+
switches (list of str): list of switches added.
|
|
651
|
+
'''
|
|
652
|
+
if not self.__switch:
|
|
653
|
+
# no switches available to this parameter
|
|
654
|
+
return None, None
|
|
655
|
+
|
|
656
|
+
if not switchlist:
|
|
657
|
+
switchlist = []
|
|
658
|
+
elif not isinstance(switchlist, (list, set, tuple)):
|
|
659
|
+
switchlist = [switchlist]
|
|
660
|
+
|
|
661
|
+
switches = []
|
|
662
|
+
metavar = None
|
|
663
|
+
for switch in self.__switch:
|
|
664
|
+
switchmatch = re.match(r'(-[\w_]+)\s+(\'([\w]+\s)*<.*>\'|<.*>)', switch)
|
|
665
|
+
gccmatch = re.match(r'(-[\w_]+)(<.*>)', switch)
|
|
666
|
+
plusmatch = re.match(r'(\+[\w_\+]+)(<.*>)', switch)
|
|
667
|
+
|
|
668
|
+
if switchmatch:
|
|
669
|
+
switchstr = switchmatch.group(1)
|
|
670
|
+
metavar = switchmatch.group(2)
|
|
671
|
+
elif gccmatch:
|
|
672
|
+
switchstr = gccmatch.group(1)
|
|
673
|
+
metavar = gccmatch.group(2)
|
|
674
|
+
elif plusmatch:
|
|
675
|
+
switchstr = plusmatch.group(1)
|
|
676
|
+
metavar = plusmatch.group(2)
|
|
677
|
+
else:
|
|
678
|
+
raise ValueError(f"unable to process switch information: {switch}")
|
|
679
|
+
|
|
680
|
+
if switchlist and switchstr not in switchlist:
|
|
681
|
+
continue
|
|
682
|
+
|
|
683
|
+
switches.append(switchstr)
|
|
684
|
+
|
|
685
|
+
if not switches:
|
|
686
|
+
return None, None
|
|
687
|
+
|
|
688
|
+
# argparse 'dest' must be a string, so join keypath with commas
|
|
689
|
+
dest = '_'.join(keypath)
|
|
690
|
+
|
|
691
|
+
if self.__type == "bool":
|
|
692
|
+
# Boolean type arguments
|
|
693
|
+
if self.__pernode.is_never():
|
|
694
|
+
argparser.add_argument(
|
|
695
|
+
*switches,
|
|
696
|
+
nargs='?',
|
|
697
|
+
metavar=metavar,
|
|
698
|
+
dest=dest,
|
|
699
|
+
const='true',
|
|
700
|
+
help=self.__shorthelp,
|
|
701
|
+
default=argparse.SUPPRESS)
|
|
702
|
+
else:
|
|
703
|
+
argparser.add_argument(
|
|
704
|
+
*switches,
|
|
705
|
+
metavar=metavar,
|
|
706
|
+
nargs='?',
|
|
707
|
+
dest=dest,
|
|
708
|
+
action='append',
|
|
709
|
+
const='true',
|
|
710
|
+
help=self.__shorthelp,
|
|
711
|
+
default=argparse.SUPPRESS)
|
|
712
|
+
elif isinstance(self.__type, list) or self.__pernode != PerNode.NEVER:
|
|
713
|
+
# list type arguments
|
|
714
|
+
argparser.add_argument(
|
|
715
|
+
*switches,
|
|
716
|
+
metavar=metavar,
|
|
717
|
+
dest=dest,
|
|
718
|
+
action='append',
|
|
719
|
+
help=self.__shorthelp,
|
|
720
|
+
default=argparse.SUPPRESS)
|
|
721
|
+
else:
|
|
722
|
+
# all the rest
|
|
723
|
+
argparser.add_argument(
|
|
724
|
+
*switches,
|
|
725
|
+
metavar=metavar,
|
|
726
|
+
dest=dest,
|
|
727
|
+
help=self.__shorthelp,
|
|
728
|
+
default=argparse.SUPPRESS)
|
|
729
|
+
|
|
730
|
+
return dest, switches
|
|
731
|
+
|
|
732
|
+
def parse_commandline_arguments(self, value, *keypath):
|
|
733
|
+
"""
|
|
734
|
+
Parse and set the values provided form the commandline parser.
|
|
735
|
+
|
|
736
|
+
Args:
|
|
737
|
+
value (str): string from commandline
|
|
738
|
+
keypath (list of str): leypath to this parameter
|
|
739
|
+
"""
|
|
740
|
+
num_free_keys = keypath.count('default')
|
|
741
|
+
|
|
742
|
+
if num_free_keys > 0:
|
|
743
|
+
valueitem = shlex.split(value)
|
|
744
|
+
if len(valueitem) != num_free_keys + 1:
|
|
745
|
+
raise ValueError(f'Invalid value "{value}" for switch {"/".join(self.__switch)}')
|
|
746
|
+
|
|
747
|
+
free_keys = valueitem[0:num_free_keys]
|
|
748
|
+
remainder = valueitem[-1]
|
|
749
|
+
keypath = tuple([free_keys.pop(0) if key == 'default' else key for key in keypath])
|
|
750
|
+
else:
|
|
751
|
+
remainder = value
|
|
752
|
+
|
|
753
|
+
step, index = None, None
|
|
754
|
+
if self.__pernode == PerNode.REQUIRED:
|
|
755
|
+
try:
|
|
756
|
+
step, index, val = shlex.split(remainder)
|
|
757
|
+
except ValueError:
|
|
758
|
+
raise ValueError(f'Invalid value "{value}" for switch {"/".join(self.__switch)}: '
|
|
759
|
+
'Requires step and index before final value')
|
|
760
|
+
elif self.__pernode == PerNode.OPTIONAL:
|
|
761
|
+
# Split on spaces, preserving items that are grouped in quotes
|
|
762
|
+
items = shlex.split(remainder)
|
|
763
|
+
if len(items) > 3:
|
|
764
|
+
raise ValueError(f'Invalid value "{value}" for switch {"/".join(self.__switch)}: '
|
|
765
|
+
'Too many arguments')
|
|
766
|
+
if self.__type == 'bool':
|
|
767
|
+
if len(items) == 3:
|
|
768
|
+
step, index, val = items
|
|
769
|
+
elif len(items) == 2:
|
|
770
|
+
step, val = items
|
|
771
|
+
if val != 'true' and val != 'false':
|
|
772
|
+
index = val
|
|
773
|
+
val = 'true'
|
|
774
|
+
elif len(items) == 1:
|
|
775
|
+
val, = items
|
|
776
|
+
if val != 'true' and val != 'false':
|
|
777
|
+
step = val
|
|
778
|
+
val = 'true'
|
|
779
|
+
else:
|
|
780
|
+
val = 'true'
|
|
781
|
+
else:
|
|
782
|
+
if len(items) == 3:
|
|
783
|
+
step, index, val = items
|
|
784
|
+
elif len(items) == 2:
|
|
785
|
+
step, val = items
|
|
786
|
+
else:
|
|
787
|
+
val, = items
|
|
788
|
+
else:
|
|
789
|
+
val = remainder
|
|
790
|
+
|
|
791
|
+
return keypath, step, index, val
|