labview-fpga-hdl-tools 2.0.0.dev3__tar.gz → 2.0.0.dev4__tar.gz

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.
Files changed (29) hide show
  1. {labview_fpga_hdl_tools-2.0.0.dev3 → labview_fpga_hdl_tools-2.0.0.dev4}/PKG-INFO +5 -5
  2. {labview_fpga_hdl_tools-2.0.0.dev3 → labview_fpga_hdl_tools-2.0.0.dev4}/README.md +2 -2
  3. {labview_fpga_hdl_tools-2.0.0.dev3 → labview_fpga_hdl_tools-2.0.0.dev4}/labview_fpga_hdl_tools/__main__.py +3 -2
  4. {labview_fpga_hdl_tools-2.0.0.dev3 → labview_fpga_hdl_tools-2.0.0.dev4}/labview_fpga_hdl_tools/check_syntax.py +4 -3
  5. {labview_fpga_hdl_tools-2.0.0.dev3 → labview_fpga_hdl_tools-2.0.0.dev4}/labview_fpga_hdl_tools/common.py +2 -3
  6. {labview_fpga_hdl_tools-2.0.0.dev3 → labview_fpga_hdl_tools-2.0.0.dev4}/labview_fpga_hdl_tools/compile_modelsim_lib.py +5 -4
  7. {labview_fpga_hdl_tools-2.0.0.dev3 → labview_fpga_hdl_tools-2.0.0.dev4}/labview_fpga_hdl_tools/compile_project.py +4 -3
  8. {labview_fpga_hdl_tools-2.0.0.dev3 → labview_fpga_hdl_tools-2.0.0.dev4}/labview_fpga_hdl_tools/create_lvbitx.py +3 -3
  9. {labview_fpga_hdl_tools-2.0.0.dev3 → labview_fpga_hdl_tools-2.0.0.dev4}/labview_fpga_hdl_tools/create_modelsim_project.py +5 -4
  10. {labview_fpga_hdl_tools-2.0.0.dev3 → labview_fpga_hdl_tools-2.0.0.dev4}/labview_fpga_hdl_tools/create_vivado_project.py +4 -3
  11. {labview_fpga_hdl_tools-2.0.0.dev3 → labview_fpga_hdl_tools-2.0.0.dev4}/labview_fpga_hdl_tools/gen_labview_target_plugin.py +10 -7
  12. {labview_fpga_hdl_tools-2.0.0.dev3 → labview_fpga_hdl_tools-2.0.0.dev4}/labview_fpga_hdl_tools/generate_vhdl.py +5 -4
  13. {labview_fpga_hdl_tools-2.0.0.dev3 → labview_fpga_hdl_tools-2.0.0.dev4}/labview_fpga_hdl_tools/get_window_netlist.py +4 -3
  14. {labview_fpga_hdl_tools-2.0.0.dev3 → labview_fpga_hdl_tools-2.0.0.dev4}/labview_fpga_hdl_tools/install_dependencies.py +1 -1
  15. {labview_fpga_hdl_tools-2.0.0.dev3 → labview_fpga_hdl_tools-2.0.0.dev4}/labview_fpga_hdl_tools/install_labview_target_plugin.py +30 -11
  16. {labview_fpga_hdl_tools-2.0.0.dev3 → labview_fpga_hdl_tools-2.0.0.dev4}/labview_fpga_hdl_tools/launch_modelsim.py +5 -4
  17. {labview_fpga_hdl_tools-2.0.0.dev3 → labview_fpga_hdl_tools-2.0.0.dev4}/labview_fpga_hdl_tools/launch_vivado.py +4 -3
  18. {labview_fpga_hdl_tools-2.0.0.dev3 → labview_fpga_hdl_tools-2.0.0.dev4}/labview_fpga_hdl_tools/migrate_clip.py +8 -5
  19. {labview_fpga_hdl_tools-2.0.0.dev3 → labview_fpga_hdl_tools-2.0.0.dev4}/labview_fpga_hdl_tools/process_constraints.py +3 -3
  20. {labview_fpga_hdl_tools-2.0.0.dev3 → labview_fpga_hdl_tools-2.0.0.dev4}/labview_fpga_hdl_tools/sim_modelsim.py +5 -4
  21. labview_fpga_hdl_tools-2.0.0.dev4/pyproject.toml +75 -0
  22. labview_fpga_hdl_tools-2.0.0.dev3/pyproject.toml +0 -50
  23. {labview_fpga_hdl_tools-2.0.0.dev3 → labview_fpga_hdl_tools-2.0.0.dev4}/LICENSE +0 -0
  24. {labview_fpga_hdl_tools-2.0.0.dev3 → labview_fpga_hdl_tools-2.0.0.dev4}/labview_fpga_hdl_tools/.gitignore +0 -0
  25. {labview_fpga_hdl_tools-2.0.0.dev3 → labview_fpga_hdl_tools-2.0.0.dev4}/labview_fpga_hdl_tools/__init__.py +0 -0
  26. {labview_fpga_hdl_tools-2.0.0.dev3 → labview_fpga_hdl_tools-2.0.0.dev4}/labview_fpga_hdl_tools/command_config.py +0 -0
  27. {labview_fpga_hdl_tools-2.0.0.dev3 → labview_fpga_hdl_tools-2.0.0.dev4}/labview_fpga_hdl_tools/command_hooks.py +0 -0
  28. {labview_fpga_hdl_tools-2.0.0.dev3 → labview_fpga_hdl_tools-2.0.0.dev4}/labview_fpga_hdl_tools/nihdlsettings_default.py +0 -0
  29. {labview_fpga_hdl_tools-2.0.0.dev3 → labview_fpga_hdl_tools-2.0.0.dev4}/labview_fpga_hdl_tools/reporting.py +0 -0
