Skip to content

Commit 93d356f

Browse files
[MERGE] Merge branch '769-loadRecordsFromGdx-breaking-change' into 'develop'
Revert the commit that causes a breaking change in the behaviour of... Closes #769 See merge request devel/gamspy!744
2 parents cb08720 + cde2cc2 commit 93d356f

8 files changed

Lines changed: 36 additions & 66 deletions

File tree

changelog/769.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Revert the commit that causes a breaking change in the behaviour of container.loadRecordsFromGdx. If a symbol in the gdx file does not already exist in the container, create it automatically.

ci/.cli.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,8 @@ wei-cli-3.14:
141141
variables:
142142
UV_PYTHON_INSTALL_DIR: "$CI_PROJECT_DIR/.uv_pythons"
143143
script:
144+
- Expand-Archive -Path uv_toolchain.zip -DestinationPath . -Force
145+
- Expand-Archive -Path uv_bin.zip -DestinationPath . -Force
144146
- $env:Path = "$CI_PROJECT_DIR\.uv_bin;$env:Path"
145147
- uv venv .venv --python 3.14
146148
- .venv\Scripts\Activate.ps1
@@ -159,6 +161,8 @@ wei-cli-3.10:
159161
variables:
160162
UV_PYTHON_INSTALL_DIR: "$CI_PROJECT_DIR/.uv_pythons"
161163
script:
164+
- Expand-Archive -Path uv_toolchain.zip -DestinationPath . -Force
165+
- Expand-Archive -Path uv_bin.zip -DestinationPath . -Force
162166
- $env:Path = "$CI_PROJECT_DIR\.uv_bin;$env:Path"
163167
- uv venv .venv --python 3.10
164168
- .venv\Scripts\Activate.ps1

ci/.test-wei.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
variables:
77
UV_PYTHON_INSTALL_DIR: "$CI_PROJECT_DIR/.uv_pythons"
88
script:
9+
- Expand-Archive -Path uv_toolchain.zip -DestinationPath . -Force
10+
- Expand-Archive -Path uv_bin.zip -DestinationPath . -Force
911
- $env:Path = "$CI_PROJECT_DIR\.uv_bin;$env:Path"
1012
- uv venv .venv --python $env:PYTHON_VERSION
1113
- .venv\Scripts\Activate.ps1
@@ -20,6 +22,8 @@ wei-test-3.14:
2022
variables:
2123
PYTHON_VERSION: "3.14"
2224
script:
25+
- Expand-Archive -Path uv_toolchain.zip -DestinationPath . -Force
26+
- Expand-Archive -Path uv_bin.zip -DestinationPath . -Force
2327
- $env:Path = "$CI_PROJECT_DIR\.uv_bin;$env:Path"
2428
- uv venv .venv --python 3.14
2529
- .venv\Scripts\Activate.ps1
@@ -78,6 +82,8 @@ wei-test-3.10:
7882
variables:
7983
UV_PYTHON_INSTALL_DIR: "$CI_PROJECT_DIR/.uv_pythons"
8084
script:
85+
- Expand-Archive -Path uv_toolchain.zip -DestinationPath . -Force
86+
- Expand-Archive -Path uv_bin.zip -DestinationPath . -Force
8187
- $env:Path = "$CI_PROJECT_DIR\.uv_bin;$env:Path"
8288
- uv venv .venv --python $env:PYTHON_VERSION
8389
- .venv\Scripts\Activate.ps1
@@ -104,6 +110,8 @@ wei-engine-3.10:
104110
variables:
105111
UV_PYTHON_INSTALL_DIR: "$CI_PROJECT_DIR/.uv_pythons"
106112
script:
113+
- Expand-Archive -Path uv_toolchain.zip -DestinationPath . -Force
114+
- Expand-Archive -Path uv_bin.zip -DestinationPath . -Force
107115
- $env:Path = "$CI_PROJECT_DIR\.uv_bin;$env:Path"
108116
- uv venv .venv --python $env:PYTHON_VERSION
109117
- .venv\Scripts\Activate.ps1

