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,627 @@
|
|
|
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
|
+
import numpy as np
|
|
27
|
+
import pandas as pd
|
|
28
|
+
from gams.transfer._internals import SpecialValues
|
|
29
|
+
import gams.transfer._abcs as abcs
|
|
30
|
+
from typing import Optional, Union, List
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class PVEMixin:
|
|
34
|
+
@property
|
|
35
|
+
def shape(self) -> tuple:
|
|
36
|
+
"""
|
|
37
|
+
Returns a tuple describing the array dimensions if records were converted with .toDense()
|
|
38
|
+
|
|
39
|
+
Returns
|
|
40
|
+
-------
|
|
41
|
+
tuple
|
|
42
|
+
A tuple describing the records dimensions
|
|
43
|
+
"""
|
|
44
|
+
if self.domain_type == "regular":
|
|
45
|
+
return tuple(
|
|
46
|
+
[
|
|
47
|
+
(
|
|
48
|
+
0
|
|
49
|
+
if i.getUELs(0, ignore_unused=True) is None
|
|
50
|
+
else len(i.getUELs(0, ignore_unused=True))
|
|
51
|
+
)
|
|
52
|
+
for i in self.domain
|
|
53
|
+
]
|
|
54
|
+
)
|
|
55
|
+
else:
|
|
56
|
+
return tuple(
|
|
57
|
+
[
|
|
58
|
+
(
|
|
59
|
+
0
|
|
60
|
+
if self.getUELs(i, ignore_unused=True) is None
|
|
61
|
+
else len(self.getUELs(i, ignore_unused=True))
|
|
62
|
+
)
|
|
63
|
+
for i in range(self.dimension)
|
|
64
|
+
]
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
@property
|
|
68
|
+
def is_scalar(self) -> bool:
|
|
69
|
+
"""
|
|
70
|
+
Returns True if the len(self.domain) = 0
|
|
71
|
+
|
|
72
|
+
Returns
|
|
73
|
+
-------
|
|
74
|
+
bool
|
|
75
|
+
True if the len(self.domain) = 0
|
|
76
|
+
"""
|
|
77
|
+
return self.dimension == 0
|
|
78
|
+
|
|
79
|
+
def findEps(self, column: Optional[str] = None) -> pd.DataFrame:
|
|
80
|
+
"""
|
|
81
|
+
Find positions of SpecialValues.EPS in value column
|
|
82
|
+
|
|
83
|
+
Parameters
|
|
84
|
+
----------
|
|
85
|
+
column : str, optional
|
|
86
|
+
Column to find the special values in, by default None
|
|
87
|
+
|
|
88
|
+
Returns
|
|
89
|
+
-------
|
|
90
|
+
pd.DataFrame
|
|
91
|
+
Dataframe containing special values
|
|
92
|
+
"""
|
|
93
|
+
return self.findSpecialValues(SpecialValues.EPS, column=column)
|
|
94
|
+
|
|
95
|
+
def findNA(self, column: Optional[str] = None) -> pd.DataFrame:
|
|
96
|
+
"""
|
|
97
|
+
Find positions of SpecialValues.NA in value column
|
|
98
|
+
|
|
99
|
+
Parameters
|
|
100
|
+
----------
|
|
101
|
+
column : str, optional
|
|
102
|
+
Column to find the special values in, by default None
|
|
103
|
+
|
|
104
|
+
Returns
|
|
105
|
+
-------
|
|
106
|
+
pd.DataFrame
|
|
107
|
+
Dataframe containing special values
|
|
108
|
+
"""
|
|
109
|
+
return self.findSpecialValues(SpecialValues.NA, column=column)
|
|
110
|
+
|
|
111
|
+
def findUndef(self, column: Optional[str] = None) -> pd.DataFrame:
|
|
112
|
+
"""
|
|
113
|
+
Find positions of SpecialValues.Undef in value column
|
|
114
|
+
|
|
115
|
+
Parameters
|
|
116
|
+
----------
|
|
117
|
+
column : str, optional
|
|
118
|
+
Column to find the special values in, by default None
|
|
119
|
+
|
|
120
|
+
Returns
|
|
121
|
+
-------
|
|
122
|
+
pd.DataFrame
|
|
123
|
+
Dataframe containing special values
|
|
124
|
+
"""
|
|
125
|
+
return self.findSpecialValues(SpecialValues.UNDEF, column=column)
|
|
126
|
+
|
|
127
|
+
def findPosInf(self, column: Optional[str] = None) -> pd.DataFrame:
|
|
128
|
+
"""
|
|
129
|
+
Find positions of SpecialValues.PosInf in value column
|
|
130
|
+
|
|
131
|
+
Parameters
|
|
132
|
+
----------
|
|
133
|
+
column : str, optional
|
|
134
|
+
Column to find the special values in, by default None
|
|
135
|
+
|
|
136
|
+
Returns
|
|
137
|
+
-------
|
|
138
|
+
pd.DataFrame
|
|
139
|
+
Dataframe containing special values
|
|
140
|
+
"""
|
|
141
|
+
return self.findSpecialValues(SpecialValues.POSINF, column=column)
|
|
142
|
+
|
|
143
|
+
def findNegInf(self, column: Optional[str] = None) -> pd.DataFrame:
|
|
144
|
+
"""
|
|
145
|
+
Find positions of SpecialValues.NegInf in value column
|
|
146
|
+
|
|
147
|
+
Parameters
|
|
148
|
+
----------
|
|
149
|
+
column : str, optional
|
|
150
|
+
Column to find the special values in, by default None
|
|
151
|
+
|
|
152
|
+
Returns
|
|
153
|
+
-------
|
|
154
|
+
pd.DataFrame
|
|
155
|
+
Dataframe containing special values
|
|
156
|
+
"""
|
|
157
|
+
return self.findSpecialValues(SpecialValues.NEGINF, column=column)
|
|
158
|
+
|
|
159
|
+
def findSpecialValues(
|
|
160
|
+
self, values: Union[float, List[float]], column: Optional[str] = None
|
|
161
|
+
) -> pd.DataFrame:
|
|
162
|
+
"""
|
|
163
|
+
Find positions of specified values in records columns
|
|
164
|
+
|
|
165
|
+
Parameters
|
|
166
|
+
----------
|
|
167
|
+
values : float | List[float]
|
|
168
|
+
Values to look for
|
|
169
|
+
column : str, optional
|
|
170
|
+
Column to find the special values in, by default None
|
|
171
|
+
|
|
172
|
+
Returns
|
|
173
|
+
-------
|
|
174
|
+
pd.DataFrame
|
|
175
|
+
Dataframe containing special values
|
|
176
|
+
"""
|
|
177
|
+
# ARG: values
|
|
178
|
+
if not isinstance(values, (float, list)):
|
|
179
|
+
raise TypeError("Argument 'values' must be type float or list")
|
|
180
|
+
|
|
181
|
+
if isinstance(values, float):
|
|
182
|
+
values = [values]
|
|
183
|
+
|
|
184
|
+
for i in values:
|
|
185
|
+
if not (
|
|
186
|
+
SpecialValues.isEps(i)
|
|
187
|
+
or SpecialValues.isNA(i)
|
|
188
|
+
or SpecialValues.isUndef(i)
|
|
189
|
+
or SpecialValues.isPosInf(i)
|
|
190
|
+
or SpecialValues.isNegInf(i)
|
|
191
|
+
):
|
|
192
|
+
return ValueError(
|
|
193
|
+
"Argument 'values' is currently limited to one of the "
|
|
194
|
+
"five special value constants defined as: "
|
|
195
|
+
"EPS, NA, UNDEF, POSINF, or NEGINF"
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
# ARG: columns
|
|
199
|
+
# set defaults
|
|
200
|
+
if column is None:
|
|
201
|
+
if isinstance(self, abcs.ABCParameter):
|
|
202
|
+
column = "value"
|
|
203
|
+
elif isinstance(self, (abcs.ABCVariable, abcs.ABCEquation)):
|
|
204
|
+
column = "level"
|
|
205
|
+
else:
|
|
206
|
+
raise Exception(f"Unsupported object type: {type(self)}")
|
|
207
|
+
|
|
208
|
+
# checks
|
|
209
|
+
if not isinstance(column, str):
|
|
210
|
+
raise TypeError(
|
|
211
|
+
f"Argument 'column' must be type str. User passed {type(column)}."
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
if column not in self._attributes:
|
|
215
|
+
raise TypeError(
|
|
216
|
+
f"Argument 'column' must be a one of the following: {self._attributes}"
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
if self.records is not None:
|
|
220
|
+
for n, i in enumerate(values):
|
|
221
|
+
if n == 0:
|
|
222
|
+
if SpecialValues.isEps(i):
|
|
223
|
+
idx = SpecialValues.isEps(self.records[column])
|
|
224
|
+
elif SpecialValues.isNA(i):
|
|
225
|
+
idx = SpecialValues.isNA(self.records[column])
|
|
226
|
+
elif SpecialValues.isUndef(i):
|
|
227
|
+
idx = SpecialValues.isUndef(self.records[column])
|
|
228
|
+
elif SpecialValues.isPosInf(i):
|
|
229
|
+
idx = SpecialValues.isPosInf(self.records[column])
|
|
230
|
+
elif SpecialValues.isNegInf(i):
|
|
231
|
+
idx = SpecialValues.isNegInf(self.records[column])
|
|
232
|
+
else:
|
|
233
|
+
raise Exception("Unknown special value detected")
|
|
234
|
+
else:
|
|
235
|
+
if SpecialValues.isEps(i):
|
|
236
|
+
idx = (idx) | (SpecialValues.isEps(self.records[column]))
|
|
237
|
+
elif SpecialValues.isNA(i):
|
|
238
|
+
idx = (idx) | (SpecialValues.isNA(self.records[column]))
|
|
239
|
+
elif SpecialValues.isUndef(i):
|
|
240
|
+
idx = (idx) | (SpecialValues.isUndef(self.records[column]))
|
|
241
|
+
elif SpecialValues.isPosInf(i):
|
|
242
|
+
idx = (idx) | (SpecialValues.isPosInf(self.records[column]))
|
|
243
|
+
elif SpecialValues.isNegInf(i):
|
|
244
|
+
idx = (idx) | (SpecialValues.isNegInf(self.records[column]))
|
|
245
|
+
else:
|
|
246
|
+
raise Exception("Unknown special value detected")
|
|
247
|
+
|
|
248
|
+
return self.records.loc[idx, :]
|
|
249
|
+
|
|
250
|
+
def countNA(self, columns: Optional[Union[str, List[str]]] = None) -> int:
|
|
251
|
+
"""
|
|
252
|
+
Counts total number of SpecialValues.NA across columns
|
|
253
|
+
|
|
254
|
+
Parameters
|
|
255
|
+
----------
|
|
256
|
+
columns : str | List[str], optional
|
|
257
|
+
Columns to count special values in, by default None
|
|
258
|
+
|
|
259
|
+
Returns
|
|
260
|
+
-------
|
|
261
|
+
Total number of SpecialValues.NA across columns
|
|
262
|
+
"""
|
|
263
|
+
return self._countSpecialValues(SpecialValues.NA, columns=columns)
|
|
264
|
+
|
|
265
|
+
def countEps(self, columns: Optional[Union[str, List[str]]] = None) -> int:
|
|
266
|
+
"""
|
|
267
|
+
Counts total number of SpecialValues.EPS across columns
|
|
268
|
+
|
|
269
|
+
Parameters
|
|
270
|
+
----------
|
|
271
|
+
columns : str | List[str], optional
|
|
272
|
+
Columns to count special values in, by default None
|
|
273
|
+
|
|
274
|
+
Returns
|
|
275
|
+
-------
|
|
276
|
+
Total number of SpecialValues.EPS across columns
|
|
277
|
+
"""
|
|
278
|
+
return self._countSpecialValues(SpecialValues.EPS, columns=columns)
|
|
279
|
+
|
|
280
|
+
def countUndef(self, columns: Optional[Union[str, List[str]]] = None) -> int:
|
|
281
|
+
"""
|
|
282
|
+
Counts total number of SpecialValues.Undef across columns
|
|
283
|
+
|
|
284
|
+
Parameters
|
|
285
|
+
----------
|
|
286
|
+
columns : str | List[str], optional
|
|
287
|
+
Columns to count special values in, by default None
|
|
288
|
+
|
|
289
|
+
Returns
|
|
290
|
+
-------
|
|
291
|
+
Total number of SpecialValues.Undef across columns
|
|
292
|
+
"""
|
|
293
|
+
return self._countSpecialValues(SpecialValues.UNDEF, columns=columns)
|
|
294
|
+
|
|
295
|
+
def countPosInf(self, columns: Optional[Union[str, List[str]]] = None) -> int:
|
|
296
|
+
"""
|
|
297
|
+
Counts total number of SpecialValues.PosInf across columns
|
|
298
|
+
|
|
299
|
+
Parameters
|
|
300
|
+
----------
|
|
301
|
+
columns : str | List[str], optional
|
|
302
|
+
Columns to count special values in, by default None
|
|
303
|
+
|
|
304
|
+
Returns
|
|
305
|
+
-------
|
|
306
|
+
Total number of SpecialValues.PosInf across columns
|
|
307
|
+
"""
|
|
308
|
+
return self._countSpecialValues(SpecialValues.POSINF, columns=columns)
|
|
309
|
+
|
|
310
|
+
def countNegInf(self, columns: Optional[Union[str, List[str]]] = None) -> int:
|
|
311
|
+
"""
|
|
312
|
+
Counts total number of SpecialValues.NegInf across columns
|
|
313
|
+
|
|
314
|
+
Parameters
|
|
315
|
+
----------
|
|
316
|
+
columns : str | List[str], optional
|
|
317
|
+
Columns to count special values in, by default None
|
|
318
|
+
|
|
319
|
+
Returns
|
|
320
|
+
-------
|
|
321
|
+
Total number of SpecialValues.NegInf across columns
|
|
322
|
+
"""
|
|
323
|
+
return self._countSpecialValues(SpecialValues.NEGINF, columns=columns)
|
|
324
|
+
|
|
325
|
+
def _countSpecialValues(self, special_value, columns):
|
|
326
|
+
# ARG: special_value
|
|
327
|
+
if not isinstance(special_value, float):
|
|
328
|
+
raise TypeError("Argument 'float' must be type float")
|
|
329
|
+
|
|
330
|
+
if not (
|
|
331
|
+
SpecialValues.isEps(special_value)
|
|
332
|
+
or SpecialValues.isNA(special_value)
|
|
333
|
+
or SpecialValues.isUndef(special_value)
|
|
334
|
+
or SpecialValues.isPosInf(special_value)
|
|
335
|
+
or SpecialValues.isNegInf(special_value)
|
|
336
|
+
):
|
|
337
|
+
return ValueError(
|
|
338
|
+
"Argument 'special_value' is currently limited to one of the "
|
|
339
|
+
"five special value constants defined as: "
|
|
340
|
+
"SpecialValues.EPS SpecialValues.NA, SpecialValues.UNDEF, "
|
|
341
|
+
"SpecialValues.POSINF, or SpecialValues.NEGINF"
|
|
342
|
+
)
|
|
343
|
+
|
|
344
|
+
# ARG: columns
|
|
345
|
+
# set defaults
|
|
346
|
+
if columns is None:
|
|
347
|
+
if isinstance(self, abcs.ABCParameter):
|
|
348
|
+
columns = "value"
|
|
349
|
+
elif isinstance(self, (abcs.ABCVariable, abcs.ABCEquation)):
|
|
350
|
+
columns = "level"
|
|
351
|
+
else:
|
|
352
|
+
raise Exception(f"Unsupported object type: {type(self)}")
|
|
353
|
+
|
|
354
|
+
# checks
|
|
355
|
+
if not isinstance(columns, (str, list)):
|
|
356
|
+
raise TypeError(
|
|
357
|
+
f"Argument 'columns' must be type str or list. User passed {type(columns)}."
|
|
358
|
+
)
|
|
359
|
+
|
|
360
|
+
if isinstance(columns, str):
|
|
361
|
+
columns = [columns]
|
|
362
|
+
|
|
363
|
+
if any(not isinstance(i, str) for i in columns):
|
|
364
|
+
raise TypeError(f"Argument 'columns' must contain only type str.")
|
|
365
|
+
|
|
366
|
+
if any(i not in self._attributes for i in columns):
|
|
367
|
+
raise TypeError(
|
|
368
|
+
f"Argument 'columns' must be a subset of the following: {self._attributes}"
|
|
369
|
+
)
|
|
370
|
+
|
|
371
|
+
if self.records is not None:
|
|
372
|
+
if SpecialValues.isEps(special_value):
|
|
373
|
+
return np.sum(SpecialValues.isEps(self.records[columns]))
|
|
374
|
+
elif SpecialValues.isNA(special_value):
|
|
375
|
+
return np.sum(SpecialValues.isNA(self.records[columns]))
|
|
376
|
+
elif SpecialValues.isUndef(special_value):
|
|
377
|
+
return np.sum(SpecialValues.isUndef(self.records[columns]))
|
|
378
|
+
elif SpecialValues.isPosInf(special_value):
|
|
379
|
+
return np.sum(SpecialValues.isPosInf(self.records[columns]))
|
|
380
|
+
elif SpecialValues.isNegInf(special_value):
|
|
381
|
+
return np.sum(SpecialValues.isNegInf(self.records[columns]))
|
|
382
|
+
else:
|
|
383
|
+
raise Exception("Unknown special value detected")
|
|
384
|
+
|
|
385
|
+
def whereMax(self, column: Optional[str] = None) -> List[str]:
|
|
386
|
+
"""
|
|
387
|
+
Find the domain entry of records with a maximum value (return first instance only)
|
|
388
|
+
|
|
389
|
+
Parameters
|
|
390
|
+
----------
|
|
391
|
+
column : str, optional
|
|
392
|
+
Columns to find maximum values in, by default None
|
|
393
|
+
|
|
394
|
+
Returns
|
|
395
|
+
-------
|
|
396
|
+
List[str]
|
|
397
|
+
List of symbol names where maximum values exist
|
|
398
|
+
"""
|
|
399
|
+
return self._whereMetric("max", column=column)
|
|
400
|
+
|
|
401
|
+
def whereMaxAbs(self, column: Optional[str] = None) -> List[str]:
|
|
402
|
+
"""
|
|
403
|
+
Find the domain entry of records with a maximum absolute value (return first instance only)
|
|
404
|
+
|
|
405
|
+
Parameters
|
|
406
|
+
----------
|
|
407
|
+
column : str, optional
|
|
408
|
+
Columns to find maximum absolute values in, by default None
|
|
409
|
+
|
|
410
|
+
Returns
|
|
411
|
+
-------
|
|
412
|
+
List[str]
|
|
413
|
+
List of symbol names where maximum absolute values exist
|
|
414
|
+
"""
|
|
415
|
+
|
|
416
|
+
return self._whereMetric("absmax", column=column)
|
|
417
|
+
|
|
418
|
+
def whereMin(self, column: Optional[str] = None) -> List[str]:
|
|
419
|
+
"""
|
|
420
|
+
Find the domain entry of records with a minimum value (return first instance only)
|
|
421
|
+
|
|
422
|
+
Parameters
|
|
423
|
+
----------
|
|
424
|
+
column : str, optional
|
|
425
|
+
Columns to find minimum values in, by default None
|
|
426
|
+
|
|
427
|
+
Returns
|
|
428
|
+
-------
|
|
429
|
+
List[str]
|
|
430
|
+
List of symbol names where minimum values exist
|
|
431
|
+
"""
|
|
432
|
+
|
|
433
|
+
return self._whereMetric("min", column=column)
|
|
434
|
+
|
|
435
|
+
def _whereMetric(self, metric, column):
|
|
436
|
+
# ARG: metric
|
|
437
|
+
if not isinstance(metric, str):
|
|
438
|
+
raise TypeError("Argument 'metric' must be type str")
|
|
439
|
+
|
|
440
|
+
if metric not in [
|
|
441
|
+
"max",
|
|
442
|
+
"min",
|
|
443
|
+
"absmax",
|
|
444
|
+
]:
|
|
445
|
+
return ValueError(
|
|
446
|
+
"Argument 'metric' is currently limited to str type 'max', 'min' or 'absmax'"
|
|
447
|
+
)
|
|
448
|
+
|
|
449
|
+
# ARG: columns
|
|
450
|
+
|
|
451
|
+
# set defaults
|
|
452
|
+
if column is None:
|
|
453
|
+
if isinstance(self, abcs.ABCParameter):
|
|
454
|
+
column = "value"
|
|
455
|
+
elif isinstance(self, (abcs.ABCVariable, abcs.ABCEquation)):
|
|
456
|
+
column = "level"
|
|
457
|
+
else:
|
|
458
|
+
raise Exception(f"Unsupported object type: {type(self)}")
|
|
459
|
+
|
|
460
|
+
# checks
|
|
461
|
+
if not isinstance(column, str):
|
|
462
|
+
raise TypeError(
|
|
463
|
+
f"Argument 'column' must be type str. User passed {type(column)}."
|
|
464
|
+
)
|
|
465
|
+
|
|
466
|
+
if column not in self._attributes:
|
|
467
|
+
raise TypeError(
|
|
468
|
+
f"Argument 'column' must be a one of the following: {self._attributes}"
|
|
469
|
+
)
|
|
470
|
+
|
|
471
|
+
if self.records is not None:
|
|
472
|
+
dom = []
|
|
473
|
+
if metric == "max":
|
|
474
|
+
if self.dimension > 0:
|
|
475
|
+
try:
|
|
476
|
+
dom = list(
|
|
477
|
+
self.records[
|
|
478
|
+
self.records[column] == self.getMaxValue(column)
|
|
479
|
+
].to_numpy()[0][: self.dimension]
|
|
480
|
+
)
|
|
481
|
+
return dom
|
|
482
|
+
except Exception as err:
|
|
483
|
+
return None
|
|
484
|
+
|
|
485
|
+
if metric == "min":
|
|
486
|
+
if self.dimension > 0:
|
|
487
|
+
try:
|
|
488
|
+
dom = list(
|
|
489
|
+
self.records[
|
|
490
|
+
self.records[column] == self.getMinValue(column)
|
|
491
|
+
].to_numpy()[0][: self.dimension]
|
|
492
|
+
)
|
|
493
|
+
return dom
|
|
494
|
+
except:
|
|
495
|
+
return None
|
|
496
|
+
|
|
497
|
+
if metric == "absmax":
|
|
498
|
+
if self.dimension > 0:
|
|
499
|
+
try:
|
|
500
|
+
dom = list(
|
|
501
|
+
self.records[
|
|
502
|
+
self.records[column] == self.getMaxAbsValue(column)
|
|
503
|
+
].to_numpy()[0][: self.dimension]
|
|
504
|
+
)
|
|
505
|
+
return dom
|
|
506
|
+
except:
|
|
507
|
+
return None
|
|
508
|
+
|
|
509
|
+
def getMaxValue(self, columns: Optional[Union[str, List[str]]] = None) -> float:
|
|
510
|
+
"""
|
|
511
|
+
Get the maximum value across chosen columns
|
|
512
|
+
|
|
513
|
+
Parameters
|
|
514
|
+
----------
|
|
515
|
+
columns : str | List[str], optional
|
|
516
|
+
Columns to find maximum values in, by default None
|
|
517
|
+
|
|
518
|
+
Returns
|
|
519
|
+
-------
|
|
520
|
+
float
|
|
521
|
+
Maximum value
|
|
522
|
+
"""
|
|
523
|
+
return self._getMetric(metric="max", columns=columns)
|
|
524
|
+
|
|
525
|
+
def getMinValue(self, columns: Optional[Union[str, List[str]]] = None) -> float:
|
|
526
|
+
"""
|
|
527
|
+
Get the minimum value across chosen columns
|
|
528
|
+
|
|
529
|
+
Parameters
|
|
530
|
+
----------
|
|
531
|
+
columns : str | List[str], optional
|
|
532
|
+
Columns to find minimum values in, by default None
|
|
533
|
+
|
|
534
|
+
Returns
|
|
535
|
+
-------
|
|
536
|
+
float
|
|
537
|
+
Minimum value
|
|
538
|
+
"""
|
|
539
|
+
return self._getMetric(metric="min", columns=columns)
|
|
540
|
+
|
|
541
|
+
def getMeanValue(self, columns: Optional[Union[str, List[str]]] = None) -> float:
|
|
542
|
+
"""
|
|
543
|
+
Get the mean value across chosen columns
|
|
544
|
+
|
|
545
|
+
Parameters
|
|
546
|
+
----------
|
|
547
|
+
columns : str | List[str], optional
|
|
548
|
+
Columns to find mean values in, by default None
|
|
549
|
+
|
|
550
|
+
Returns
|
|
551
|
+
-------
|
|
552
|
+
float
|
|
553
|
+
Mean value
|
|
554
|
+
"""
|
|
555
|
+
return self._getMetric(metric="mean", columns=columns)
|
|
556
|
+
|
|
557
|
+
def getMaxAbsValue(self, columns: Optional[Union[str, List[str]]] = None) -> float:
|
|
558
|
+
"""
|
|
559
|
+
Get the maximum absolute value across chosen columns
|
|
560
|
+
|
|
561
|
+
Parameters
|
|
562
|
+
----------
|
|
563
|
+
columns : str | List[str], optional
|
|
564
|
+
Columns to find maximum absolute values in, by default None
|
|
565
|
+
|
|
566
|
+
Returns
|
|
567
|
+
-------
|
|
568
|
+
float
|
|
569
|
+
Maximum absolute value
|
|
570
|
+
"""
|
|
571
|
+
return self._getMetric(metric="absmax", columns=columns)
|
|
572
|
+
|
|
573
|
+
def _getMetric(self, metric, columns):
|
|
574
|
+
# ARG: metric
|
|
575
|
+
if not isinstance(metric, str):
|
|
576
|
+
raise TypeError("Argument 'metric' must be type str")
|
|
577
|
+
|
|
578
|
+
if metric not in [
|
|
579
|
+
"max",
|
|
580
|
+
"min",
|
|
581
|
+
"mean",
|
|
582
|
+
"absmax",
|
|
583
|
+
]:
|
|
584
|
+
return ValueError(
|
|
585
|
+
"Argument 'metric' is currently limited to str type 'max', 'min' or 'mean', absmax"
|
|
586
|
+
)
|
|
587
|
+
|
|
588
|
+
# ARG: columns
|
|
589
|
+
# set defaults
|
|
590
|
+
if columns is None:
|
|
591
|
+
if isinstance(self, abcs.ABCParameter):
|
|
592
|
+
columns = "value"
|
|
593
|
+
elif isinstance(self, (abcs.ABCVariable, abcs.ABCEquation)):
|
|
594
|
+
columns = "level"
|
|
595
|
+
|
|
596
|
+
# checks
|
|
597
|
+
if not isinstance(columns, (str, list)):
|
|
598
|
+
raise TypeError(
|
|
599
|
+
f"Argument 'columns' must be type str or list. User passed {type(columns)}."
|
|
600
|
+
)
|
|
601
|
+
|
|
602
|
+
if isinstance(columns, str):
|
|
603
|
+
columns = [columns]
|
|
604
|
+
|
|
605
|
+
if any(not isinstance(i, str) for i in columns):
|
|
606
|
+
raise TypeError(f"Argument 'columns' must contain only type str.")
|
|
607
|
+
|
|
608
|
+
if any(i not in self._attributes for i in columns):
|
|
609
|
+
raise TypeError(
|
|
610
|
+
f"Argument 'columns' must be a subset of the following: {self._attributes}"
|
|
611
|
+
)
|
|
612
|
+
|
|
613
|
+
if self.records is not None:
|
|
614
|
+
if metric == "max":
|
|
615
|
+
return self.records[columns].max().max()
|
|
616
|
+
elif metric == "min":
|
|
617
|
+
return self.records[columns].min().min()
|
|
618
|
+
elif metric == "mean":
|
|
619
|
+
if not (
|
|
620
|
+
self.records[columns].min().min() == float("-inf")
|
|
621
|
+
and self.records[columns].max().max() == float("inf")
|
|
622
|
+
):
|
|
623
|
+
return self.records[columns].mean().mean()
|
|
624
|
+
else:
|
|
625
|
+
return float("nan")
|
|
626
|
+
elif metric == "absmax":
|
|
627
|
+
return self.records[columns].abs().max().max()
|
|
@@ -0,0 +1,27 @@
|
|
|
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
|
+
|
|
27
|
+
class SAMixin: ...
|
|
@@ -0,0 +1,27 @@
|
|
|
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
|
+
|
|
27
|
+
class SAPVEMixin: ...
|