@@ -1,19 +1,19 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: labview-fpga-hdl-tools
3
- Version: 2.0.0.dev3
3
+ Version: 2.0.0.dev4
4
4
  Summary: LabVIEW FPGA HDL Tools
5
5
  License: MIT
6
6
  Author: Salvador Santolucito
7
7
  Author-email: salvador.santolucito@gmail.com
8
- Requires-Python: >=3.9,<4.0
8
+ Requires-Python: >=3.10,<3.15
9
9
  Classifier: License :: OSI Approved :: MIT License
10
10
  Classifier: Programming Language :: Python :: 3
11
- Classifier: Programming Language :: Python :: 3.9
12
11
  Classifier: Programming Language :: Python :: 3.10
13
12
  Classifier: Programming Language :: Python :: 3.11
14
13
  Classifier: Programming Language :: Python :: 3.12
15
14
  Classifier: Programming Language :: Python :: 3.13
16
15
  Requires-Dist: click (>=8.1.8,<8.2)
16
+ Requires-Dist: defusedxml (>=0.7.1)
17
17
  Requires-Dist: mako (>=1.3.10)
18
18
  Requires-Dist: packaging (>=21.0)
19
19
  Requires-Dist: tomli (>=1.1.0) ; python_version < "3.11"
@@ -66,8 +66,8 @@ You need the external tools your flow uses:
66
66
  - **ModelSim** — only for simulation (`gen-modelsim`, `sim-modelsim`,
67
67
  `launch-modelsim`, `compile-modelsim-lib`). `compile-modelsim-lib` also needs
68
68
  Vivado to compile the Xilinx simulation libraries.
69
- - **Git** and **Python** — the tools support Python 3.9+; CI tests on 3.9 and
70
- 3.11 (3.11 is also used for static analysis).
69
+ - **Git** and **Python** — the tools support Python 3.10–3.14; CI tests on
70
+ 3.10 through 3.14 (3.11 is also used for static analysis).
71
71
 
72
72
  ### Installing the tools
73
73
 
@@ -45,8 +45,8 @@ You need the external tools your flow uses:
45
45
  - **ModelSim** — only for simulation (`gen-modelsim`, `sim-modelsim`,
46
46
  `launch-modelsim`, `compile-modelsim-lib`). `compile-modelsim-lib` also needs
47
47
  Vivado to compile the Xilinx simulation libraries.
48
- - **Git** and **Python** — the tools support Python 3.9+; CI tests on 3.9 and
49
- 3.11 (3.11 is also used for static analysis).
48
+ - **Git** and **Python** — the tools support Python 3.10–3.14; CI tests on
49
+ 3.10 through 3.14 (3.11 is also used for static analysis).
50
50
 
51
51
  ### Installing the tools
52
52
 
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env python3
2
2
  """LVFPGAHDLTools - Command-line interface for LabVIEW FPGA HDL Tools."""
3
+
3
4
  # Copyright (c) 2025 National Instruments Corporation
4
5
  #
5
6
  # SPDX-License-Identifier: MIT
@@ -11,7 +12,7 @@ import traceback
11
12
  import click
12
13
 
13
14
  # Import main functions from all the tool modules