ci/.toolchain.yml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,13 @@ setup-wei-toolchain:
4949
- $env:Path = "$CI_PROJECT_DIR\.uv_bin;$env:Path"
5050
- echo "Downloading Python toolchain for Windows..."
5151
- uv python install 3.10 3.11 3.12 3.13 3.14
52+
# Compress the folder manually to bypass GitLab Runner's symlink/junction issues
53+
- echo "Compressing toolchain to avoid 'Incorrect function' artifact error..."
54+
- Compress-Archive -Path "$CI_PROJECT_DIR\.uv_pythons" -DestinationPath "$CI_PROJECT_DIR\uv_toolchain.zip" -Force
55+
- Compress-Archive -Path "$CI_PROJECT_DIR\.uv_bin" -DestinationPath "$CI_PROJECT_DIR\uv_bin.zip" -Force
5256
artifacts:
5357
name: "toolchain-windows"
5458
paths:
55-
- .uv_pythons/
56-
- .uv_bin/
59+
- uv_toolchain.zip
60+
- uv_bin.zip
5761
expire_in: 2 hours

src/gamspy/_backend/backend.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -222,9 +222,7 @@ def load_records(self, relaxed_domain_mapping: bool = False):
222222
symbols = filtered_names
223223

224224
if len(symbols) != 0:
225-
self.container._load_records_from_gdx(
226-
self.container._gdx_out, symbols, create_if_not_declared=True
227-
)
225+
self.container._load_records_from_gdx(self.container._gdx_out, symbols)
228226
self.make_unmodified(symbols)
229227

230228
if relaxed_domain_mapping:

src/gamspy/_container.py

