Skip to content

Commit 78f4097

Browse files
ssantoluSalvador Santoluctio
andauthored
Fixing tests (#7)
* cleanup * style fix * fixing tests --------- Co-authored-by: Salvador Santoluctio <salvador.santolucito@ni.com>
1 parent 8f02d68 commit 78f4097

File tree

8 files changed

+285
-194
lines changed

8 files changed

+285
-194
lines changed

labview_fpga_hdl_tools/__main__.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
migrate_clip,
2424
)
2525
from .common import generate_guid
26-
from .common import generate_guid
2726

2827

2928
@click.group(help=f"LabVIEW FPGA HDL Tools (v{__version__})")

labview_fpga_hdl_tools/common.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,11 @@ class FileConfiguration:
7979
lv_target_install_folder: Optional[str] = None # Installation folder for target plugins
8080
lv_target_menus_folder: Optional[str] = None # Folder containing target plugin menu files
8181
lv_target_info_ini: Optional[str] = None # Path to TargetInfo.ini file
82-
lv_target_exclude_files: Optional[str] = None # Path to Python script with file exclusion patterns
82+
lv_target_exclude_files: Optional[str] = (
83+
None # Path to Python script with file exclusion patterns
84+
)
8385
num_hdl_registers: Optional[int] = None # Number of HDL registers
86+
max_hdl_reg_offset: Optional[int] = None # Maximum HDL register byte offset
8487
# ----- CLIP MIGRATION SETTINGS -----
8588
input_xml_path: Optional[str] = None # Path to source CLIP XML file
8689
output_csv_path: Optional[str] = None # Path where CSV signals will be written
@@ -552,6 +555,10 @@ def process_constraints_template(config):
552555
"""
553556
# Define output directory
554557
output_folder = os.path.join(os.getcwd(), "objects", "xdc")
558+
period_content = ""
559+
clip_content = ""
560+
from_to_content = ""
561+
555562
if config.the_window_folder_input is None:
556563
print("TheWindowFolder input is not specified in the configuration.")
557564
else:
@@ -571,7 +578,9 @@ def process_constraints_template(config):
571578
period_pattern = (
572579
r"# BEGIN_LV_FPGA_PERIOD_CONSTRAINTS(.*?)# END_LV_FPGA_PERIOD_CONSTRAINTS"
573580
)
574-
clip_pattern = r"# BEGIN_LV_FPGA_CLIP_CONSTRAINTS(.*?)# END_LV_FPGA_CLIP_CONSTRAINTS"
581+
clip_pattern = (
582+
r"# BEGIN_LV_FPGA_CLIP_CONSTRAINTS(.*?)# END_LV_FPGA_CLIP_CONSTRAINTS"
583+
)
575584
from_to_pattern = (
576585
r"# BEGIN_LV_FPGA_FROM_TO_CONSTRAINTS(.*?)# END_LV_FPGA_FROM_TO_CONSTRAINTS"
577586
)
@@ -760,8 +769,9 @@ def get_invalid_paths_error(invalid_paths):
760769

761770
def generate_guid():
762771
"""Generate a new GUID (UUID4) in standard format.
763-
772+
764773
Returns:
765-
str: A new GUID in lowercase format with hyphens (e.g., '8943868e-fc0c-4e48-a2e9-1ebce7779d5c')
774+
str: A new GUID in lowercase format with hyphens
775+
(e.g., '8943868e-fc0c-4e48-a2e9-1ebce7779d5c')
766776
"""
767777
return str(uuid.uuid4())

labview_fpga_hdl_tools/create_vivado_project.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -653,17 +653,16 @@ def create_project(overwrite=False, update=False, test=False, config_path=None):
653653
# Process the xdc_template to ensure that we have one for the Vivado project
654654
common.process_constraints_template(config)
655655

656-
657656
# Validate that all constraints files exist - do this after processing the templates
658657
try:
659658
_validate_constraints_files(config)
660659
except Exception as e:
661660
print(f"Error: {e}")
662661
return 1
663-
662+
664663
if len(config.window_vhdl_templates) > 0:
665-
# Run (or rerun) generate LV Window VHDL - this is needed to generate TheWindow.vhd that goes
666-
# into the objects directory and which gets used in the Vivado project
664+
# Run (or rerun) generate LV Window VHDL - this is needed to generate TheWindow.vhd that
665+
# goes into the objects directory and which gets used in the Vivado project
667666
try:
668667
gen_labview_target_plugin.gen_window_vhdl(config_path=config_path)
669668
except Exception as e:

labview_fpga_hdl_tools/gen_labview_target_plugin.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,13 @@
5959
}
6060

6161

62+
def _ensure_text(value):
63+
"""Return template output as a text string."""
64+
if isinstance(value, bytes):
65+
return value.decode("utf-8")
66+
return value
67+
68+
6269
def _write_tree_to_xml(root, output_file):
6370
"""Write an XML tree to a formatted XML file.
6471
@@ -422,7 +429,7 @@ def _generate_window_vhdl_from_csv(
422429
# Write output file
423430
os.makedirs(os.path.dirname(output_path), exist_ok=True)
424431
with open(output_path, "w", encoding="utf-8") as f:
425-
f.write(output_text)
432+
f.write(_ensure_text(output_text))
426433

427434
print(f"Generated VHDL file: {output_path}")
428435

@@ -467,7 +474,8 @@ def _generate_target_xml(
467474
clock_filename = os.path.basename(clock_path)
468475

469476
# Calculate min_lv_reg_offset from max_hdl_reg_offset
470-
# Formula: max_hdl_reg_offset + 4 (next 32-bit register), converted to hex with 5 hex digits (0x00000 format)
477+
# Formula: max_hdl_reg_offset + 4 (next 32-bit register), converted to hex with
478+
# 5 hex digits (0x00000 format)
471479
offset_value = max_hdl_reg_offset + 4 if max_hdl_reg_offset is not None else 0
472480
min_lv_reg_offset = f"0x{offset_value:05X}"
473481

@@ -503,7 +511,7 @@ def _generate_target_xml(
503511

504512
# Write output file
505513
with open(current_output_path, "w", encoding="utf-8") as f:
506-
f.write(output_text)
514+
f.write(_ensure_text(output_text))
507515

508516
print(f"Generated Target XML file: {current_output_path}")
509517

labview_fpga_hdl_tools/install_dependencies.py

Lines changed: 36 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,18 @@
88
99
Pre-release handling (--pre flag):
1010
Follows pip's PEP 440 pre-release behavior:
11-
11+
1212
Without --pre:
1313
- Pre-release versions (dev, alpha, beta, rc, etc.) are excluded
1414
- Example: ">=26.0.0" matches only 26.0.0, 26.0.1, etc.
1515
- Example: ">=26.0.0" does NOT match 26.0.0.dev0 (pre-releases come before releases)
16-
16+
1717
With --pre:
1818
- Pre-release versions are included in version resolution
1919
- Example: ">=26.0.0.dev0" matches 26.0.0.dev0, 26.0.0.dev1, 26.0.0, 26.0.1, etc.
2020
- Example: ">=26.0.0" matches 26.0.0, 26.0.1, 26.1.0.dev0, etc.
2121
- Note: 26.0.0.dev0 < 26.0.0 in PEP 440 (pre-releases sort before releases)
22-
22+
2323
Version ordering (PEP 440):
2424
- 25.0.0 < 26.0.0.dev0 < 26.0.0.dev1 < 26.0.0 < 26.0.1
2525
@@ -46,8 +46,8 @@
4646
except ModuleNotFoundError:
4747
import tomli as tomllib # type: ignore[import]
4848

49-
from packaging.version import Version, InvalidVersion
5049
from packaging.specifiers import SpecifierSet
50+
from packaging.version import InvalidVersion, Version
5151

5252

5353
def _remove_readonly(func, path, exc_info):
@@ -58,12 +58,12 @@ def _remove_readonly(func, path, exc_info):
5858

5959
def _normalize_tag(tag):
6060
"""Normalize a git tag to a PEP 440 compliant version string.
61-
61+
6262
Removes 'v' or 'V' prefix to match PEP 440 format.
63-
63+
6464
Args:
6565
tag: Git tag string (e.g., "v26.0.0", "26.0.0.dev3")
66-
66+
6767
Returns:
6868
Normalized version string without 'v' prefix (e.g., "26.0.0", "26.0.0.dev3")
6969
"""
@@ -72,49 +72,49 @@ def _normalize_tag(tag):
7272

7373
def _parse_dependency(dep_string):
7474
"""Parse dependency string with PEP 440 version specifier.
75-
75+
7676
Supports the same specifiers as pip install:
7777
owner/repo==1.2.3 - exact version
7878
owner/repo>=1.2.3 - minimum version
7979
owner/repo<2.0.0 - maximum version
8080
owner/repo~=1.2.3 - compatible release (>=1.2.3, <1.3.0)
81-
81+
8282
Args:
8383
dep_string: Dependency string
84-
84+
8585
Returns:
8686
tuple: (repo, specifier, version) where specifier is one of '==', '>=', '<', '~='
8787
Returns (None, None, None) if parsing fails
8888
"""
8989
# Try each specifier in order of length (longest first to avoid conflicts)
90-
specifiers = ['~=', '>=', '==', '<']
91-
90+
specifiers = ["~=", ">=", "==", "<"]
91+
9292
for spec in specifiers:
9393
if spec in dep_string:
9494
parts = dep_string.split(spec, 1)
9595
if len(parts) == 2:
9696
return parts[0].strip(), spec, parts[1].strip()
97-
97+
9898
return None, None, None
9999

100100

101101
def _filter_tags_by_specifier(tags, specifier, version, allow_prerelease=False):
102102
"""Filter tags based on version specifier using PEP 440.
103-
103+
104104
Uses packaging library for PEP 440 compliance, matching pip install behavior.
105-
105+
106106
Args:
107107
tags: List of tag names
108108
specifier: Version specifier ('==', '>=', '<', '~=')
109109
version: Version string
110110
allow_prerelease: Include pre-release versions (equivalent to pip --pre)
111-
111+
112112
Returns:
113113
Best matching tag, or None if no match
114114
"""
115115
# Create specifier set (PEP 440)
116116
spec_set = SpecifierSet(f"{specifier}{version}", prereleases=allow_prerelease)
117-
117+
118118
# Filter tags that match the specifier
119119
matching_tags = []
120120
for tag in tags:
@@ -126,10 +126,10 @@ def _filter_tags_by_specifier(tags, specifier, version, allow_prerelease=False):
126126
except InvalidVersion:
127127
# Skip tags that aren't valid PEP 440 versions
128128
continue
129-
129+
130130
if not matching_tags:
131131
return None
132-
132+
133133
# Sort by version (highest first) and return the best match
134134
matching_tags.sort(reverse=True, key=lambda x: x[0])
135135
return matching_tags[0][1]
@@ -205,29 +205,31 @@ def _clone_repo_at_tag(repo, tag_or_spec, base_dir, delete_allowed=False, allow_
205205
tag = tag_or_spec
206206
specifier = None
207207
version = None
208-
208+
209209
# Check for version specifiers
210-
for spec in ['~=', '>=', '==', '<']:
210+
for spec in ["~=", ">=", "==", "<"]:
211211
if tag_or_spec.startswith(spec):
212212
specifier = spec
213-
version = tag_or_spec[len(spec):]
213+
version = tag_or_spec[len(spec) :]
214214
break
215-
215+
216216
# Resolve version if specifier is used (or if --latest flag forces "latest")
217217
if specifier or tag_or_spec.lower() == "latest":
218218
if specifier:
219219
print(f"Resolving version {specifier}{version} for {repo}...")
220220
else:
221221
print(f"Resolving latest version for {repo}...")
222-
222+
223223
try:
224224
all_tags = _get_all_tags(repo_url, allow_prerelease)
225225
if not all_tags:
226226
print(f" [FAIL] No tags found in repository {repo}")
227227
return False
228228
else:
229229
if specifier:
230-
matched_tag = _filter_tags_by_specifier(all_tags, specifier, version, allow_prerelease)
230+
matched_tag = _filter_tags_by_specifier(
231+
all_tags, specifier, version, allow_prerelease
232+
)
231233
else:
232234
# "latest" - get the latest tag
233235
valid_tags = []
@@ -238,7 +240,7 @@ def _clone_repo_at_tag(repo, tag_or_spec, base_dir, delete_allowed=False, allow_
238240
continue
239241
valid_tags.sort(reverse=True, key=lambda x: x[0])
240242
matched_tag = valid_tags[0][1] if valid_tags else None
241-
243+
242244
if matched_tag:
243245
print(f" [INFO] Resolved to tag: {matched_tag}")
244246
tag = matched_tag
@@ -376,19 +378,23 @@ def install_dependencies(delete_allowed=False, allow_prerelease=False, use_lates
376378
for dep_string in dependencies:
377379
# Parse the dependency string
378380
repo, specifier, version = _parse_dependency(dep_string)
379-
381+
380382
if repo is None:
381383
print(f"Warning: Invalid dependency format: {dep_string}")
382384
print(f" Expected format: owner/repo==version or owner/repo>=version")
383385
continue
384-
386+
387+
if specifier is None or version is None:
388+
print(f"Warning: Invalid dependency version specifier: {dep_string}")
389+
continue
390+
385391
# Build the tag/version string for cloning
386392
tag_or_spec = specifier + version
387-
393+
388394
# Override with "latest" if --latest flag is used
389395
if use_latest:
390396
tag_or_spec = "latest"
391-
397+
392398
total_count += 1
393399

394400
if _clone_repo_at_tag(repo, tag_or_spec, deps_dir, delete_allowed, allow_prerelease):

0 commit comments

Comments
 (0)