14
- from . import (
15
+ from labview_fpga_hdl_tools import (
15
16
  __version__,
16
17
  check_syntax,
17
18
  command_hooks,
@@ -32,7 +33,7 @@ from . import (
32
33
  process_constraints,
33
34
  sim_modelsim,
34
35
  )
35
- from .reporting import reporter
36
+ from labview_fpga_hdl_tools.reporting import reporter
36
37
 
37
38
 
38
39
  class SectionGroup(click.Group):
@@ -8,8 +8,9 @@
8
8
  import os
9
9
  import subprocess
10
10
 
11
- from . import common
12
- from .reporting import reporter
11
+ from labview_fpga_hdl_tools import common
12
+ from labview_fpga_hdl_tools.command_config import CommandConfiguration
13
+ from labview_fpga_hdl_tools.reporting import reporter
13
14
 
14
15
 
15
16
  def _generate_check_syntax_tcl(config, output_path):
@@ -178,7 +179,7 @@ def check_syntax(config=None):
178
179
  int: 0 for success, 1 for error
179
180
  """
180
181
  if config is None:
181
- config = common.CommandConfiguration()
182
+ config = CommandConfiguration()
182
183
 
183
184
  try:
184
185
  _validate_ini(config)
@@ -14,8 +14,7 @@ from typing import Optional
14
14
 
15
15
  from mako.template import Template
16
16
 
17
- from .command_config import CommandConfiguration, resolve_path # noqa: F401
18
- from .reporting import reporter
17
+ from labview_fpga_hdl_tools.reporting import reporter
19
18
 
20
19
 
21
20
  def handle_long_path(path):
@@ -599,7 +598,7 @@ def render_mako_template(template_path, output_path, **kwargs):
599
598
  output_path (str): Path where the rendered output will be written
600
599
  **kwargs: Template variables to substitute
601
600
  """
602
- template = Template(filename=template_path, input_encoding="utf-8")
601
+ template = Template(filename=template_path, input_encoding="utf-8") # nosec B702
603
602
  rendered = str(template.render(**kwargs))
604
603
 
605
604
  # Mako preserves \r\n from template files on Windows. Normalize to \n
@@ -21,9 +21,10 @@ import os
21
21
  import subprocess
22
22
  import sys
23
23
 
24
- from . import common
25
- from .create_modelsim_project import _find_modelsim_executable
26
- from .reporting import reporter
24
+ from labview_fpga_hdl_tools import common
25
+ from labview_fpga_hdl_tools.command_config import CommandConfiguration
26
+ from labview_fpga_hdl_tools.create_modelsim_project import _find_modelsim_executable
27
+ from labview_fpga_hdl_tools.reporting import reporter
27
28
 
28
29
  # Libraries built when nihdlsettings.py does not specify an explicit scope.
29
30
  _DEFAULT_XILINX_SIM_LIBRARIES = ["unisim", "secureip"]
@@ -250,7 +251,7 @@ def compile_modelsim_lib(config=None, force=False):
250
251
  int: 0 for success, 1 for error.
251
252
  """
252
253
  if config is None:
253
- config = common.CommandConfiguration()
254
+ config = CommandConfiguration()
254
255
 
255
256
  out_folder = config.xilinx_sim_lib_folder
256
257
  if not out_folder:
@@ -8,8 +8,9 @@
8
8
  import os
9
9
  import subprocess
10
10
 
11
- from . import common
12
- from .reporting import reporter
11
+ from labview_fpga_hdl_tools import common
12
+ from labview_fpga_hdl_tools.command_config import CommandConfiguration
13
+ from labview_fpga_hdl_tools.reporting import reporter
13
14
 
14
15
 
15
16
  def _generate_compile_project_tcl(config, output_path):
@@ -187,7 +188,7 @@ def compile_project(config=None):
187
188
  int: 0 for success, 1 for error
188
189
  """
189
190
  if config is None:
190
- config = common.CommandConfiguration()
191
+ config = CommandConfiguration()
191
192
 
192
193
  try:
193
194
  _validate_ini(config)
@@ -7,8 +7,8 @@
7
7
  import os # For file and directory operations
8
8
  import subprocess # For executing external programs
9
9
 
10
- from . import common # For shared utilities across tools
11
- from .reporting import reporter
10
+ from labview_fpga_hdl_tools.command_config import CommandConfiguration
11
+ from labview_fpga_hdl_tools.reporting import reporter
12
12
 
13
13
  # createBitfile.exe lives at this path relative to a LabVIEW install root.
14
14
  _CREATEBITFILE_RELPATH = os.path.join("vi.lib", "rvi", "CDR", "createBitfile.exe")
@@ -114,7 +114,7 @@ def _create_lv_bitfile(config=None):
114
114
 
115
115
  # Load configuration
116
116
  if config is None:
117
- config = common.CommandConfiguration()
117
+ config = CommandConfiguration()
118
118
 
119
119
  # Determine path to CodeGenerationResults.lvtxt from TheWindow folder
120
120
  if not config.lv_window_netlist_folder:
@@ -11,8 +11,9 @@ import shutil
11
11
  import stat
12
12
  import subprocess
13
13
 
14
- from . import common, generate_vhdl
15
- from .reporting import reporter
14
+ from labview_fpga_hdl_tools import common, generate_vhdl
15
+ from labview_fpga_hdl_tools.command_config import CommandConfiguration
16
+ from labview_fpga_hdl_tools.reporting import reporter
16
17
 
17
18
 
18
19
  def _validate_ini(config):
@@ -426,7 +427,7 @@ def create_modelsim_project(overwrite=False, config=None):
426
427
  - .do files for GUI and batch simulation
427
428
  """
428
429
  if config is None:
429
- config = common.CommandConfiguration()
430
+ config = CommandConfiguration()
430
431
 
431
432
  try:
432
433
  _validate_ini(config)
@@ -499,7 +500,7 @@ def create_modelsim_project(overwrite=False, config=None):
499
500
  # This is idempotent: once compiled it is a cheap no-op (and does not
500
501
  # even require Vivado). Imported locally to avoid a circular import,
501
502
  # since compile_modelsim_lib imports helpers from this module.
502
- from . import compile_modelsim_lib
503
+ from labview_fpga_hdl_tools import compile_modelsim_lib
503
504
 
504
505
  if compile_modelsim_lib.compile_modelsim_lib(config=config) != 0:
505
506
  return 1
@@ -23,8 +23,9 @@ import subprocess
23
23
  from collections import defaultdict
24
24
  from enum import Enum
25
25
 
26
- from . import common, generate_vhdl, process_constraints
27
- from .reporting import reporter
26
+ from labview_fpga_hdl_tools import common, generate_vhdl, process_constraints
27
+ from labview_fpga_hdl_tools.command_config import CommandConfiguration
28
+ from labview_fpga_hdl_tools.reporting import reporter
28
29
 
29
30
  # Windows MAX_PATH. When the generated TCL adds a source file, Vivado resolves the
30
31
  # file's add_files path (which is relative to the TCL folder) against the Vivado
@@ -810,7 +811,7 @@ def create_project(overwrite=False, update=False, config=None):
810
811
  """
811
812
  # Load configuration with optional custom config path
812
813
  if config is None:
813
- config = common.CommandConfiguration()
814
+ config = CommandConfiguration()
814
815
 
815
816
  result = _run_create_project_steps(overwrite, update, config)
816
817
 
@@ -22,14 +22,17 @@ import re
22
22
  import shutil # For file copying operations
23
23
  import stat
24
24
  import xml.etree.ElementTree as ET # For XML generation and manipulation # noqa: N817
25
- from xml.dom.minidom import parseString # For pretty-formatted XML output
26
25
 
26
+ from defusedxml.minidom import parseString # For safe pretty-formatted XML output
27
27
  from mako.template import Template # For template-based file generation # type: ignore
28
28
 
29
- from . import common # For shared utilities across tools
30
- from . import generate_vhdl # For generated VHDL file generation
31
- from . import process_constraints # For shared constraint macro replacement
32
- from .reporting import reporter
29
+ from labview_fpga_hdl_tools import common # For shared utilities across tools
30
+ from labview_fpga_hdl_tools import generate_vhdl # For generated VHDL file generation
31
+ from labview_fpga_hdl_tools import (
32
+ process_constraints, # For shared constraint macro replacement
33
+ )
34
+ from labview_fpga_hdl_tools.command_config import CommandConfiguration
35
+ from labview_fpga_hdl_tools.reporting import reporter
33
36
 
34
37
  # Constants
35
38
  BOARDIO_WRAPPER_NAME = "BoardIO" # Top-level wrapper name in the BoardIO XML hierarchy
@@ -507,7 +510,7 @@ def _generate_target_xml(
507
510
  # Render template
508
511
  try:
509
512
  with open(template_path, "r", encoding="utf-8") as f:
510
- template = Template(f.read())
513
+ template = Template(f.read()) # nosec B702
511
514
 
512
515
  render_kwargs = {
513
516
  "include_board_io": include_board_io,
@@ -750,7 +753,7 @@ def gen_lv_target_support(config=None):
750
753
  """Generate target support files."""
751
754
  # Load configuration
752
755
  if config is None:
753
- config = common.CommandConfiguration()
756
+ config = CommandConfiguration()
754
757
  has_validation_errors = False
755
758
  validation_errors = []
756
759
  register_space_warnings = []
@@ -23,8 +23,9 @@ import os # For file and directory operations
23
23
 
24
24
  from mako.template import Template # For template-based file generation # type: ignore
25
25
 
26
- from . import common # For shared utilities across tools
27
- from .reporting import reporter
26
+ from labview_fpga_hdl_tools import common # For shared utilities across tools
27
+ from labview_fpga_hdl_tools.command_config import CommandConfiguration
28
+ from labview_fpga_hdl_tools.reporting import reporter
28
29
 
29
30
 
30
31
  def _ensure_text(value):
@@ -241,7 +242,7 @@ def _render_generated_vhdl(template_paths, output_folder, context):
241
242
  reporter.detail(f"Processing template: {template_path} -> {output_path}")
242
243
 
243
244
  with open(template_path, "r", encoding="utf-8") as f:
244
- template = Template(f.read())
245
+ template = Template(f.read()) # nosec B702
245
246
 
246
247
  output_text = template.render(**context)
247
248
 
@@ -303,7 +304,7 @@ def gen_generated_vhdl(config=None):
303
304
  """
304
305
  # Load configuration
305
306
  if config is None:
306
- config = common.CommandConfiguration()
307
+ config = CommandConfiguration()
307
308
 
308
309
  if not config.generated_vhdl_templates:
309
310
  # Nothing to generate; not an error.
@@ -10,8 +10,9 @@ import os
10
10
  import shutil
11
11
  import subprocess
12
12
 
13
- from . import common
14
- from .reporting import reporter
13
+ from labview_fpga_hdl_tools import common
14
+ from labview_fpga_hdl_tools.command_config import CommandConfiguration
15
+ from labview_fpga_hdl_tools.reporting import reporter
15
16
 
16
17
  # Generated flat wrapper file produced by the GetWindowNetlist TCL script.
17
18
  _WINDOW_FLAT_WRAPPER_FILE = "TheLvWindowFlatWrapper.v"
@@ -305,7 +306,7 @@ def get_window(config=None):
305
306
  """Main entry point for the script."""
306
307
  # Load configuration
307
308
  if config is None:
308
- config = common.CommandConfiguration()
309
+ config = CommandConfiguration()
309
310
 
310
311
  # Validate that all required settings are present
311
312
  try:
@@ -52,7 +52,7 @@ except ModuleNotFoundError:
52
52
  from packaging.specifiers import SpecifierSet
53
53
  from packaging.version import InvalidVersion, Version
54
54
 
55
- from .reporting import reporter
55
+ from labview_fpga_hdl_tools.reporting import reporter
56
56
 
57
57
  # Suffix for the per-dependency version marker files written next to each
58
58
  # cloned repo. Mirrors the discoverability of Python's "<pkg>-<ver>.dist-info"
@@ -8,8 +8,9 @@ import os # For file and directory operations
8
8
  import shutil # For file copying and directory removal
9
9
  import sys # For command-line arguments and error handling
10
10
 
11
- from . import common # For shared utilities across tools
12
- from .reporting import reporter
11
+ from labview_fpga_hdl_tools import common # For shared utilities across tools
12
+ from labview_fpga_hdl_tools.command_config import CommandConfiguration
13
+ from labview_fpga_hdl_tools.reporting import reporter
13
14
 
14
15
 
15
16
  def _is_admin():
@@ -26,8 +27,21 @@ def _is_admin():
26
27
 
27
28
 
28
29
  def _run_as_admin():
29
- """Re-launch the command with administrator privileges."""
30
+ """Re-launch the command with administrator privileges.
31
+
32
+ Security notes:
33
+ - Elevation spawns a *separate* short-lived process via UAC; the elevated
34
+ privileges live and die with that child process. The elevated instance
35
+ performs the install and then exits, so admin rights are never retained
36
+ by any process after installation completes.
37
+ - The executable is always resolved to a fully-qualified path before being
38
+ handed to ShellExecuteW. Passing a bare program name (e.g. "nihdl") would
39
+ let Windows resolve it against the working directory / PATH in the
40
+ elevated context, allowing an attacker-planted binary to run as admin
41
+ (CWE-426/CWE-427, untrusted search path).
42
+ """
30
43
  import ctypes
44
+ import subprocess
31
45
  import sys
32
46
 
33
47
  # Skip on non-Windows platforms
@@ -35,13 +49,17 @@ def _run_as_admin():
35
49
  reporter.detail("Admin elevation only supported on Windows")
36
50
  return
37
51
 
38
- # When running via pip-installed entry point
39
- if sys.argv[0].endswith("nihdl") or sys.argv[0].endswith("nihdl.exe"):
40
- command = "nihdl"
41
- arguments = " ".join(sys.argv[1:])
52
+ # Resolve the launcher to an absolute, trusted path. Never pass a bare
53
+ # program name to ShellExecuteW "runas".
54
+ launcher = os.path.abspath(sys.argv[0])
55
+ if launcher.lower().endswith(".exe") and os.path.isfile(launcher):
56
+ # pip-installed console entry point (e.g. nihdl.exe)
57
+ command = launcher
58
+ arguments = subprocess.list2cmdline(sys.argv[1:])
42
59
  else:
43
- command = sys.executable
44
- arguments = f'"{sys.argv[0]}" {" ".join(sys.argv[1:])}'
60
+ # Running as a .py script under the current interpreter
61
+ command = os.path.abspath(sys.executable)
62
+ arguments = subprocess.list2cmdline([launcher, *sys.argv[1:]])
45
63
 
46
64
  reporter.detail("Requesting administrator privileges...")
47
65
 
@@ -55,7 +73,8 @@ def _run_as_admin():
55
73
  reporter.error(f"Error elevating privileges. Error code: {result}")
56
74
  sys.exit(1)
57
75
 
58
- # The original process should exit after launching the elevated one
76
+ # The original (non-elevated) process exits after launching the elevated
77
+ # one, so no admin privileges are held by a lingering process.
59
78
  reporter.detail("Elevated process launched. This process will now exit.")
60
79
  sys.exit(0)
61
80
 
@@ -121,7 +140,7 @@ def install_lv_target_support(config=None):
121
140
  """
122
141
  # Load configuration
123
142
  if config is None:
124
- config = common.CommandConfiguration()
143
+ config = CommandConfiguration()
125
144
 
126
145
  # Validate that all required settings are present
127
146
  try:
@@ -9,9 +9,10 @@ import os
9
9
  import platform
10
10
  import subprocess
11
11
 
12
- from . import common
13
- from .create_modelsim_project import _get_vsim_executable
14
- from .reporting import reporter
12
+ from labview_fpga_hdl_tools import common
13
+ from labview_fpga_hdl_tools.command_config import CommandConfiguration
14
+ from labview_fpga_hdl_tools.create_modelsim_project import _get_vsim_executable
15
+ from labview_fpga_hdl_tools.reporting import reporter
15
16
 
16
17
 
17
18
  def _validate_ini(config):
@@ -38,7 +39,7 @@ def _validate_ini(config):
38
39
  def launch_modelsim(batch=False, config=None):
39
40
  """Launch ModelSim using settings from nihdlsettings.py."""
40
41
  if config is None:
41
- config = common.CommandConfiguration()
42
+ config = CommandConfiguration()
42
43
 
43
44
  try:
44
45
  _validate_ini(config)
@@ -9,8 +9,9 @@ import os
9
9
  import platform
10
10
  import subprocess
11
11
 
12
- from . import common
13
- from .reporting import reporter
12
+ from labview_fpga_hdl_tools import common
13
+ from labview_fpga_hdl_tools.command_config import CommandConfiguration
14
+ from labview_fpga_hdl_tools.reporting import reporter
14
15
 
15
16
 
16
17
  def _validate_ini(config):
@@ -50,7 +51,7 @@ def launch_vivado(config=None):
50
51
  """Launch Vivado using settings from nihdlsettings.py."""
51
52
  # Load configuration from nihdlsettings.py
52
53
  if config is None:
53
- config = common.CommandConfiguration()
54
+ config = CommandConfiguration()
54
55
 
55
56
  # Validate that all required settings are present and paths exist
56
57
  try:
@@ -21,8 +21,11 @@ import sys
21
21
  import traceback
22
22
  import xml.etree.ElementTree as ET # noqa: N817
23
23
 
24
- from . import common
25
- from .reporting import reporter
24
+ import defusedxml.ElementTree as DefusedET
25
+
26
+ from labview_fpga_hdl_tools import common
27
+ from labview_fpga_hdl_tools.command_config import CommandConfiguration
28
+ from labview_fpga_hdl_tools.reporting import reporter
26
29
 
27
30
  INVALID_LV_DATA_TYPE = "INVALID_LV_DATA_TYPE"
28
31
 
@@ -181,7 +184,7 @@ def _generate_board_io_csv_from_clip_xml(input_xml_path, clip_output_csv):
181
184
 
182
185
  # Parse XML
183
186
  try:
184
- tree = ET.parse(input_xml_path)
187
+ tree = DefusedET.parse(input_xml_path)
185
188
  root = tree.getroot()
186
189
  except ET.ParseError as e:
187
190
  sys.exit(f"Error parsing XML file: {e}")
@@ -369,7 +372,7 @@ def _generate_clip_to_window_signals(input_xml_path, output_vhdl_path):
369
372
 
370
373
  # Parse XML
371
374
  try:
372
- tree = ET.parse(input_xml_path)
375
+ tree = DefusedET.parse(input_xml_path)
373
376
  root = tree.getroot()
374
377
  except ET.ParseError as e:
375
378
  reporter.error(f"Error parsing XML file: {e}")
@@ -637,7 +640,7 @@ def migrate_clip(config=None):
637
640
  """Main program entry point."""
638
641
  # Load configuration
639
642
  if config is None:
640
- config = common.CommandConfiguration()
643
+ config = CommandConfiguration()
641
644
  validation_errors = []
642
645
 
643
646
  # Validate that all required settings are present
@@ -13,8 +13,8 @@ into user-provided template files, replacing macro tokens.
13
13
  import os
14
14
  import re
15
15
 
16
- from . import common
17
- from .reporting import reporter
16
+ from labview_fpga_hdl_tools.command_config import CommandConfiguration
17
+ from labview_fpga_hdl_tools.reporting import reporter
18
18
 
19
19
  # ---------------------------------------------------------------------------
20
20
  # TG/TNM constraint conversion helpers
@@ -435,6 +435,6 @@ def process_constraints(config=None):
435
435
  int: 0 on success.
436
436
  """
437
437
  if config is None:
438
- config = common.CommandConfiguration()
438
+ config = CommandConfiguration()
439
439
  process_constraints_template(config)
440
440
  return 0
@@ -10,9 +10,10 @@ import subprocess
10
10
  import sys
11
11
  import time
12
12
 
13
- from . import common
14
- from .create_modelsim_project import _get_vsim_executable
15
- from .reporting import reporter
13
+ from labview_fpga_hdl_tools import common
14
+ from labview_fpga_hdl_tools.command_config import CommandConfiguration
15
+ from labview_fpga_hdl_tools.create_modelsim_project import _get_vsim_executable
16
+ from labview_fpga_hdl_tools.reporting import reporter
16
17
 
17
18
 
18
19
  def _validate_ini(config):
@@ -50,7 +51,7 @@ def sim_modelsim(do_file=None, config=None):
50
51
  int: 0 on success, non-zero on failure.
51
52
  """
52
53
  if config is None:
53
- config = common.CommandConfiguration()
54
+ config = CommandConfiguration()
54
55
 
55
56
  try:
56
57
  _validate_ini(config)
@@ -0,0 +1,75 @@
1
+ [build-system]
2
+ requires = ["poetry-core>=1.8"]
3
+ build-backend = "poetry.core.masonry.api"
4
+
5
+ [tool.poetry]
6
+ name = "labview-fpga-hdl-tools"
7
+ version = "2.0.0.dev4"
8
+ description = "LabVIEW FPGA HDL Tools"
9
+ authors = [
10
+ "Salvador Santolucito <salvador.santolucito@gmail.com>"
11
+ ]
12
+ readme = "README.md"
13
+ license = "MIT"
14
+ include = [
15
+ { path = "labview_fpga_hdl_tools/host_interfaces/**", format = "sdist" }
16
+ ]
17
+
18
+ [tool.poetry.dependencies]
19
+ # Supports the Python versions in their maintenance window (3.10-3.14).
20
+ python = ">=3.10,<3.15"
21
+ mako = ">=1.3.10"
22
+ click = ">=8.1.8,<8.2"
23
+ packaging = ">=21.0"
24
+ # Hardens XML parsing against XXE / entity-expansion attacks (used instead of xml.etree/minidom).
25
+ defusedxml = ">=0.7.1"
26
+ tomli = {version = ">=1.1.0", python = "<3.11"}
27
+
28
+ [tool.poetry.group.test.dependencies]
29
+ # >=9.0.3 fixes insecure /tmp/pytest-of-{user} tmpdir handling (CVE); requires Python >=3.10.
30
+ pytest = ">=9.0.3"
31
+
32
+ [tool.poetry.group.lint.dependencies]
33
+ bandit = { version = ">=1.7", extras = ["toml"] }
34
+ # 0.5.x bundles flake8-tidy-imports (bans relative imports) and a pkg_resources-free
35
+ # flake8-import-order (>=0.19.2), which is required for setuptools >= 81.
36
+ ni-python-styleguide = ">=0.5.1"
37
+ # Pinned directly (transitive via ni-python-styleguide) so security updates can be applied.
38
+ # Capped < 26 because ni-python-styleguide 0.5.x requires black < 26.0; 25.12.0 needs Python >= 3.10.
39
+ black = ">=25.12.0,<26"
40
+ # flake8-black < 0.4.0 crashes (BLK900) on black >= 25.9.0 due to a decode_bytes API change.
41
+ flake8-black = ">=0.4.0"
42
+ # Transitive via bandit/pbr and ni-python-styleguide. Bumped to the latest to clear the
43
+ # setuptools sdist Unicode-normalization advisory (fixed in 83.0.0); 83 dropped pkg_resources,
44
+ # which is why ni-python-styleguide 0.5.x (pkg_resources-free import-order) is required.
45
+ setuptools = ">=83.0.0"
46
+ mypy = ">=1.0"
47
+ pyright = { version = ">=1.1.400", extras = ["nodejs"] }
48
+
49
+ [tool.poetry.scripts]
50
+ nihdl = "labview_fpga_hdl_tools.__main__:main"
51
+
52
+ [tool.mypy]
53
+ packages = ["labview_fpga_hdl_tools"]
54
+ python_version = "3.10"
55
+ warn_return_any = true
56
+ warn_unused_configs = true
57
+ disallow_untyped_defs = false
58
+ disallow_incomplete_defs = false
59
+
60
+ [[tool.mypy.overrides]]
61
+ module = "mako.*"
62
+ ignore_missing_imports = true
63
+
64
+ [[tool.mypy.overrides]]
65
+ module = "defusedxml.*"
66
+ ignore_missing_imports = true
67
+
68
+ [tool.bandit]
69
+ exclude_dirs = ["tests"]
70
+ # Reviewed low-severity informational tests, safe by construction:
71
+ # B404/B603/B607 - subprocess is invoked with argument lists (never shell=True), so there is
72
+ # no shell-injection surface; executable paths are resolved from trusted configuration.
73
+ # B405 - xml.etree is used only for XML generation / ParseError handling; all XML parsing
74
+ # uses defusedxml (see the B314/B318 remediations).
75
+ skips = ["B404", "B603", "B607", "B405"]
@@ -1,50 +0,0 @@
1
- [build-system]
2
- requires = ["poetry-core>=1.8"]
3
- build-backend = "poetry.core.masonry.api"
4
-
5
- [tool.poetry]
6
- name = "labview-fpga-hdl-tools"
7
- version = "2.0.0.dev3"
8
- description = "LabVIEW FPGA HDL Tools"
9
- authors = [
10
- "Salvador Santolucito <salvador.santolucito@gmail.com>"
11
- ]
12
- readme = "README.md"
13
- license = "MIT"
14
- include = [
15
- { path = "labview_fpga_hdl_tools/host_interfaces/**", format = "sdist" }
16
- ]
17
-
18
- [tool.poetry.dependencies]
19
- python = ">=3.9,<4.0"
20
- mako = ">=1.3.10"
21
- click = ">=8.1.8,<8.2"
22
- packaging = ">=21.0"
23
- tomli = {version = ">=1.1.0", python = "<3.11"}
24
-
25
- [tool.poetry.group.test.dependencies]
26
- pytest = ">=7.2"
27
-
28
- [tool.poetry.group.lint.dependencies]
29
- bandit = { version = ">=1.7", extras = ["toml"] }
30
- ni-python-styleguide = ">=0.4.1"
31
- mypy = ">=1.0"
32
- pyright = { version = ">=1.1.400", extras = ["nodejs"] }
33
-
34
- [tool.poetry.scripts]
35
- nihdl = "labview_fpga_hdl_tools.__main__:main"
36
-
37
- [tool.mypy]
38
- packages = ["labview_fpga_hdl_tools"]
39
- python_version = "3.9"
40
- warn_return_any = true
41
- warn_unused_configs = true
42
- disallow_untyped_defs = false
43
- disallow_incomplete_defs = false
44
-
45
- [[tool.mypy.overrides]]
46
- module = "mako.*"
47
- ignore_missing_imports = true
48
-
49
- [tool.bandit]
50
- exclude_dirs = ["tests"]