Lines changed: 10 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -588,7 +588,6 @@ def _generate_gams_string(
588588
def _filter_load_symbols(
589589
self,
590590
symbol_names: dict[str, str] | list[str],
591-
create_if_not_declared: bool = False,
592591
) -> dict[str, str] | list[str]:
593592
if isinstance(symbol_names, list):
594593
names = []
@@ -598,12 +597,7 @@ def _filter_load_symbols(
598597
if not isinstance(symbol, gt.Alias) and symbol.synchronize:
599598
names.append(name)
600599
else:
601-
if create_if_not_declared:
602-
names.append(name)
603-
else:
604-
raise ValidationError(
605-
f"Cannot load records of `{name}` because it does not exist in the container."
606-
)
600+
names.append(name)
607601

608602
return names
609603

@@ -619,13 +613,7 @@ def _filter_load_symbols(
619613

620614
return mapping
621615

622-
def _load_records_from_gdx(
623-
self,
624-
load_from: str,
625-
names: Iterable[str],
626-
*,
627-
create_if_not_declared: bool = False,
628-
) -> None:
616+
def _load_records_from_gdx(self, load_from: str, names: Iterable[str]) -> None:
629617
self._temp_container.read(load_from, names)
630618
original_state = self._options.miro_protect
631619
self._options.miro_protect = False
@@ -636,12 +624,7 @@ def _load_records_from_gdx(
636624
self[name].records = updated_records
637625
self[name].domain_labels = self[name].domain_names
638626
else:
639-
if create_if_not_declared:
640-
self._read(load_from, [name])
641-
else:
642-
raise ValidationError(
643-
f"Cannot load records of `{name}` because it does not exist in the container."
644-
)
627+
self._read(load_from, [name])
645628

646629
self._options.miro_protect = original_state
647630
self._temp_container.data = {}
@@ -989,54 +972,28 @@ def loadRecordsFromGdx(
989972
if isinstance(load_from, Path):
990973
load_from = str(load_from.resolve())
991974

992-
create_if_not_declared = symbol_names is None
993975
if symbol_names is None:
994976
# If no symbol names are given, all records in the gdx should be loaded
995977
symbol_names = utils._get_symbol_names_from_gdx(
996978
self.system_directory, load_from
997979
)
998980
self._add_statement(f"$declareAndLoad {load_from}")
999-
symbol_names = self._filter_load_symbols(
1000-
symbol_names, # type: ignore
1001-
create_if_not_declared,
1002-
)
1003-
self._load_records_from_gdx(
1004-
load_from, symbol_names, create_if_not_declared=create_if_not_declared
1005-
)
981+
symbol_names = self._filter_load_symbols(symbol_names) # type: ignore
982+
self._load_records_from_gdx(load_from, symbol_names)
1006983
self._synch_with_gams()
1007984
return
1008985

1009-
if isinstance(symbol_names, list):
1010-
symbol_names = self._filter_load_symbols(
1011-
symbol_names, create_if_not_declared
1012-
)
1013-
self._add_statement(f"$gdxIn {load_from}")
1014-
symbols_str = " ".join(symbol_names)
1015-
self._add_statement(f"$loadDC {symbols_str}")
1016-
self._add_statement("$gdxIn")
1017-
elif isinstance(symbol_names, dict):
1018-
symbol_names = self._filter_load_symbols(
1019-
symbol_names, create_if_not_declared
1020-
)
1021-
self._add_statement(f"$gdxIn {load_from}")
1022-
symbols_str = " ".join(
1023-
[f"{value}={key}" for key, value in symbol_names.items()] # type: ignore
1024-
)
1025-
self._add_statement(f"$loadDC {symbols_str}")
1026-
self._add_statement("$gdxIn")
986+
if isinstance(symbol_names, (list, dict)):
987+
symbol_names = self._filter_load_symbols(symbol_names)
1027988
else:
1028989
raise TypeError("`symbol_names` must be either a list or a dictionary.")
1029990

1030-
self._options._debug_options["gdx"] = self._gdx_out
1031-
self._options._debug_options["gdxSymbols"] = "newOrChanged"
1032-
self._synch_with_gams()
1033-
1034991
if isinstance(symbol_names, dict):
1035992
self._load_records_with_rename(load_from, symbol_names)
1036993
else:
1037-
self._load_records_from_gdx(
1038-
load_from, symbol_names, create_if_not_declared=create_if_not_declared
1039-
)
994+
self._load_records_from_gdx(load_from, symbol_names)
995+
996+
self._synch_with_gams()
1040997

1041998
def addGamsCode(self, gams_code: str) -> None:
1042999
"""

src/gamspy/_miro.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,7 @@ def load_miro_symbol_records(container: Container):
4141
for name in container._miro_input_symbols
4242
if not container[name]._already_loaded
4343
]
44-
container._load_records_from_gdx(
45-
MIRO_GDX_IN, names, create_if_not_declared=True
46-
)
44+
container._load_records_from_gdx(MIRO_GDX_IN, names)
4745
for name in names:
4846
symbol = container[name]
4947
symbol._already_loaded = True
@@ -56,9 +54,7 @@ def load_miro_symbol_records(container: Container):
5654

5755
# Load records of miro output symbols
5856
if MIRO_GDX_OUT and container._miro_output_symbols:
59-
container._load_records_from_gdx(
60-
MIRO_GDX_OUT, container._miro_output_symbols, create_if_not_declared=True
61-
)
57+
container._load_records_from_gdx(MIRO_GDX_OUT, container._miro_output_symbols)
6258

6359
for name in container._miro_input_symbols + container._miro_output_symbols:
6460
container[name].modified = False

tests/unit/test_container.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -346,11 +346,13 @@ def test_loadRecordsFromGdxSync(tmp_path):
346346
assert i.records is None, i.records
347347
assert j.toList() == ["0", "1", "2"], j.toList()
348348

349+
# load a symbol that does not exist in the container
349350
m = gp.Container()
350351
i = gp.Set(m, "i")
351352
i.synchronize = False
352-
with pytest.raises(ValidationError):
353-
m.loadRecordsFromGdx(tmp_file, symbol_names=["i", "j"])
353+
m.loadRecordsFromGdx(tmp_file, symbol_names=["i", "j"])
354+
assert list(m.data.keys()) == ["i", "j"]
355+
assert m["j"].toList() == ["0", "1", "2"]
354356

355357
j = gp.Set(m, "j")
356358
m.loadRecordsFromGdx(tmp_file, symbol_names=["i", "j"])

0 commit comments

Comments
 (0)