gamsapi 52.5.0__cp312-cp312-win_amd64.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.
- gams/__init__.py +27 -0
- gams/_version.py +1 -0
- gams/connect/__init__.py +28 -0
- gams/connect/agents/__init__.py +24 -0
- gams/connect/agents/_excel/__init__.py +32 -0
- gams/connect/agents/_excel/excelagent.py +312 -0
- gams/connect/agents/_excel/workbook.py +155 -0
- gams/connect/agents/_sqlconnectors/__init__.py +42 -0
- gams/connect/agents/_sqlconnectors/_accesshandler.py +211 -0
- gams/connect/agents/_sqlconnectors/_databasehandler.py +250 -0
- gams/connect/agents/_sqlconnectors/_mysqlhandler.py +168 -0
- gams/connect/agents/_sqlconnectors/_postgreshandler.py +131 -0
- gams/connect/agents/_sqlconnectors/_pyodbchandler.py +112 -0
- gams/connect/agents/_sqlconnectors/_sqlalchemyhandler.py +74 -0
- gams/connect/agents/_sqlconnectors/_sqlitehandler.py +262 -0
- gams/connect/agents/_sqlconnectors/_sqlserverhandler.py +179 -0
- gams/connect/agents/concatenate.py +440 -0
- gams/connect/agents/connectagent.py +743 -0
- gams/connect/agents/csvreader.py +675 -0
- gams/connect/agents/csvwriter.py +151 -0
- gams/connect/agents/domainwriter.py +143 -0
- gams/connect/agents/excelreader.py +756 -0
- gams/connect/agents/excelwriter.py +467 -0
- gams/connect/agents/filter.py +223 -0
- gams/connect/agents/gamsreader.py +112 -0
- gams/connect/agents/gamswriter.py +239 -0
- gams/connect/agents/gdxreader.py +109 -0
- gams/connect/agents/gdxwriter.py +146 -0
- gams/connect/agents/labelmanipulator.py +303 -0
- gams/connect/agents/projection.py +539 -0
- gams/connect/agents/pythoncode.py +71 -0
- gams/connect/agents/rawcsvreader.py +248 -0
- gams/connect/agents/rawexcelreader.py +312 -0
- gams/connect/agents/schema/CSVReader.yaml +92 -0
- gams/connect/agents/schema/CSVWriter.yaml +44 -0
- gams/connect/agents/schema/Concatenate.yaml +52 -0
- gams/connect/agents/schema/DomainWriter.yaml +25 -0
- gams/connect/agents/schema/ExcelReader.yaml +121 -0
- gams/connect/agents/schema/ExcelWriter.yaml +78 -0
- gams/connect/agents/schema/Filter.yaml +74 -0
- gams/connect/agents/schema/GAMSReader.yaml +20 -0
- gams/connect/agents/schema/GAMSWriter.yaml +47 -0
- gams/connect/agents/schema/GDXReader.yaml +23 -0
- gams/connect/agents/schema/GDXWriter.yaml +32 -0
- gams/connect/agents/schema/LabelManipulator.yaml +99 -0
- gams/connect/agents/schema/Projection.yaml +24 -0
- gams/connect/agents/schema/PythonCode.yaml +6 -0
- gams/connect/agents/schema/RawCSVReader.yaml +34 -0
- gams/connect/agents/schema/RawExcelReader.yaml +42 -0
- gams/connect/agents/schema/SQLReader.yaml +75 -0
- gams/connect/agents/schema/SQLWriter.yaml +103 -0
- gams/connect/agents/sqlreader.py +301 -0
- gams/connect/agents/sqlwriter.py +276 -0
- gams/connect/connectdatabase.py +275 -0
- gams/connect/connectvalidator.py +93 -0
- gams/connect/errors.py +34 -0
- gams/control/__init__.py +136 -0
- gams/control/database.py +2231 -0
- gams/control/execution.py +1900 -0
- gams/control/options.py +2792 -0
- gams/control/workspace.py +1198 -0
- gams/core/__init__.py +24 -0
- gams/core/cfg/__init__.py +26 -0
- gams/core/cfg/_cfgmcc.cp312-win_amd64.pyd +0 -0
- gams/core/cfg/cfgmcc.py +519 -0
- gams/core/dct/__init__.py +26 -0
- gams/core/dct/_dctmcc.cp312-win_amd64.pyd +0 -0
- gams/core/dct/dctmcc.py +574 -0
- gams/core/embedded/__init__.py +26 -0
- gams/core/embedded/gamsemb.py +1024 -0
- gams/core/emp/__init__.py +24 -0
- gams/core/emp/emplexer.py +89 -0
- gams/core/emp/empyacc.py +281 -0
- gams/core/gdx/__init__.py +26 -0
- gams/core/gdx/_gdxcc.cp312-win_amd64.pyd +0 -0
- gams/core/gdx/gdxcc.py +866 -0
- gams/core/gev/__init__.py +26 -0
- gams/core/gev/_gevmcc.cp312-win_amd64.pyd +0 -0
- gams/core/gev/gevmcc.py +855 -0
- gams/core/gmd/__init__.py +26 -0
- gams/core/gmd/_gmdcc.cp312-win_amd64.pyd +0 -0
- gams/core/gmd/gmdcc.py +917 -0
- gams/core/gmo/__init__.py +26 -0
- gams/core/gmo/_gmomcc.cp312-win_amd64.pyd +0 -0
- gams/core/gmo/gmomcc.py +2046 -0
- gams/core/idx/__init__.py +26 -0
- gams/core/idx/_idxcc.cp312-win_amd64.pyd +0 -0
- gams/core/idx/idxcc.py +510 -0
- gams/core/numpy/__init__.py +29 -0
- gams/core/numpy/_gams2numpy.cp312-win_amd64.pyd +0 -0
- gams/core/numpy/gams2numpy.py +1048 -0
- gams/core/opt/__init__.py +26 -0
- gams/core/opt/_optcc.cp312-win_amd64.pyd +0 -0
- gams/core/opt/optcc.py +840 -0
- gams/engine/__init__.py +204 -0
- gams/engine/api/__init__.py +13 -0
- gams/engine/api/auth_api.py +7653 -0
- gams/engine/api/cleanup_api.py +751 -0
- gams/engine/api/default_api.py +887 -0
- gams/engine/api/hypercube_api.py +2629 -0
- gams/engine/api/jobs_api.py +5229 -0
- gams/engine/api/licenses_api.py +2220 -0
- gams/engine/api/namespaces_api.py +7783 -0
- gams/engine/api/usage_api.py +5627 -0
- gams/engine/api/users_api.py +5931 -0
- gams/engine/api_client.py +804 -0
- gams/engine/api_response.py +21 -0
- gams/engine/configuration.py +601 -0
- gams/engine/exceptions.py +216 -0
- gams/engine/models/__init__.py +86 -0
- gams/engine/models/bad_input.py +89 -0
- gams/engine/models/cleanable_job_result.py +104 -0
- gams/engine/models/cleanable_job_result_page.py +113 -0
- gams/engine/models/engine_license.py +107 -0
- gams/engine/models/files_not_found.py +93 -0
- gams/engine/models/forwarded_token_response.py +112 -0
- gams/engine/models/generic_key_value_pair.py +89 -0
- gams/engine/models/hypercube.py +160 -0
- gams/engine/models/hypercube_page.py +111 -0
- gams/engine/models/hypercube_summary.py +91 -0
- gams/engine/models/hypercube_token.py +97 -0
- gams/engine/models/identity_provider.py +107 -0
- gams/engine/models/identity_provider_ldap.py +121 -0
- gams/engine/models/identity_provider_oauth2.py +146 -0
- gams/engine/models/identity_provider_oauth2_scope.py +89 -0
- gams/engine/models/identity_provider_oauth2_with_secret.py +152 -0
- gams/engine/models/identity_provider_oidc.py +133 -0
- gams/engine/models/identity_provider_oidc_with_secret.py +143 -0
- gams/engine/models/inex.py +91 -0
- gams/engine/models/invitation.py +136 -0
- gams/engine/models/invitation_quota.py +106 -0
- gams/engine/models/invitation_token.py +87 -0
- gams/engine/models/job.py +165 -0
- gams/engine/models/job_no_text_entry.py +138 -0
- gams/engine/models/job_no_text_entry_page.py +111 -0
- gams/engine/models/license.py +91 -0
- gams/engine/models/log_piece.py +96 -0
- gams/engine/models/message.py +87 -0
- gams/engine/models/message_and_token.py +99 -0
- gams/engine/models/message_with_webhook_id.py +89 -0
- gams/engine/models/model_auth_token.py +87 -0
- gams/engine/models/model_configuration.py +125 -0
- gams/engine/models/model_default_instance.py +99 -0
- gams/engine/models/model_default_user_instance.py +98 -0
- gams/engine/models/model_hypercube_job.py +106 -0
- gams/engine/models/model_hypercube_usage.py +130 -0
- gams/engine/models/model_instance_info.py +116 -0
- gams/engine/models/model_instance_info_full.py +123 -0
- gams/engine/models/model_instance_pool_info.py +112 -0
- gams/engine/models/model_job_labels.py +179 -0
- gams/engine/models/model_job_usage.py +133 -0
- gams/engine/models/model_pool_usage.py +124 -0
- gams/engine/models/model_usage.py +115 -0
- gams/engine/models/model_user.py +96 -0
- gams/engine/models/model_userinstance_info.py +119 -0
- gams/engine/models/model_userinstancepool_info.py +95 -0
- gams/engine/models/model_version.py +91 -0
- gams/engine/models/models.py +120 -0
- gams/engine/models/namespace.py +104 -0
- gams/engine/models/namespace_quota.py +96 -0
- gams/engine/models/namespace_with_permission.py +96 -0
- gams/engine/models/not_found.py +91 -0
- gams/engine/models/password_policy.py +97 -0
- gams/engine/models/perm_and_username.py +89 -0
- gams/engine/models/quota.py +117 -0
- gams/engine/models/quota_exceeded.py +97 -0
- gams/engine/models/status_code_meaning.py +89 -0
- gams/engine/models/stream_entry.py +89 -0
- gams/engine/models/system_wide_license.py +92 -0
- gams/engine/models/text_entries.py +87 -0
- gams/engine/models/text_entry.py +101 -0
- gams/engine/models/time_span.py +95 -0
- gams/engine/models/time_span_pool_worker.py +99 -0
- gams/engine/models/token_forward_error.py +87 -0
- gams/engine/models/user.py +127 -0
- gams/engine/models/user_group_member.py +96 -0
- gams/engine/models/user_groups.py +108 -0
- gams/engine/models/vapid_info.py +87 -0
- gams/engine/models/webhook.py +138 -0
- gams/engine/models/webhook_parameterized_event.py +99 -0
- gams/engine/py.typed +0 -0
- gams/engine/rest.py +258 -0
- gams/magic/__init__.py +32 -0
- gams/magic/gams_magic.py +142 -0
- gams/magic/interactive.py +402 -0
- gams/tools/__init__.py +30 -0
- gams/tools/errors.py +34 -0
- gams/tools/toolcollection/__init__.py +24 -0
- gams/tools/toolcollection/alg/__init__.py +24 -0
- gams/tools/toolcollection/alg/rank.py +51 -0
- gams/tools/toolcollection/data/__init__.py +24 -0
- gams/tools/toolcollection/data/csvread.py +444 -0
- gams/tools/toolcollection/data/csvwrite.py +311 -0
- gams/tools/toolcollection/data/exceldump.py +47 -0
- gams/tools/toolcollection/data/sqlitewrite.py +276 -0
- gams/tools/toolcollection/gdxservice/__init__.py +24 -0
- gams/tools/toolcollection/gdxservice/gdxencoding.py +104 -0
- gams/tools/toolcollection/gdxservice/gdxrename.py +94 -0
- gams/tools/toolcollection/linalg/__init__.py +24 -0
- gams/tools/toolcollection/linalg/cholesky.py +57 -0
- gams/tools/toolcollection/linalg/eigenvalue.py +56 -0
- gams/tools/toolcollection/linalg/eigenvector.py +58 -0
- gams/tools/toolcollection/linalg/invert.py +55 -0
- gams/tools/toolcollection/linalg/ols.py +138 -0
- gams/tools/toolcollection/tooltemplate.py +321 -0
- gams/tools/toolcollection/win32/__init__.py +24 -0
- gams/tools/toolcollection/win32/excelmerge.py +93 -0
- gams/tools/toolcollection/win32/exceltalk.py +76 -0
- gams/tools/toolcollection/win32/msappavail.py +49 -0
- gams/tools/toolcollection/win32/shellexecute.py +54 -0
- gams/tools/tools.py +116 -0
- gams/transfer/__init__.py +35 -0
- gams/transfer/_abcs/__init__.py +37 -0
- gams/transfer/_abcs/container_abcs.py +433 -0
- gams/transfer/_internals/__init__.py +63 -0
- gams/transfer/_internals/algorithms.py +436 -0
- gams/transfer/_internals/casepreservingdict.py +124 -0
- gams/transfer/_internals/constants.py +270 -0
- gams/transfer/_internals/domainviolation.py +103 -0
- gams/transfer/_internals/specialvalues.py +172 -0
- gams/transfer/containers/__init__.py +26 -0
- gams/transfer/containers/_container.py +1794 -0
- gams/transfer/containers/_io/__init__.py +28 -0
- gams/transfer/containers/_io/containers.py +164 -0
- gams/transfer/containers/_io/gdx.py +1029 -0
- gams/transfer/containers/_io/gmd.py +872 -0
- gams/transfer/containers/_mixins/__init__.py +26 -0
- gams/transfer/containers/_mixins/ccc.py +1274 -0
- gams/transfer/syms/__init__.py +33 -0
- gams/transfer/syms/_methods/__init__.py +24 -0
- gams/transfer/syms/_methods/tables.py +120 -0
- gams/transfer/syms/_methods/toDict.py +115 -0
- gams/transfer/syms/_methods/toList.py +83 -0
- gams/transfer/syms/_methods/toValue.py +60 -0
- gams/transfer/syms/_mixins/__init__.py +32 -0
- gams/transfer/syms/_mixins/equals.py +626 -0
- gams/transfer/syms/_mixins/generateRecords.py +499 -0
- gams/transfer/syms/_mixins/pivot.py +313 -0
- gams/transfer/syms/_mixins/pve.py +627 -0
- gams/transfer/syms/_mixins/sa.py +27 -0
- gams/transfer/syms/_mixins/sapve.py +27 -0
- gams/transfer/syms/_mixins/saua.py +27 -0
- gams/transfer/syms/_mixins/sauapve.py +199 -0
- gams/transfer/syms/_mixins/spve.py +1528 -0
- gams/transfer/syms/_mixins/ve.py +936 -0
- gams/transfer/syms/container_syms/__init__.py +31 -0
- gams/transfer/syms/container_syms/_alias.py +984 -0
- gams/transfer/syms/container_syms/_equation.py +333 -0
- gams/transfer/syms/container_syms/_parameter.py +973 -0
- gams/transfer/syms/container_syms/_set.py +604 -0
- gams/transfer/syms/container_syms/_universe_alias.py +461 -0
- gams/transfer/syms/container_syms/_variable.py +321 -0
- gamsapi-52.5.0.dist-info/METADATA +150 -0
- gamsapi-52.5.0.dist-info/RECORD +257 -0
- gamsapi-52.5.0.dist-info/WHEEL +5 -0
- gamsapi-52.5.0.dist-info/licenses/LICENSE +22 -0
- gamsapi-52.5.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,743 @@
|
|
|
1
|
+
#
|
|
2
|
+
# GAMS - General Algebraic Modeling System Python API
|
|
3
|
+
#
|
|
4
|
+
# Copyright (c) 2017-2026 GAMS Development Corp. <support@gams.com>
|
|
5
|
+
# Copyright (c) 2017-2026 GAMS Software GmbH <support@gams.com>
|
|
6
|
+
#
|
|
7
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
9
|
+
# in the Software without restriction, including without limitation the rights
|
|
10
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
12
|
+
# furnished to do so, subject to the following conditions:
|
|
13
|
+
#
|
|
14
|
+
# The above copyright notice and this permission notice shall be included in all
|
|
15
|
+
# copies or substantial portions of the Software.
|
|
16
|
+
#
|
|
17
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
23
|
+
# SOFTWARE.
|
|
24
|
+
#
|
|
25
|
+
|
|
26
|
+
from __future__ import annotations
|
|
27
|
+
|
|
28
|
+
from typing import TYPE_CHECKING
|
|
29
|
+
|
|
30
|
+
if TYPE_CHECKING:
|
|
31
|
+
from gams.connect.connectdatabase import ConnectDatabase
|
|
32
|
+
|
|
33
|
+
from abc import ABC, abstractmethod
|
|
34
|
+
import importlib.resources
|
|
35
|
+
import sys
|
|
36
|
+
import yaml
|
|
37
|
+
from gams.connect.connectvalidator import ConnectValidator
|
|
38
|
+
from gams.connect.errors import GamsConnectException
|
|
39
|
+
import pandas as pd
|
|
40
|
+
import numpy as np
|
|
41
|
+
import gams.transfer as gt
|
|
42
|
+
from gams.transfer._internals import generate_unique_labels
|
|
43
|
+
from gams import GamsWorkspace
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class ConnectAgent(ABC):
|
|
47
|
+
"""
|
|
48
|
+
An abstract base class that defines the structure for Connect agent implementations.
|
|
49
|
+
|
|
50
|
+
Subclasses must implement the abstract methods to define their own behavior.
|
|
51
|
+
This class provides a common interface and some shared functionality.
|
|
52
|
+
|
|
53
|
+
Parameters
|
|
54
|
+
----------
|
|
55
|
+
cdb : gams.connect.connectdatabase.ConnectDatabase.
|
|
56
|
+
The Connect Database responsible for the Connect agent.
|
|
57
|
+
inst : dict
|
|
58
|
+
A nested data structure consisting of dictionaries and lists containing the instructions to be executed by the Connect agent.
|
|
59
|
+
|
|
60
|
+
Abstract methods:
|
|
61
|
+
- __init__: Connect agent constructor.
|
|
62
|
+
- execute: Called by the ConnectDatabase after open() and before close().
|
|
63
|
+
|
|
64
|
+
Non-abstract methods:
|
|
65
|
+
- _apply_value_substitutions: Substitutes values in the last column of df as provided in value_subs and returns the modified DataFrame.
|
|
66
|
+
- _connect_error: Raises a GamsConnectException.
|
|
67
|
+
- _describe_container: Logs the status of a gams.transfer.Container.
|
|
68
|
+
- _dict_get: Like dict.get() but handles keys with None value as if they were missing.
|
|
69
|
+
- _log_instructions: Logs raw and processed instructions in a table format.
|
|
70
|
+
- _normalize_instructions: Performs normalization of the given instructions.
|
|
71
|
+
- _pandas_version_before: Checks if the installed pandas version is before the given version string x.y.
|
|
72
|
+
- _sym_records_no_none: Returns the records of a symbol or an empty DataFrame with appropriate column names for None records.
|
|
73
|
+
- _transform_sym_none_to_empty: Sets the records of a symbol to an empty DataFrame with appropriate column names if the given records are None.
|
|
74
|
+
- _update_sym_inst: Updates None values in the symbols scope instructions with the corresponding values from the root scope for all keys that exist in both instruction dictionaries.
|
|
75
|
+
- _symbols_exist_gmd: Raises a GamsConnectException if a single symbol or at least one symbol of a given list of symbols does not exist in the GMD object.
|
|
76
|
+
- _symbols_exist_gdx: Raises a GamsConnectException if a single symbol or at least one symbol of a given list of symbols does not exist in the GDX file.
|
|
77
|
+
- _symbols_exist_cdb: Checks the Connect database for existing symbols and raises a GamsConnectException depending on parameter should_exist.
|
|
78
|
+
- _log_instructions_r: Recursive helper method for instruction logging.
|
|
79
|
+
- _replace_no_warn: Helper method for _apply_value_substitutions().
|
|
80
|
+
"""
|
|
81
|
+
|
|
82
|
+
@abstractmethod
|
|
83
|
+
def __init__(self, cdb: ConnectDatabase, inst, agent_index):
|
|
84
|
+
self._agent_index = agent_index
|
|
85
|
+
self._agent_name = self.__class__.__name__
|
|
86
|
+
self._col_widths = [30, 30, 30]
|
|
87
|
+
self._no_option_list = [
|
|
88
|
+
"connection",
|
|
89
|
+
"connectionArguments",
|
|
90
|
+
"dimensionMap",
|
|
91
|
+
"dTypeMap",
|
|
92
|
+
"indexSubstitutions",
|
|
93
|
+
"readCSVArguments",
|
|
94
|
+
"readSQLArguments",
|
|
95
|
+
"toCSVArguments",
|
|
96
|
+
"toSQLArguments",
|
|
97
|
+
"valueSubstitutions",
|
|
98
|
+
]
|
|
99
|
+
self._system_directory = cdb.system_directory
|
|
100
|
+
self._cdb = cdb
|
|
101
|
+
self._trace = 0
|
|
102
|
+
self._inst_raw = inst
|
|
103
|
+
self._inst = self._normalize_instructions(inst)
|
|
104
|
+
|
|
105
|
+
def _normalize_instructions(self, inst):
|
|
106
|
+
"""
|
|
107
|
+
Performs normalization of the given instructions.
|
|
108
|
+
|
|
109
|
+
Parameters
|
|
110
|
+
----------
|
|
111
|
+
inst : dict
|
|
112
|
+
The instructions to be normalized.
|
|
113
|
+
|
|
114
|
+
Returns
|
|
115
|
+
-------
|
|
116
|
+
dict
|
|
117
|
+
The normalized instructions.
|
|
118
|
+
"""
|
|
119
|
+
v = ConnectValidator(self._cdb.load_schema(self))
|
|
120
|
+
inst = v.normalized(inst)
|
|
121
|
+
inst = v.normalize_of_rules(inst)
|
|
122
|
+
return inst
|
|
123
|
+
|
|
124
|
+
def _log_instructions_r(
|
|
125
|
+
self, inst, has_inst_raw, inst_raw=None, level=0, is_list=False, no_option=False
|
|
126
|
+
):
|
|
127
|
+
"""
|
|
128
|
+
Recursive helper method for instruction logging.
|
|
129
|
+
|
|
130
|
+
Parameters
|
|
131
|
+
----------
|
|
132
|
+
inst : dict
|
|
133
|
+
The normalized/processed instructions.
|
|
134
|
+
has_inst_raw : bool
|
|
135
|
+
Flag indicating if raw instructions has been passed to _log_instructions().
|
|
136
|
+
inst_raw : dict, optional
|
|
137
|
+
The raw instructions, by default None.
|
|
138
|
+
level : int, optional
|
|
139
|
+
Level used for log indentation where one level corresponds to two spaces, by default 0.
|
|
140
|
+
is_list : bool, optional
|
|
141
|
+
Flag indicating if the current item is part of a list, by default False.
|
|
142
|
+
no_option : bool
|
|
143
|
+
Flag indicating if an item should be treated as a Connect agent option or as a generic data structure, by default False.
|
|
144
|
+
"""
|
|
145
|
+
istr = " " * level * 2
|
|
146
|
+
self._cdb.print_log("")
|
|
147
|
+
if is_list:
|
|
148
|
+
iterable = enumerate(inst)
|
|
149
|
+
format_key = lambda idx: f"{istr}({idx+1})"
|
|
150
|
+
get_raw_value = lambda idx: inst_raw[idx] if inst_raw else None
|
|
151
|
+
else:
|
|
152
|
+
iterable = inst.items()
|
|
153
|
+
format_key = lambda k: f"{istr}{k}: "
|
|
154
|
+
get_raw_value = lambda k: (
|
|
155
|
+
inst_raw.get(k, "") if isinstance(inst_raw, dict) else inst_raw
|
|
156
|
+
)
|
|
157
|
+
for k, v in iterable:
|
|
158
|
+
s_option = "" if no_option else format_key(k)
|
|
159
|
+
self._cdb.print_log(f"{s_option:<{self._col_widths[0]}}", end="")
|
|
160
|
+
v_raw = get_raw_value(k)
|
|
161
|
+
if isinstance(v, dict) and len(v) > 0:
|
|
162
|
+
if not isinstance(v_raw, dict) and has_inst_raw:
|
|
163
|
+
self._cdb.print_log(f">{v_raw}<", end="")
|
|
164
|
+
if k in self._no_option_list:
|
|
165
|
+
self._log_instructions_r(
|
|
166
|
+
v, has_inst_raw, v_raw, level + 1, no_option=True
|
|
167
|
+
)
|
|
168
|
+
else:
|
|
169
|
+
self._log_instructions_r(v, has_inst_raw, v_raw, level + 1)
|
|
170
|
+
elif isinstance(v, list) and len(v) > 0:
|
|
171
|
+
self._log_instructions_r(
|
|
172
|
+
v, has_inst_raw, v_raw, level + 1, is_list=True
|
|
173
|
+
)
|
|
174
|
+
else:
|
|
175
|
+
if no_option:
|
|
176
|
+
s_input = f">{k}<: >{v_raw}<" if inst_raw else ""
|
|
177
|
+
s_processed = f">{k}<: >{v}<"
|
|
178
|
+
else:
|
|
179
|
+
s_input = f">{v_raw}<" if isinstance(inst_raw, (dict, list)) else ""
|
|
180
|
+
s_processed = f">{v}<"
|
|
181
|
+
if has_inst_raw:
|
|
182
|
+
self._cdb.print_log(
|
|
183
|
+
f"{s_input:<{self._col_widths[1]}}{s_processed}"
|
|
184
|
+
)
|
|
185
|
+
else:
|
|
186
|
+
self._cdb.print_log(f"{s_processed}")
|
|
187
|
+
|
|
188
|
+
def _log_instructions(self, inst, inst_raw=None, description=None):
|
|
189
|
+
"""
|
|
190
|
+
Logs raw and processed instructions in a table format. If inst_raw is
|
|
191
|
+
None, only the instructions given in inst are printed to the log.
|
|
192
|
+
|
|
193
|
+
Parameters
|
|
194
|
+
----------
|
|
195
|
+
inst : dict
|
|
196
|
+
The normalized/processed instructions.
|
|
197
|
+
inst_raw : dict, optional
|
|
198
|
+
The raw instructions, by default None.
|
|
199
|
+
description : str, optional
|
|
200
|
+
A describtion to be printed to the table header or the Connect agent class if omitted, by default None.
|
|
201
|
+
"""
|
|
202
|
+
|
|
203
|
+
if description is None:
|
|
204
|
+
agent_info = self._cdb._get_idx_str(self._agent_name, self._agent_index)
|
|
205
|
+
description = f"{agent_info}:"
|
|
206
|
+
|
|
207
|
+
header = f"{'Option':<{self._col_widths[0]}}"
|
|
208
|
+
ruler = (
|
|
209
|
+
"-" * sum(self._col_widths[:2])
|
|
210
|
+
if inst_raw is None
|
|
211
|
+
else "-" * sum(self._col_widths)
|
|
212
|
+
)
|
|
213
|
+
if inst_raw is not None:
|
|
214
|
+
header += f"{'Input':<{self._col_widths[1]}}"
|
|
215
|
+
header += "Processed Input"
|
|
216
|
+
self._cdb.print_log("")
|
|
217
|
+
self._cdb.print_log(ruler)
|
|
218
|
+
self._cdb.print_log(f"{description}")
|
|
219
|
+
self._cdb.print_log(header)
|
|
220
|
+
self._cdb.print_log(ruler, end="")
|
|
221
|
+
|
|
222
|
+
if isinstance(inst, dict):
|
|
223
|
+
self._log_instructions_r(inst, inst_raw is not None, inst_raw)
|
|
224
|
+
else:
|
|
225
|
+
self._cdb.print_log(
|
|
226
|
+
f"Warning: Can not log instructions because type was not 'dict' but {type(inst).__name__}."
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
self._cdb.print_log(ruler + "\n")
|
|
230
|
+
|
|
231
|
+
def _connect_error(self, msg, agent_info=True):
|
|
232
|
+
"""
|
|
233
|
+
Raises a GamsConnectException.
|
|
234
|
+
|
|
235
|
+
Parameters
|
|
236
|
+
----------
|
|
237
|
+
msg : str
|
|
238
|
+
Message for the exception.
|
|
239
|
+
agent_info : bool
|
|
240
|
+
Add agent name and index to the exception, by default True.
|
|
241
|
+
|
|
242
|
+
Raises
|
|
243
|
+
----------
|
|
244
|
+
GamsConnectException
|
|
245
|
+
Always.
|
|
246
|
+
"""
|
|
247
|
+
if agent_info:
|
|
248
|
+
agent_info = self._cdb._get_idx_str(self._agent_name, self._agent_index)
|
|
249
|
+
msg = f"{agent_info} failed: " + msg
|
|
250
|
+
raise GamsConnectException(msg, traceback=self._trace > 0)
|
|
251
|
+
|
|
252
|
+
def _describe_container(self, m, msg):
|
|
253
|
+
"""
|
|
254
|
+
Logs the status of a gams.transfer.Container
|
|
255
|
+
|
|
256
|
+
Parameters
|
|
257
|
+
----------
|
|
258
|
+
m : gams.transfer.Container
|
|
259
|
+
The Container to be used.
|
|
260
|
+
msg : str
|
|
261
|
+
A custom message to be printed to the log.
|
|
262
|
+
"""
|
|
263
|
+
try:
|
|
264
|
+
with pd.option_context("display.max_columns", None):
|
|
265
|
+
self._cdb.print_log(f"{msg}\n")
|
|
266
|
+
if len(m.listSets()):
|
|
267
|
+
self._cdb.print_log(f"Sets:\n{ m.describeSets() }\n")
|
|
268
|
+
if len(m.listAliases()):
|
|
269
|
+
self._cdb.print_log(f"Aliases:\n{ m.describeAliases() }\n")
|
|
270
|
+
if len(m.listParameters()):
|
|
271
|
+
self._cdb.print_log(f"Parameters:\n{m.describeParameters()}\n")
|
|
272
|
+
if len(m.listEquations()):
|
|
273
|
+
self._cdb.print_log(f"Equations:\n{ m.describeEquations() }\n")
|
|
274
|
+
if len(m.listVariables()):
|
|
275
|
+
self._cdb.print_log(f"Variables:\n{ m.describeVariables() }\n")
|
|
276
|
+
except Exception as e:
|
|
277
|
+
self._cdb.print_log(
|
|
278
|
+
f"Exception in ConnectDatabase._describe_container turned into warning: {e}\n"
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
def _pandas_version_before(self, pandas_version, version_string):
|
|
282
|
+
"""
|
|
283
|
+
Checks if the installed pandas version is before the given version string x.y.
|
|
284
|
+
|
|
285
|
+
Parameters
|
|
286
|
+
----------
|
|
287
|
+
pandas_version : str
|
|
288
|
+
Installed pandas version.
|
|
289
|
+
version_string : str
|
|
290
|
+
Pandas version to check agains in the format x.y.
|
|
291
|
+
|
|
292
|
+
Returns
|
|
293
|
+
----------
|
|
294
|
+
bool
|
|
295
|
+
True if pandas version is before version string and otherwise False.
|
|
296
|
+
"""
|
|
297
|
+
pd_ver = list(map(int, pandas_version.split(".")))
|
|
298
|
+
ver = list(map(int, version_string.split(".")))
|
|
299
|
+
if pd_ver[0] < ver[0] or (pd_ver[0] == ver[0] and pd_ver[1] < ver[1]):
|
|
300
|
+
return True
|
|
301
|
+
return False
|
|
302
|
+
|
|
303
|
+
def _transform_sym_none_to_empty(self, sym):
|
|
304
|
+
"""
|
|
305
|
+
Sets the records of a symbol to an empty DataFrame
|
|
306
|
+
with appropriate column names if the given records are None.
|
|
307
|
+
|
|
308
|
+
Parameters
|
|
309
|
+
----------
|
|
310
|
+
sym : gams.transfer.Alias, gams.transfer.Equation, gams.transfer.Parameter, gams.transfer.Set, gams.transfer.Variable
|
|
311
|
+
Symbol to be checked for None records.
|
|
312
|
+
"""
|
|
313
|
+
if sym.records is None:
|
|
314
|
+
sym.setRecords(self._sym_records_no_none(sym, False))
|
|
315
|
+
|
|
316
|
+
def _sym_records_no_none(self, sym, set_dtypes=True):
|
|
317
|
+
"""
|
|
318
|
+
Returns the records of a symbol or an empty DataFrame
|
|
319
|
+
with appropriate column names for None records.
|
|
320
|
+
|
|
321
|
+
Parameters
|
|
322
|
+
----------
|
|
323
|
+
sym : gams.transfer.Alias, gams.transfer.Equation, gams.transfer.Parameter, gams.transfer.Set, gams.transfer.Variable
|
|
324
|
+
Symbol to be checked for None records.
|
|
325
|
+
set_dtypes : bool, optional
|
|
326
|
+
Sets gams.transfer-like column types if True, by default True.
|
|
327
|
+
|
|
328
|
+
Returns
|
|
329
|
+
----------
|
|
330
|
+
pandas.DataFrame
|
|
331
|
+
The DataFrame of the symbol if records are not None, otherwise an empty DataFrame.
|
|
332
|
+
"""
|
|
333
|
+
if sym.records is None:
|
|
334
|
+
attributes = sym._attributes
|
|
335
|
+
cols = generate_unique_labels(sym.domain_names) + attributes
|
|
336
|
+
df = pd.DataFrame(columns=cols)
|
|
337
|
+
if set_dtypes: # set column dtypes as gams.transfer would do
|
|
338
|
+
for col in cols[: sym.dimension]:
|
|
339
|
+
df[col] = df[col].astype("category")
|
|
340
|
+
if isinstance(sym, (gt.Parameter, gt.Variable, gt.Equation)):
|
|
341
|
+
for col in attributes:
|
|
342
|
+
df[col] = df[col].astype(float)
|
|
343
|
+
elif isinstance(
|
|
344
|
+
sym, gt.UniverseAlias
|
|
345
|
+
): # nothing to do for UniverseAlias
|
|
346
|
+
pass
|
|
347
|
+
else: # sets, alias
|
|
348
|
+
df[attributes[0]] = df[attributes[0]].astype(object)
|
|
349
|
+
else:
|
|
350
|
+
df = sym.records
|
|
351
|
+
return df
|
|
352
|
+
|
|
353
|
+
def _replace_no_warn(self, df, vs, mask=None):
|
|
354
|
+
"""
|
|
355
|
+
Helper method for _apply_value_substitutions(). Substitutes values in the last column of df
|
|
356
|
+
as provided in vs and returns the modified DataFrame.
|
|
357
|
+
|
|
358
|
+
Parameters
|
|
359
|
+
----------
|
|
360
|
+
df : pandas.DataFrame
|
|
361
|
+
The DataFrame to be used for replacing values in its last column.
|
|
362
|
+
vs : dict
|
|
363
|
+
Dictionary containing the keys that will be replaced by their values.
|
|
364
|
+
mask : numpy.ndarray, optional
|
|
365
|
+
A numpy mask that can be used to exclude certain value positions from the substitution, by default None.
|
|
366
|
+
|
|
367
|
+
Returns
|
|
368
|
+
----------
|
|
369
|
+
pandas.DataFrame
|
|
370
|
+
The DataFrame with the replaced values.
|
|
371
|
+
"""
|
|
372
|
+
if vs and len(vs) > 0:
|
|
373
|
+
if df[df.columns[-1]].dtype != object and any(
|
|
374
|
+
isinstance(v, str) for v in vs.values()
|
|
375
|
+
):
|
|
376
|
+
for k, v in vs.items():
|
|
377
|
+
if isinstance(v, str) and k in df[df.columns[-1]].values:
|
|
378
|
+
df[df.columns[-1]] = df[df.columns[-1]].astype(object)
|
|
379
|
+
break
|
|
380
|
+
if mask is None:
|
|
381
|
+
# pandas-version-check
|
|
382
|
+
if self._pandas_version_before(pd.__version__, "2.2"): # pandas < 2.2.0
|
|
383
|
+
df.iloc[:, -1] = df.iloc[:, -1].replace(vs)
|
|
384
|
+
else: # pandas >= 2.2.0
|
|
385
|
+
with pd.option_context("future.no_silent_downcasting", True):
|
|
386
|
+
df.iloc[:, -1] = df.iloc[:, -1].replace(vs).infer_objects()
|
|
387
|
+
else:
|
|
388
|
+
# pandas-version-check
|
|
389
|
+
if self._pandas_version_before(pd.__version__, "2.2"): # pandas < 2.2.0
|
|
390
|
+
df.iloc[~mask, -1] = df.iloc[~mask, -1].replace(vs)
|
|
391
|
+
else: # pandas >= 2.2.0
|
|
392
|
+
with pd.option_context("future.no_silent_downcasting", True):
|
|
393
|
+
df.iloc[~mask, -1] = (
|
|
394
|
+
df.iloc[~mask, -1].replace(vs).infer_objects()
|
|
395
|
+
)
|
|
396
|
+
return df
|
|
397
|
+
|
|
398
|
+
def _apply_value_substitutions(
|
|
399
|
+
self,
|
|
400
|
+
df,
|
|
401
|
+
value_subs,
|
|
402
|
+
sym_type,
|
|
403
|
+
sv_eps=gt.SpecialValues.EPS,
|
|
404
|
+
sv_na=gt.SpecialValues.NA,
|
|
405
|
+
sv_undef=gt.SpecialValues.UNDEF,
|
|
406
|
+
sv_posinf=gt.SpecialValues.POSINF,
|
|
407
|
+
sv_neginf=gt.SpecialValues.NEGINF,
|
|
408
|
+
):
|
|
409
|
+
"""
|
|
410
|
+
Substitutes values in the last column of df as provided in value_subs and returns the modified DataFrame.
|
|
411
|
+
|
|
412
|
+
Parameters
|
|
413
|
+
----------
|
|
414
|
+
df : pandas.DataFrame
|
|
415
|
+
DataFrame on which the value substitutions is applied assuming that the last column contains the values.
|
|
416
|
+
value_subs : dict
|
|
417
|
+
Dictionary containing keys to be substituted by values. For GAMS special values, "EPS', "NA", "UNDEF", "INF", and "-INF"
|
|
418
|
+
should be used as keys in the dictionary.
|
|
419
|
+
sym_type : str
|
|
420
|
+
Symbol type. Can be either "par" or "set".
|
|
421
|
+
sv_eps : str, int, float, optional
|
|
422
|
+
Default value used for replacing EPS values (gams.transfer.SpecialValues.EPS) in case "EPS" is not contained in value_subs, by default gams.transfer.SpecialValues.EPS.
|
|
423
|
+
sv_na : str, int, float, optional
|
|
424
|
+
Default value used for replacing NA values (gams.transfer.SpecialValues.NA) in case "NA" is not contained in value_subs, by default gams.transfer.SpecialValues.NA.
|
|
425
|
+
sv_undef : str, int, float, optional
|
|
426
|
+
Default value used for replacing UNDEF values (gams.transfer.SpecialValues.UNDEF) in case "UNDEF" is not contained in value_subs, by default gams.transfer.SpecialValues.UNDEF.
|
|
427
|
+
sv_posinf : str, int, float, optional
|
|
428
|
+
Default value used for replacing INF values (gams.transfer.SpecialValues.POSINF) in case "INF" is not contained in value_subs, by default gams.transfer.SpecialValues.POSINF.
|
|
429
|
+
sv_neginf : str, int, float, optional
|
|
430
|
+
Default value used for replacing -INF values (gams.transfer.SpecialValues.NEGINF) in case "-INF" is not contained in value_subs, by default gams.transfer.SpecialValues.NEGINF.
|
|
431
|
+
|
|
432
|
+
Returns
|
|
433
|
+
-------
|
|
434
|
+
pandas.DataFrame
|
|
435
|
+
The modified DataFrame with applied substitutions for the last column. Depending on the used substitutions, the dtype of
|
|
436
|
+
that column might be changed to object.
|
|
437
|
+
"""
|
|
438
|
+
|
|
439
|
+
vs = value_subs.copy() if value_subs is not None else {}
|
|
440
|
+
if vs: # convert int/complex to float
|
|
441
|
+
vs = {
|
|
442
|
+
k: float(v) if isinstance(v, (int, complex)) else v
|
|
443
|
+
for k, v in value_subs.items()
|
|
444
|
+
}
|
|
445
|
+
if sym_type == "par":
|
|
446
|
+
|
|
447
|
+
def replace_sv(df, eps_val, na_val, undef_val, posinf_val, neginf_val):
|
|
448
|
+
arr = df.iloc[:, -1].values
|
|
449
|
+
|
|
450
|
+
# create special values masks
|
|
451
|
+
eps_mask = gt.SpecialValues.isEps(arr)
|
|
452
|
+
has_eps = eps_mask.any()
|
|
453
|
+
|
|
454
|
+
na_mask = gt.SpecialValues.isNA(arr)
|
|
455
|
+
has_na = na_mask.any()
|
|
456
|
+
|
|
457
|
+
undef_mask = gt.SpecialValues.isUndef(arr)
|
|
458
|
+
has_undef = undef_mask.any()
|
|
459
|
+
|
|
460
|
+
posinf_mask = gt.SpecialValues.isPosInf(arr)
|
|
461
|
+
has_posinf = posinf_mask.any()
|
|
462
|
+
|
|
463
|
+
neginf_mask = gt.SpecialValues.isNegInf(arr)
|
|
464
|
+
has_neginf = neginf_mask.any()
|
|
465
|
+
|
|
466
|
+
# replace special values
|
|
467
|
+
if has_eps or has_na or has_undef or has_posinf or has_neginf:
|
|
468
|
+
if (
|
|
469
|
+
has_eps
|
|
470
|
+
and isinstance(eps_val, str)
|
|
471
|
+
or has_na
|
|
472
|
+
and isinstance(na_val, str)
|
|
473
|
+
or has_undef
|
|
474
|
+
and isinstance(undef_val, str)
|
|
475
|
+
or has_posinf
|
|
476
|
+
and isinstance(posinf_val, str)
|
|
477
|
+
or has_neginf
|
|
478
|
+
and isinstance(neginf_val, str)
|
|
479
|
+
):
|
|
480
|
+
arr = arr.astype(object)
|
|
481
|
+
mask = eps_mask | na_mask | undef_mask | posinf_mask | neginf_mask
|
|
482
|
+
if has_eps:
|
|
483
|
+
arr[eps_mask] = eps_val
|
|
484
|
+
if has_na:
|
|
485
|
+
arr[na_mask] = na_val
|
|
486
|
+
if has_undef:
|
|
487
|
+
arr[undef_mask] = undef_val
|
|
488
|
+
if has_posinf:
|
|
489
|
+
arr[posinf_mask] = posinf_val
|
|
490
|
+
if has_neginf:
|
|
491
|
+
arr[neginf_mask] = neginf_val
|
|
492
|
+
df[df.columns[-1]] = arr
|
|
493
|
+
return df, mask
|
|
494
|
+
return df, None
|
|
495
|
+
|
|
496
|
+
# determine special values substitutions
|
|
497
|
+
gt_eps_in_vs = any(
|
|
498
|
+
not isinstance(k, str) and gt.SpecialValues.isEps(k) for k in vs.keys()
|
|
499
|
+
)
|
|
500
|
+
if "EPS" in vs.keys():
|
|
501
|
+
if gt_eps_in_vs:
|
|
502
|
+
self._cdb.print_log(
|
|
503
|
+
f'Warning: "EPS" ({vs["EPS"]}) overwrites -0.0 ({vs[gt.SpecialValues.EPS]}) in valueSubstitutions.'
|
|
504
|
+
)
|
|
505
|
+
del vs[gt.SpecialValues.EPS]
|
|
506
|
+
eps_val = vs["EPS"]
|
|
507
|
+
del vs["EPS"]
|
|
508
|
+
elif gt_eps_in_vs:
|
|
509
|
+
eps_val = vs[gt.SpecialValues.EPS]
|
|
510
|
+
del vs[gt.SpecialValues.EPS]
|
|
511
|
+
else:
|
|
512
|
+
eps_val = sv_eps
|
|
513
|
+
|
|
514
|
+
if "NA" in vs.keys():
|
|
515
|
+
na_val = vs["NA"]
|
|
516
|
+
del vs["NA"]
|
|
517
|
+
else:
|
|
518
|
+
na_val = sv_na
|
|
519
|
+
|
|
520
|
+
if "UNDEF" in vs.keys():
|
|
521
|
+
undef_val = vs["UNDEF"]
|
|
522
|
+
del vs["UNDEF"]
|
|
523
|
+
else:
|
|
524
|
+
undef_val = sv_undef
|
|
525
|
+
|
|
526
|
+
if "INF" in vs.keys():
|
|
527
|
+
if gt.SpecialValues.POSINF in vs:
|
|
528
|
+
self._cdb.print_log(
|
|
529
|
+
f'Warning: "INF" ({vs["INF"]}) overwrites .inf ({vs[float("inf")]}) in valueSubstitutions.'
|
|
530
|
+
)
|
|
531
|
+
del vs[gt.SpecialValues.POSINF]
|
|
532
|
+
posinf_val = vs["INF"]
|
|
533
|
+
del vs["INF"]
|
|
534
|
+
elif gt.SpecialValues.POSINF in vs:
|
|
535
|
+
posinf_val = vs[gt.SpecialValues.POSINF]
|
|
536
|
+
del vs[gt.SpecialValues.POSINF]
|
|
537
|
+
else:
|
|
538
|
+
posinf_val = sv_posinf
|
|
539
|
+
|
|
540
|
+
if "-INF" in vs.keys():
|
|
541
|
+
if gt.SpecialValues.NEGINF in vs:
|
|
542
|
+
self._cdb.print_log(
|
|
543
|
+
f'Warning: "-INF" ({vs["-INF"]}) overwrites -.inf ({vs[float("-inf")]}) in valueSubstitutions.'
|
|
544
|
+
)
|
|
545
|
+
del vs[gt.SpecialValues.NEGINF]
|
|
546
|
+
neginf_val = vs["-INF"]
|
|
547
|
+
del vs["-INF"]
|
|
548
|
+
elif gt.SpecialValues.NEGINF in vs:
|
|
549
|
+
neginf_val = vs[gt.SpecialValues.NEGINF]
|
|
550
|
+
del vs[gt.SpecialValues.NEGINF]
|
|
551
|
+
else:
|
|
552
|
+
neginf_val = sv_neginf
|
|
553
|
+
|
|
554
|
+
# - pandas does not distingish between gt.SpecialValues.NA and gt.SpecialValues.UNDEF and
|
|
555
|
+
# we have to replace NA manually first.
|
|
556
|
+
# - pandas replace() does not distinguish between +0.0 and -0.0 (gt.SpecialValues.EPS) and we
|
|
557
|
+
# have to replace EPS manually first.
|
|
558
|
+
# - all other special values (UNDEF, INF, -INF) are replaced manually as well for consistency and
|
|
559
|
+
# performance reasons
|
|
560
|
+
df, mask = replace_sv(
|
|
561
|
+
df, eps_val, na_val, undef_val, posinf_val, neginf_val
|
|
562
|
+
)
|
|
563
|
+
df = self._replace_no_warn(df, vs, mask)
|
|
564
|
+
else: # set
|
|
565
|
+
df = self._replace_no_warn(df, vs)
|
|
566
|
+
|
|
567
|
+
return df
|
|
568
|
+
|
|
569
|
+
def _compile_error_message(self, symbols, suffix, should_exist):
|
|
570
|
+
plural = len(symbols) > 1
|
|
571
|
+
symbol_label = "Symbols" if plural else "Symbol"
|
|
572
|
+
symbol_list = ",".join(symbols)
|
|
573
|
+
if should_exist:
|
|
574
|
+
verb = "do not exist" if plural else "does not exist"
|
|
575
|
+
else:
|
|
576
|
+
verb = "already exist" if plural else "already exists"
|
|
577
|
+
|
|
578
|
+
return f"{symbol_label} >{symbol_list}< {verb} {suffix}"
|
|
579
|
+
|
|
580
|
+
def _symbols_exist_gmd(self, gmd, sym_names):
|
|
581
|
+
"""
|
|
582
|
+
Raises a GamsConnectException if a single symbol or at least one symbol
|
|
583
|
+
of a given list of symbols does not exist in the given GMD object.
|
|
584
|
+
|
|
585
|
+
Parameters
|
|
586
|
+
----------
|
|
587
|
+
gmd : GMD handle
|
|
588
|
+
sym_names : str, list[str]
|
|
589
|
+
A list of symbol names or a single symbol name to be checked.
|
|
590
|
+
|
|
591
|
+
Raises
|
|
592
|
+
----------
|
|
593
|
+
GamsConnectException
|
|
594
|
+
If at least one symbol does not exist.
|
|
595
|
+
"""
|
|
596
|
+
sym_list = sym_names if isinstance(sym_names, list) else [sym_names]
|
|
597
|
+
tmp_ws = GamsWorkspace(system_directory=self._cdb._system_directory)
|
|
598
|
+
db = tmp_ws._add_database_from_gmd(gmd)
|
|
599
|
+
|
|
600
|
+
symbols = []
|
|
601
|
+
for s in sym_list:
|
|
602
|
+
try:
|
|
603
|
+
db[s]
|
|
604
|
+
except:
|
|
605
|
+
symbols.append(s)
|
|
606
|
+
|
|
607
|
+
if not symbols:
|
|
608
|
+
return
|
|
609
|
+
|
|
610
|
+
msg = self._compile_error_message(symbols, "in the GAMS database.", should_exist=True)
|
|
611
|
+
self._connect_error(msg)
|
|
612
|
+
|
|
613
|
+
def _symbols_exist_gdx(self, gdx_file, sym_names):
|
|
614
|
+
"""
|
|
615
|
+
Raises a GamsConnectException if a single symbol or at least one symbol
|
|
616
|
+
of a given list of symbols does not exist in the given GDX file.
|
|
617
|
+
|
|
618
|
+
Parameters
|
|
619
|
+
----------
|
|
620
|
+
gdx_file : str
|
|
621
|
+
sym_names : str, list[str]
|
|
622
|
+
A list of symbol names or a single symbol name to be checked.
|
|
623
|
+
|
|
624
|
+
Raises
|
|
625
|
+
----------
|
|
626
|
+
GamsConnectException
|
|
627
|
+
If at least one symbol does not exist.
|
|
628
|
+
"""
|
|
629
|
+
sym_list = sym_names if isinstance(sym_names, list) else [sym_names]
|
|
630
|
+
tmp_ws = GamsWorkspace(system_directory=self._cdb._system_directory)
|
|
631
|
+
db = tmp_ws.add_database_from_gdx(gdx_file)
|
|
632
|
+
|
|
633
|
+
symbols = []
|
|
634
|
+
for s in sym_list:
|
|
635
|
+
try:
|
|
636
|
+
db[s]
|
|
637
|
+
except:
|
|
638
|
+
symbols.append(s)
|
|
639
|
+
|
|
640
|
+
if not symbols:
|
|
641
|
+
return
|
|
642
|
+
|
|
643
|
+
msg = self._compile_error_message(symbols, f"in the GDX file >{gdx_file}<.", should_exist=True)
|
|
644
|
+
self._connect_error(msg)
|
|
645
|
+
|
|
646
|
+
def _symbols_exist_cdb(self, sym_names, should_exist=False):
|
|
647
|
+
"""
|
|
648
|
+
Checks the Connect database for existing symbols and raises a GamsConnectException
|
|
649
|
+
depending on parameter should_exist.
|
|
650
|
+
For should_exist=False: Raises a GamsConnectException if a single symbol or at least one symbol
|
|
651
|
+
of a given list of symbols does exist in the Connect Database.
|
|
652
|
+
For should_exist=True: Raises a GamsConnectException if a single symbol or at least one symbol
|
|
653
|
+
of a given list of symbols does not exist in the Connect Database.
|
|
654
|
+
|
|
655
|
+
Parameters
|
|
656
|
+
----------
|
|
657
|
+
sym_names : str, list[str]
|
|
658
|
+
A list of symbol names or a single symbol name to be checked.
|
|
659
|
+
should_exist : bool
|
|
660
|
+
If False, raises an exception if any symbol is missing. If True, raises an exception if any symbol already exists.
|
|
661
|
+
|
|
662
|
+
Raises
|
|
663
|
+
----------
|
|
664
|
+
GamsConnectException
|
|
665
|
+
If at least one symbol already exists.
|
|
666
|
+
"""
|
|
667
|
+
sym_list = sym_names if isinstance(sym_names, list) else [sym_names]
|
|
668
|
+
symbols = (
|
|
669
|
+
[s for s in sym_list if s not in self._cdb.container]
|
|
670
|
+
if should_exist
|
|
671
|
+
else [s for s in sym_list if s in self._cdb.container]
|
|
672
|
+
)
|
|
673
|
+
|
|
674
|
+
if not symbols:
|
|
675
|
+
return
|
|
676
|
+
msg = self._compile_error_message(symbols, "in the Connect database.", should_exist)
|
|
677
|
+
self._connect_error(msg)
|
|
678
|
+
|
|
679
|
+
def _update_sym_inst(self, sym_inst, root_inst):
|
|
680
|
+
"""
|
|
681
|
+
Updates None values in the symbols scope instructions with the corresponding values
|
|
682
|
+
from the root scope for all keys that exist in both instruction dictionaries.
|
|
683
|
+
This method is not recursive and considers only the first level of the provided
|
|
684
|
+
dictionaries. sym_inst is updated inplace and also returned.
|
|
685
|
+
|
|
686
|
+
Parameters
|
|
687
|
+
----------
|
|
688
|
+
sym_inst : dict
|
|
689
|
+
Symbols instructions to be updated.
|
|
690
|
+
root_inst : dict
|
|
691
|
+
Root instructions to be used for updating sym_inst
|
|
692
|
+
|
|
693
|
+
Returns
|
|
694
|
+
----------
|
|
695
|
+
dict
|
|
696
|
+
The updated sym_inst dictionary
|
|
697
|
+
"""
|
|
698
|
+
keys = [
|
|
699
|
+
k for k in sym_inst.keys() if k in root_inst
|
|
700
|
+
] # all keys that exist in both dictionaries
|
|
701
|
+
for k in keys:
|
|
702
|
+
if sym_inst[k] is None:
|
|
703
|
+
sym_inst[k] = root_inst[k]
|
|
704
|
+
return sym_inst
|
|
705
|
+
|
|
706
|
+
def _dict_get(self, d, key, default):
|
|
707
|
+
"""
|
|
708
|
+
Like dict.get() but handles keys with None value as if they were missing.
|
|
709
|
+
|
|
710
|
+
Parameters
|
|
711
|
+
----------
|
|
712
|
+
d : dict
|
|
713
|
+
Dictionary to be used.
|
|
714
|
+
key : str
|
|
715
|
+
The key to be found in d.
|
|
716
|
+
default : int, str, float
|
|
717
|
+
Default value to be returned in case d.get(key) is None.
|
|
718
|
+
|
|
719
|
+
Returns
|
|
720
|
+
----------
|
|
721
|
+
int, str, float
|
|
722
|
+
d[key] if key is in d and the value is not None, default otherwise.
|
|
723
|
+
"""
|
|
724
|
+
return default if d.get(key) is None else d[key]
|
|
725
|
+
|
|
726
|
+
def setup_log(self):
|
|
727
|
+
if self._trace > 3:
|
|
728
|
+
self._restore_max_rows = pd.get_option("display.max_rows")
|
|
729
|
+
self._restore_max_columns = pd.get_option("display.max_columns")
|
|
730
|
+
self._restore_np_threshold = np.get_printoptions()["threshold"]
|
|
731
|
+
pd.set_option("display.max_rows", None, "display.max_columns", None)
|
|
732
|
+
np.set_printoptions(threshold=sys.maxsize)
|
|
733
|
+
|
|
734
|
+
def restore_log(self):
|
|
735
|
+
if self._trace > 3:
|
|
736
|
+
pd.set_option("display.max_rows", self._restore_max_rows, "display.max_columns", self._restore_max_columns)
|
|
737
|
+
np.set_printoptions(self._restore_np_threshold)
|
|
738
|
+
|
|
739
|
+
@abstractmethod
|
|
740
|
+
def execute(self):
|
|
741
|
+
"""
|
|
742
|
+
Called by the ConnectDatabase after open() and before close(). This abstract method needs to be implemented by a subclass.
|
|
743
|
+
"""
|