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.
Files changed (257) hide show
  1. gams/__init__.py +27 -0
  2. gams/_version.py +1 -0
  3. gams/connect/__init__.py +28 -0
  4. gams/connect/agents/__init__.py +24 -0
  5. gams/connect/agents/_excel/__init__.py +32 -0
  6. gams/connect/agents/_excel/excelagent.py +312 -0
  7. gams/connect/agents/_excel/workbook.py +155 -0
  8. gams/connect/agents/_sqlconnectors/__init__.py +42 -0
  9. gams/connect/agents/_sqlconnectors/_accesshandler.py +211 -0
  10. gams/connect/agents/_sqlconnectors/_databasehandler.py +250 -0
  11. gams/connect/agents/_sqlconnectors/_mysqlhandler.py +168 -0
  12. gams/connect/agents/_sqlconnectors/_postgreshandler.py +131 -0
  13. gams/connect/agents/_sqlconnectors/_pyodbchandler.py +112 -0
  14. gams/connect/agents/_sqlconnectors/_sqlalchemyhandler.py +74 -0
  15. gams/connect/agents/_sqlconnectors/_sqlitehandler.py +262 -0
  16. gams/connect/agents/_sqlconnectors/_sqlserverhandler.py +179 -0
  17. gams/connect/agents/concatenate.py +440 -0
  18. gams/connect/agents/connectagent.py +743 -0
  19. gams/connect/agents/csvreader.py +675 -0
  20. gams/connect/agents/csvwriter.py +151 -0
  21. gams/connect/agents/domainwriter.py +143 -0
  22. gams/connect/agents/excelreader.py +756 -0
  23. gams/connect/agents/excelwriter.py +467 -0
  24. gams/connect/agents/filter.py +223 -0
  25. gams/connect/agents/gamsreader.py +112 -0
  26. gams/connect/agents/gamswriter.py +239 -0
  27. gams/connect/agents/gdxreader.py +109 -0
  28. gams/connect/agents/gdxwriter.py +146 -0
  29. gams/connect/agents/labelmanipulator.py +303 -0
  30. gams/connect/agents/projection.py +539 -0
  31. gams/connect/agents/pythoncode.py +71 -0
  32. gams/connect/agents/rawcsvreader.py +248 -0
  33. gams/connect/agents/rawexcelreader.py +312 -0
  34. gams/connect/agents/schema/CSVReader.yaml +92 -0
  35. gams/connect/agents/schema/CSVWriter.yaml +44 -0
  36. gams/connect/agents/schema/Concatenate.yaml +52 -0
  37. gams/connect/agents/schema/DomainWriter.yaml +25 -0
  38. gams/connect/agents/schema/ExcelReader.yaml +121 -0
  39. gams/connect/agents/schema/ExcelWriter.yaml +78 -0
  40. gams/connect/agents/schema/Filter.yaml +74 -0
  41. gams/connect/agents/schema/GAMSReader.yaml +20 -0
  42. gams/connect/agents/schema/GAMSWriter.yaml +47 -0
  43. gams/connect/agents/schema/GDXReader.yaml +23 -0
  44. gams/connect/agents/schema/GDXWriter.yaml +32 -0
  45. gams/connect/agents/schema/LabelManipulator.yaml +99 -0
  46. gams/connect/agents/schema/Projection.yaml +24 -0
  47. gams/connect/agents/schema/PythonCode.yaml +6 -0
  48. gams/connect/agents/schema/RawCSVReader.yaml +34 -0
  49. gams/connect/agents/schema/RawExcelReader.yaml +42 -0
  50. gams/connect/agents/schema/SQLReader.yaml +75 -0
  51. gams/connect/agents/schema/SQLWriter.yaml +103 -0
  52. gams/connect/agents/sqlreader.py +301 -0
  53. gams/connect/agents/sqlwriter.py +276 -0
  54. gams/connect/connectdatabase.py +275 -0
  55. gams/connect/connectvalidator.py +93 -0
  56. gams/connect/errors.py +34 -0
  57. gams/control/__init__.py +136 -0
  58. gams/control/database.py +2231 -0
  59. gams/control/execution.py +1900 -0
  60. gams/control/options.py +2792 -0
  61. gams/control/workspace.py +1198 -0
  62. gams/core/__init__.py +24 -0
  63. gams/core/cfg/__init__.py +26 -0
  64. gams/core/cfg/_cfgmcc.cp312-win_amd64.pyd +0 -0
  65. gams/core/cfg/cfgmcc.py +519 -0
  66. gams/core/dct/__init__.py +26 -0
  67. gams/core/dct/_dctmcc.cp312-win_amd64.pyd +0 -0
  68. gams/core/dct/dctmcc.py +574 -0
  69. gams/core/embedded/__init__.py +26 -0
  70. gams/core/embedded/gamsemb.py +1024 -0
  71. gams/core/emp/__init__.py +24 -0
  72. gams/core/emp/emplexer.py +89 -0
  73. gams/core/emp/empyacc.py +281 -0
  74. gams/core/gdx/__init__.py +26 -0
  75. gams/core/gdx/_gdxcc.cp312-win_amd64.pyd +0 -0
  76. gams/core/gdx/gdxcc.py +866 -0
  77. gams/core/gev/__init__.py +26 -0
  78. gams/core/gev/_gevmcc.cp312-win_amd64.pyd +0 -0
  79. gams/core/gev/gevmcc.py +855 -0
  80. gams/core/gmd/__init__.py +26 -0
  81. gams/core/gmd/_gmdcc.cp312-win_amd64.pyd +0 -0
  82. gams/core/gmd/gmdcc.py +917 -0
  83. gams/core/gmo/__init__.py +26 -0
  84. gams/core/gmo/_gmomcc.cp312-win_amd64.pyd +0 -0
  85. gams/core/gmo/gmomcc.py +2046 -0
  86. gams/core/idx/__init__.py +26 -0
  87. gams/core/idx/_idxcc.cp312-win_amd64.pyd +0 -0
  88. gams/core/idx/idxcc.py +510 -0
  89. gams/core/numpy/__init__.py +29 -0
  90. gams/core/numpy/_gams2numpy.cp312-win_amd64.pyd +0 -0
  91. gams/core/numpy/gams2numpy.py +1048 -0
  92. gams/core/opt/__init__.py +26 -0
  93. gams/core/opt/_optcc.cp312-win_amd64.pyd +0 -0
  94. gams/core/opt/optcc.py +840 -0
  95. gams/engine/__init__.py +204 -0
  96. gams/engine/api/__init__.py +13 -0
  97. gams/engine/api/auth_api.py +7653 -0
  98. gams/engine/api/cleanup_api.py +751 -0
  99. gams/engine/api/default_api.py +887 -0
  100. gams/engine/api/hypercube_api.py +2629 -0
  101. gams/engine/api/jobs_api.py +5229 -0
  102. gams/engine/api/licenses_api.py +2220 -0
  103. gams/engine/api/namespaces_api.py +7783 -0
  104. gams/engine/api/usage_api.py +5627 -0
  105. gams/engine/api/users_api.py +5931 -0
  106. gams/engine/api_client.py +804 -0
  107. gams/engine/api_response.py +21 -0
  108. gams/engine/configuration.py +601 -0
  109. gams/engine/exceptions.py +216 -0
  110. gams/engine/models/__init__.py +86 -0
  111. gams/engine/models/bad_input.py +89 -0
  112. gams/engine/models/cleanable_job_result.py +104 -0
  113. gams/engine/models/cleanable_job_result_page.py +113 -0
  114. gams/engine/models/engine_license.py +107 -0
  115. gams/engine/models/files_not_found.py +93 -0
  116. gams/engine/models/forwarded_token_response.py +112 -0
  117. gams/engine/models/generic_key_value_pair.py +89 -0
  118. gams/engine/models/hypercube.py +160 -0
  119. gams/engine/models/hypercube_page.py +111 -0
  120. gams/engine/models/hypercube_summary.py +91 -0
  121. gams/engine/models/hypercube_token.py +97 -0
  122. gams/engine/models/identity_provider.py +107 -0
  123. gams/engine/models/identity_provider_ldap.py +121 -0
  124. gams/engine/models/identity_provider_oauth2.py +146 -0
  125. gams/engine/models/identity_provider_oauth2_scope.py +89 -0
  126. gams/engine/models/identity_provider_oauth2_with_secret.py +152 -0
  127. gams/engine/models/identity_provider_oidc.py +133 -0
  128. gams/engine/models/identity_provider_oidc_with_secret.py +143 -0
  129. gams/engine/models/inex.py +91 -0
  130. gams/engine/models/invitation.py +136 -0
  131. gams/engine/models/invitation_quota.py +106 -0
  132. gams/engine/models/invitation_token.py +87 -0
  133. gams/engine/models/job.py +165 -0
  134. gams/engine/models/job_no_text_entry.py +138 -0
  135. gams/engine/models/job_no_text_entry_page.py +111 -0
  136. gams/engine/models/license.py +91 -0
  137. gams/engine/models/log_piece.py +96 -0
  138. gams/engine/models/message.py +87 -0
  139. gams/engine/models/message_and_token.py +99 -0
  140. gams/engine/models/message_with_webhook_id.py +89 -0
  141. gams/engine/models/model_auth_token.py +87 -0
  142. gams/engine/models/model_configuration.py +125 -0
  143. gams/engine/models/model_default_instance.py +99 -0
  144. gams/engine/models/model_default_user_instance.py +98 -0
  145. gams/engine/models/model_hypercube_job.py +106 -0
  146. gams/engine/models/model_hypercube_usage.py +130 -0
  147. gams/engine/models/model_instance_info.py +116 -0
  148. gams/engine/models/model_instance_info_full.py +123 -0
  149. gams/engine/models/model_instance_pool_info.py +112 -0
  150. gams/engine/models/model_job_labels.py +179 -0
  151. gams/engine/models/model_job_usage.py +133 -0
  152. gams/engine/models/model_pool_usage.py +124 -0
  153. gams/engine/models/model_usage.py +115 -0
  154. gams/engine/models/model_user.py +96 -0
  155. gams/engine/models/model_userinstance_info.py +119 -0
  156. gams/engine/models/model_userinstancepool_info.py +95 -0
  157. gams/engine/models/model_version.py +91 -0
  158. gams/engine/models/models.py +120 -0
  159. gams/engine/models/namespace.py +104 -0
  160. gams/engine/models/namespace_quota.py +96 -0
  161. gams/engine/models/namespace_with_permission.py +96 -0
  162. gams/engine/models/not_found.py +91 -0
  163. gams/engine/models/password_policy.py +97 -0
  164. gams/engine/models/perm_and_username.py +89 -0
  165. gams/engine/models/quota.py +117 -0
  166. gams/engine/models/quota_exceeded.py +97 -0
  167. gams/engine/models/status_code_meaning.py +89 -0
  168. gams/engine/models/stream_entry.py +89 -0
  169. gams/engine/models/system_wide_license.py +92 -0
  170. gams/engine/models/text_entries.py +87 -0
  171. gams/engine/models/text_entry.py +101 -0
  172. gams/engine/models/time_span.py +95 -0
  173. gams/engine/models/time_span_pool_worker.py +99 -0
  174. gams/engine/models/token_forward_error.py +87 -0
  175. gams/engine/models/user.py +127 -0
  176. gams/engine/models/user_group_member.py +96 -0
  177. gams/engine/models/user_groups.py +108 -0
  178. gams/engine/models/vapid_info.py +87 -0
  179. gams/engine/models/webhook.py +138 -0
  180. gams/engine/models/webhook_parameterized_event.py +99 -0
  181. gams/engine/py.typed +0 -0
  182. gams/engine/rest.py +258 -0
  183. gams/magic/__init__.py +32 -0
  184. gams/magic/gams_magic.py +142 -0
  185. gams/magic/interactive.py +402 -0
  186. gams/tools/__init__.py +30 -0
  187. gams/tools/errors.py +34 -0
  188. gams/tools/toolcollection/__init__.py +24 -0
  189. gams/tools/toolcollection/alg/__init__.py +24 -0
  190. gams/tools/toolcollection/alg/rank.py +51 -0
  191. gams/tools/toolcollection/data/__init__.py +24 -0
  192. gams/tools/toolcollection/data/csvread.py +444 -0
  193. gams/tools/toolcollection/data/csvwrite.py +311 -0
  194. gams/tools/toolcollection/data/exceldump.py +47 -0
  195. gams/tools/toolcollection/data/sqlitewrite.py +276 -0
  196. gams/tools/toolcollection/gdxservice/__init__.py +24 -0
  197. gams/tools/toolcollection/gdxservice/gdxencoding.py +104 -0
  198. gams/tools/toolcollection/gdxservice/gdxrename.py +94 -0
  199. gams/tools/toolcollection/linalg/__init__.py +24 -0
  200. gams/tools/toolcollection/linalg/cholesky.py +57 -0
  201. gams/tools/toolcollection/linalg/eigenvalue.py +56 -0
  202. gams/tools/toolcollection/linalg/eigenvector.py +58 -0
  203. gams/tools/toolcollection/linalg/invert.py +55 -0
  204. gams/tools/toolcollection/linalg/ols.py +138 -0
  205. gams/tools/toolcollection/tooltemplate.py +321 -0
  206. gams/tools/toolcollection/win32/__init__.py +24 -0
  207. gams/tools/toolcollection/win32/excelmerge.py +93 -0
  208. gams/tools/toolcollection/win32/exceltalk.py +76 -0
  209. gams/tools/toolcollection/win32/msappavail.py +49 -0
  210. gams/tools/toolcollection/win32/shellexecute.py +54 -0
  211. gams/tools/tools.py +116 -0
  212. gams/transfer/__init__.py +35 -0
  213. gams/transfer/_abcs/__init__.py +37 -0
  214. gams/transfer/_abcs/container_abcs.py +433 -0
  215. gams/transfer/_internals/__init__.py +63 -0
  216. gams/transfer/_internals/algorithms.py +436 -0
  217. gams/transfer/_internals/casepreservingdict.py +124 -0
  218. gams/transfer/_internals/constants.py +270 -0
  219. gams/transfer/_internals/domainviolation.py +103 -0
  220. gams/transfer/_internals/specialvalues.py +172 -0
  221. gams/transfer/containers/__init__.py +26 -0
  222. gams/transfer/containers/_container.py +1794 -0
  223. gams/transfer/containers/_io/__init__.py +28 -0
  224. gams/transfer/containers/_io/containers.py +164 -0
  225. gams/transfer/containers/_io/gdx.py +1029 -0
  226. gams/transfer/containers/_io/gmd.py +872 -0
  227. gams/transfer/containers/_mixins/__init__.py +26 -0
  228. gams/transfer/containers/_mixins/ccc.py +1274 -0
  229. gams/transfer/syms/__init__.py +33 -0
  230. gams/transfer/syms/_methods/__init__.py +24 -0
  231. gams/transfer/syms/_methods/tables.py +120 -0
  232. gams/transfer/syms/_methods/toDict.py +115 -0
  233. gams/transfer/syms/_methods/toList.py +83 -0
  234. gams/transfer/syms/_methods/toValue.py +60 -0
  235. gams/transfer/syms/_mixins/__init__.py +32 -0
  236. gams/transfer/syms/_mixins/equals.py +626 -0
  237. gams/transfer/syms/_mixins/generateRecords.py +499 -0
  238. gams/transfer/syms/_mixins/pivot.py +313 -0
  239. gams/transfer/syms/_mixins/pve.py +627 -0
  240. gams/transfer/syms/_mixins/sa.py +27 -0
  241. gams/transfer/syms/_mixins/sapve.py +27 -0
  242. gams/transfer/syms/_mixins/saua.py +27 -0
  243. gams/transfer/syms/_mixins/sauapve.py +199 -0
  244. gams/transfer/syms/_mixins/spve.py +1528 -0
  245. gams/transfer/syms/_mixins/ve.py +936 -0
  246. gams/transfer/syms/container_syms/__init__.py +31 -0
  247. gams/transfer/syms/container_syms/_alias.py +984 -0
  248. gams/transfer/syms/container_syms/_equation.py +333 -0
  249. gams/transfer/syms/container_syms/_parameter.py +973 -0
  250. gams/transfer/syms/container_syms/_set.py +604 -0
  251. gams/transfer/syms/container_syms/_universe_alias.py +461 -0
  252. gams/transfer/syms/container_syms/_variable.py +321 -0
  253. gamsapi-52.5.0.dist-info/METADATA +150 -0
  254. gamsapi-52.5.0.dist-info/RECORD +257 -0
  255. gamsapi-52.5.0.dist-info/WHEEL +5 -0
  256. gamsapi-52.5.0.dist-info/licenses/LICENSE +22 -0
  257. gamsapi-52.5.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,321 @@
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 abc import ABC, abstractmethod
27
+ import string
28
+ import shlex
29
+ import os
30
+ import numpy as np
31
+ from gams.tools.errors import GamsToolsException
32
+
33
+ class ToolTemplate(ABC):
34
+ def __init__(self, system_directory, tools):
35
+ '''
36
+ :param system_directory: GAMS system directory to be used.
37
+ :param tools: An instance of gams.tools.tools.Tools.
38
+ '''
39
+ self._system_directory = system_directory
40
+ self._tools = tools
41
+ self._knowntypes = ["id.in", "id.in.list", "id.out", "id.out.list", "str", "str.list", "float", "float.list", "int", "int.list", "fnExist", "fnWriteable"]
42
+ self._posargsdef = {}
43
+ self._namedargsdef = {}
44
+ self.add_namedargdef("trace=traceLevel","int","Set tracing level",0)
45
+ self._trace = 0
46
+ self._lastpositem = {}
47
+ self.posargs = []
48
+ self.namedargs = {}
49
+ self.namedargs_list = []
50
+
51
+ def add_posargdef(self, argid, argtype, argtext):
52
+ if ":" in argtype:
53
+ t = argtype.split(':')[0]
54
+ else:
55
+ t = argtype
56
+ if not t in self._knowntypes:
57
+ self.tool_error(f'Unknown argument type {t} for positional arguent {argid}')
58
+ if self._lastpositem.get("argtype",'').endswith('.list'):
59
+ self.tool_error(f'Cannot have additional positional arguments after entry of type list')
60
+ self._posargsdef[argid.lower()] = {"argid":argid, "argtype":argtype, "argtext":argtext}
61
+ self._lastpositem = self._posargsdef[argid.lower()]
62
+
63
+ def add_namedargdef(self, argid, argtype, argtext, argdefault=None, shell_req=False, multi_occurance=False):
64
+ if not argtype.split(':')[0] in self._knowntypes:
65
+ self.tool_error(f'Unknown argument type {argtype} for named arguent {argid}')
66
+ self._namedargsdef[argid.split('=')[0].lower()] = {"argid":argid, "argtype":argtype, "argtext":argtext, "argdefault":argdefault, "shell_req":shell_req, "multi_occurance":multi_occurance}
67
+
68
+ def check_gt_sym(self, m, id, argtype):
69
+ import gams.transfer as gt
70
+ typemap = {gt.Set:'set', gt.Alias:'set', gt.Parameter:'par', gt.Variable:'var', gt.Equation:'equ'}
71
+ try:
72
+ sym = m[id]
73
+ except:
74
+ self.tool_error(f'Could not find symbol "{id}" in GTP container')
75
+
76
+ ign, id_type, id_dim = argtype.split(':')
77
+ id_dim = int(id_dim)
78
+ if id_dim != -1 and id_dim != sym.dimension:
79
+ self.tool_error(f'Dimension of symbols "{id}" does not match expected {id_dim}<>{sym.dimension} (actual)')
80
+ if id_type != 'any' and typemap[type(sym)] not in id_type:
81
+ self.tool_error(f'Unexpected type {typemap[type(sym)]} of symbol "{id}", allow is/are {id_type}')
82
+
83
+ def convert_type(self, val, val_type='any'):
84
+ if "." in val_type:
85
+ v_type = val_type.split('.')[0]
86
+ else:
87
+ v_type = val_type
88
+ if v_type == "int":
89
+ try:
90
+ return int(val)
91
+ except:
92
+ self.tool_error(f'Cannot convert option value "{val}" into an integer')
93
+ elif v_type == "float":
94
+ try:
95
+ return float(val)
96
+ except:
97
+ self.tool_error(f'Cannot convert option value "{val}" into a float')
98
+ elif v_type == "id":
99
+ allowed = set(string.ascii_lowercase + string.ascii_uppercase + string.digits + '_')
100
+ if not set(val) <= allowed or len(val) == 0 or val[0] == "_" or len(val) > 63:
101
+ self.tool_error(f'String "{val}" is not a good GAMS identifier')
102
+ return val
103
+ elif v_type == "fnExist":
104
+ if not (os.path.isfile(val) and os.access(val, os.R_OK)):
105
+ self.tool_error(f'File "{val}" does not exist or cannot be read')
106
+ return val
107
+ else:
108
+ return val
109
+
110
+ def namedargs_val(self, key):
111
+ key = key.lower()
112
+ if key in self.namedargs:
113
+ if self._namedargsdef[key]["multi_occurance"]:
114
+ return [ self.namedargs_list[i][1] for i in self.namedargs[key] ]
115
+ else:
116
+ return self.namedargs[key]
117
+ else:
118
+ return self._namedargsdef[key]["argdefault"]
119
+
120
+ def _check_ids(self, m, io):
121
+ # positional arguments
122
+ for n,ko in enumerate(self._posargsdef.items()):
123
+ k,o = ko
124
+ if o["argtype"].startswith(f'id.{io}'):
125
+ self.check_gt_sym(m,self.posargs[n],o["argtype"])
126
+ if len(self._posargsdef) < len(self.posargs) and self._lastpositem["argtype"] == f'id.{io}.list':
127
+ for id in self.posargs[len(self._posargsdef):]:
128
+ self.check_gt_sym(m,id,self._lastpositem["argtype"])
129
+ # named arguments
130
+ for k,o in self._namedargsdef.items():
131
+ if k in self.namedargs and o["argtype"].startswith(f'id.{io}'):
132
+ if o["multi_occurance"]:
133
+ for lp in self.namedargs[k]:
134
+ self.check_gt_sym(m,self.namedargs_list[lp][1],o["argtype"])
135
+ else:
136
+ self.check_gt_sym(m,self.namedargs[k],o["argtype"])
137
+
138
+ def check_input_ids(self, m):
139
+ self._check_ids(m,'in')
140
+
141
+ def check_output_ids(self, m):
142
+ self._check_ids(m,'out')
143
+
144
+ def process_args(self):
145
+ numpos = 0
146
+ argv_start = 1
147
+ posarglist = False
148
+ # Process positional arguments
149
+ for s in self._tools._argv[argv_start:]:
150
+ if posarglist: # stop when we have a named argument
151
+ if "=" in s: break
152
+ if s[0] == "-": break
153
+ if s.lower() in self._namedargsdef: break
154
+ else:
155
+ if numpos == len(self._posargsdef):
156
+ break
157
+ numpos += 1
158
+ if ("=" in s) and ((s.split('=')[0]).lower() in self._namedargsdef):
159
+ self.tool_error(f'Looking for positional argument no {numpos}. Got positional argument {(s.split("=")[0]).lower()}')
160
+ if s[0] == "-":
161
+ self.tool_error(f'Looking for positional argument no {numpos}. Got token ({s}) starting with "-"')
162
+ posarglist = len(self._posargsdef) == numpos and self._lastpositem["argtype"].endswith('.list')
163
+ arg_value = self.convert_type(s,list(self._posargsdef.items())[numpos-1][1]["argtype"])
164
+ self.posargs.append(arg_value)
165
+ argv_start += 1
166
+
167
+ if not posarglist and len(self.posargs) != len(self._posargsdef):
168
+ self.tool_error(f'Expect {len(self._posargsdef)} argument(s), got {self.posargs}.')
169
+
170
+ # Process named arguments
171
+ proc_value = False
172
+ alist = self._tools._argv[argv_start:]
173
+ while len(alist):
174
+ if not proc_value:
175
+ key = alist.pop(0)
176
+ if "=" in key:
177
+ kv = key.split('=')
178
+ if len(kv) > 2:
179
+ self.tool_error(f'More than one "=" in argument token "{key}"')
180
+ key = kv[0]
181
+ if len(kv[1]):
182
+ alist.insert(0,kv[1])
183
+ if key[0] == "-": key = key[1:]
184
+ key = key.lower()
185
+ if not key in self._namedargsdef:
186
+ #self.help()
187
+ self.tool_error(f'Unknown named argument "{key}"')
188
+ if self._namedargsdef[key]["argtype"] == "None":
189
+ address = len(self.namedargs_list)
190
+ self.namedargs_list.append((key,None))
191
+ if self._namedargsdef[key]["multi_occurance"]:
192
+ if key in self.namedargs:
193
+ self.namedargs[key].append(address)
194
+ else:
195
+ self.namedargs[key] = [address]
196
+ else:
197
+ self.namedargs[key] = None # set or update
198
+ if len(alist) == 0:
199
+ break
200
+ else:
201
+ proc_value = True
202
+ continue
203
+ else: # process value
204
+ val = alist.pop(0)
205
+ if val == "=":
206
+ continue
207
+ if val[0] == "=": val = val[1:]
208
+ address = len(self.namedargs_list)
209
+ if self._namedargsdef[key]["argtype"].endswith('.list'):
210
+ val_list = [ self.convert_type(li.strip(),self._namedargsdef[key]["argtype"]) for li in val.split(',') if len(li)]
211
+ self.namedargs_list.append((key,val_list))
212
+ else:
213
+ self.namedargs_list.append((key,self.convert_type(val,self._namedargsdef[key]["argtype"])))
214
+ if self._namedargsdef[key]["multi_occurance"]:
215
+ if key in self.namedargs:
216
+ self.namedargs[key].append(address)
217
+ else:
218
+ self.namedargs[key] = [address]
219
+ else:
220
+ self.namedargs[key] = self.namedargs_list[-1][1] # set or update
221
+ proc_value = False
222
+ if proc_value:
223
+ self.tool_error(f'Unexpected end while processing value for argument {key}')
224
+
225
+ if not self._tools._ecdb:
226
+ for k,o in self._namedargsdef.items():
227
+ if o["shell_req"] and not k in self.namedargs:
228
+ self.tool_error(f'Command line use requires {o["argid"]}.')
229
+ if "trace" in self.namedargs:
230
+ self._trace = int(self.namedargs["trace"])
231
+
232
+ def read_id_inputs(self, m, inputs):
233
+ if 'gdxin' in self.namedargs: # get data from GDX
234
+ try:
235
+ m.read(self.namedargs['gdxin'], inputs)
236
+ except Exception as e:
237
+ self.tool_error(str(e))
238
+ else:
239
+ try:
240
+ m.read(self._tools._ecdb._gmd, inputs)
241
+ except Exception as e:
242
+ self.tool_error(str(e))
243
+ self.check_input_ids(m)
244
+
245
+ def write_id_outputs(self, m, outputs):
246
+ self.check_output_ids(m)
247
+ if 'gdxout' in self.namedargs: # write data to GDX
248
+ try:
249
+ m.write(self.namedargs['gdxout'], outputs)
250
+ except Exception as e:
251
+ self.tool_error(str(e))
252
+ else:
253
+ try:
254
+ m.write(self._tools._ecdb._gmd, outputs)
255
+ except Exception as e:
256
+ self.tool_error(str(e))
257
+
258
+ def dohelp(self):
259
+ if len(self._tools._argv) == 1 or self._tools._argv[1].lower() == "-h":
260
+ self.help(long=False)
261
+ return True
262
+ elif self._tools._argv[1].lower() == "--help":
263
+ self.help()
264
+ return True
265
+ else:
266
+ return False
267
+
268
+ def help(self, prefix='', long=True):
269
+ self._tools.print_log(f'{prefix}{self.title}')
270
+ usage = f"Usage: {self.title.split(':')[0]}"
271
+ maxlen = -1
272
+ for k,o in self._posargsdef.items():
273
+ if len(usage) > 75:
274
+ self._tools.print_log(f'{prefix}{usage}')
275
+ usage = " "*len(f"Usage: {self.title.split(':')[0]}")
276
+ usage += f' {o["argid"]}'
277
+ maxlen = max(maxlen,len(o["argid"]))
278
+ for k,o in self._namedargsdef.items():
279
+ if len(usage) > 75:
280
+ self._tools.print_log(f'{prefix}{usage}')
281
+ usage = " "*len(f"Usage: {self.title.split(':')[0]}")
282
+ usage += f' {o["argid"]}'
283
+ maxlen = max(maxlen,len(o["argid"].split('=')[0]))
284
+ self._tools.print_log(f'{prefix}{usage}')
285
+ if long:
286
+ for k,o in self._posargsdef.items():
287
+ s = f'{o["argid"]}:'.ljust(maxlen+2)
288
+ self._tools.print_log(f'{prefix} {s} {o["argtext"]}')
289
+ for k,o in self._namedargsdef.items():
290
+ s = f'{o["argid"].split("=")[0]}:'.ljust(maxlen+2)
291
+ t = o["argtext"]
292
+ if "\n" in t:
293
+ pf = " "*len(f'{prefix} {s} ')
294
+ if not o["argdefault"] is None:
295
+ t = t.replace('\n',f' (default {o["argdefault"]})\n',1)
296
+ t = t.replace('\n','\n'+pf)
297
+ else:
298
+ if not o["argdefault"] is None:
299
+ t = t + f' (default {o["argdefault"]})'
300
+ self._tools.print_log(f'{prefix} {s} {t}')
301
+
302
+ def tool_error(self, msg, print_help=True):
303
+ if print_help:
304
+ self.help(long=False)
305
+ raise GamsToolsException(msg, error_code=1, traceback=self._trace>0)
306
+
307
+ def is_upper_matrix(self, a):
308
+ if not np.allclose(a, a.T):
309
+ if not np.allclose(a, np.tril(a)):
310
+ if np.allclose(a, np.triu(a)):
311
+ return True
312
+ else:
313
+ self.tool_error(f'Matrix {A} is not symmetric and does not have a triangular structure.', print_help=False)
314
+ return False
315
+
316
+ @abstractmethod
317
+ def execute(self):
318
+ '''
319
+ Called by Tools. This abstract method needs to be implemented by a subclass.
320
+ '''
321
+ ...
@@ -0,0 +1,24 @@
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
+ #
@@ -0,0 +1,93 @@
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 gams.tools.toolcollection.tooltemplate import ToolTemplate
27
+ import os
28
+
29
+ class Excelmerge (ToolTemplate):
30
+
31
+ def __init__(self, system_directory, tool):
32
+ super().__init__(system_directory, tool)
33
+ self.title = 'excelmerge: Merges the sheets of the source Excel workbook into the destination workbook (MS Windows only).'
34
+ self.add_posargdef('sourceExcelFile', 'fnExist', 'Source Excel workbook filename')
35
+ self.add_posargdef('targetExcelFile', 'str', 'Merged Excel workbook filename')
36
+
37
+ def execute(self):
38
+ if self.dohelp():
39
+ return
40
+ if os.name != 'nt':
41
+ self.tool_error('excelmerge only for MS Windows', print_help=False)
42
+
43
+ self.process_args()
44
+ sourceName, targetName = self.posargs
45
+
46
+ try:
47
+ import win32com.client as w3c
48
+
49
+ xl = w3c.gencache.EnsureDispatch("Excel.Application")
50
+ except:
51
+ self.tool_error(f'Could not dispatch Excel', print_help=False)
52
+
53
+ if not os.path.isabs(targetName):
54
+ targetName = os.path.join(os.getcwd(), targetName)
55
+ if not os.path.isabs(sourceName):
56
+ sourceName = os.path.join(os.getcwd(), sourceName)
57
+
58
+ try:
59
+ target = xl.Workbooks.Open(Filename=targetName)
60
+ except:
61
+ self.tool_error(f'Could not open target Excel workbook "{targetName}"', print_help=False)
62
+
63
+ target_sheetnames = {sheet.Name: i for i, sheet in enumerate(target.Sheets)}
64
+
65
+ # required to overide the delete prompt shown by MS-Excel
66
+ xl.DisplayAlerts = False
67
+
68
+ try:
69
+ source_sheets = xl.Workbooks.Open(Filename=sourceName).Sheets
70
+ except:
71
+ self.tool_error(f'Could not extract sheets from Excel workbook "{sourceName}"', print_help=False)
72
+
73
+ for sheet in source_sheets:
74
+ if not sheet.Name in target_sheetnames.keys():
75
+ sheet.Copy(Before=None, After=target.Worksheets(target.Sheets.Count)) # append at the end
76
+ else:
77
+ # if only one sheet exists in dest add a temporary sheet so workbook is never empty
78
+ if target.Sheets.Count == 1:
79
+ add_dummy_sheet = target.Sheets.Add(Before = None , After = target.Sheets(1))
80
+ target.Worksheets(sheet.Name).Delete()
81
+ sheet.Copy(Before=target.Worksheets(1))
82
+ add_dummy_sheet.Delete()
83
+ else:
84
+ target.Worksheets(sheet.Name).Delete()
85
+ if target_sheetnames[sheet.Name] == 0:
86
+ sheet.Copy(Before=target.Worksheets(1))
87
+ else:
88
+ sheet.Copy(Before=None, After=target.Worksheets(target_sheetnames[sheet.Name]))
89
+ try:
90
+ target.Close(SaveChanges=True)
91
+ xl.Quit()
92
+ except:
93
+ self.tool_error(f'Could not save and close Excel workbook "{targetName}"', print_help=False)
@@ -0,0 +1,76 @@
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 gams.tools.toolcollection.tooltemplate import ToolTemplate
27
+ import os
28
+
29
+ class Exceltalk (ToolTemplate):
30
+
31
+ def __init__(self, system_directory, tool):
32
+ super().__init__(system_directory, tool)
33
+ self.title = 'exceltalk: Performs command on an Excel workbook specified by filename (MS Windows only).'
34
+ self.add_posargdef('command', 'str', 'Recognized commands are\n close: Close workbook ignoring changes\n open: Opens workbook\n saveAndClose: Perform save & close of the workbook')
35
+ self.add_posargdef('excelFile', 'fnExist', 'Excel workbook filename')
36
+ self.add_namedargdef('quit=0|1', 'int', 'Determines if Excel program should be terminated or not', argdefault=0)
37
+
38
+ def execute(self):
39
+ if self.dohelp():
40
+ return
41
+ if os.name != 'nt':
42
+ self.tool_error('exceltalk only for MS Windows', print_help=False)
43
+
44
+ self.process_args()
45
+ command, excelFile = self.posargs
46
+ quitExcel = self.namedargs_val("quit")
47
+
48
+ try:
49
+ import win32com.client as w3c
50
+
51
+ xl = w3c.gencache.EnsureDispatch("Excel.Application")
52
+ except:
53
+ self.tool_error(f'Could not dispatch Excel', print_help=False)
54
+
55
+ if command.lower() in ['close', 'saveandclose']:
56
+ excelFile = os.path.basename(excelFile)
57
+ for obj in xl.Workbooks:
58
+ if obj.Name.lower() == excelFile.lower():
59
+ wb = obj
60
+ break
61
+ else:
62
+ self.tool_error(f'No workbook with name "{excelFile}" found', print_help=False)
63
+ try:
64
+ wb.Close(SaveChanges=command.lower() == 'saveandclose')
65
+ except:
66
+ self.tool_error(f'Could not close Excel workbook {excelFile}', print_help=False)
67
+ elif command.lower() == 'open':
68
+ try:
69
+ xl.Visible = True
70
+ xl.Workbooks.Open(os.path.abspath(excelFile))
71
+ except:
72
+ self.tool_error(f'Could not open Excel workbook {os.path.abspath(excelFile)}', print_help=False)
73
+ else:
74
+ self.tool_error(f'Unknown command : "{command}"')
75
+ if quitExcel != 0:
76
+ xl.Quit()
@@ -0,0 +1,49 @@
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 gams.tools.toolcollection.tooltemplate import ToolTemplate
27
+ import os
28
+
29
+ class Msappavail (ToolTemplate):
30
+
31
+ def __init__(self, system_directory, tool):
32
+ super().__init__(system_directory, tool)
33
+ self.title = 'msappavail: Checks if a MS Office Application is available (MS Windows only).'
34
+ self.add_posargdef('application', 'str', 'MS Office application name')
35
+
36
+ def execute(self):
37
+ if self.dohelp():
38
+ return
39
+ if os.name != 'nt':
40
+ self.tool_error('msappavail only for MS Windows', print_help=False)
41
+
42
+ self.process_args()
43
+ import ctypes
44
+ try:
45
+ rc = ctypes.oledll.ole32.CLSIDFromProgID(f'{self.posargs[0]}.Application',ctypes.byref(ctypes.c_void_p()))
46
+ except:
47
+ rc = 1
48
+ if 0 != rc:
49
+ self.tool_error(f'Application {self.posargs[0]} not available', print_help=False)
@@ -0,0 +1,54 @@
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 gams.tools.toolcollection.tooltemplate import ToolTemplate
27
+ import os
28
+
29
+ class Shellexecute (ToolTemplate):
30
+
31
+ def __init__(self, system_directory, tool):
32
+ super().__init__(system_directory, tool)
33
+ self.title = 'shellexecute: This allows to spawn an external program based on the file type of the document to open. (MS Windows only)'
34
+ self.add_posargdef('progargs', 'str.list', 'Program and arguments')
35
+ self.add_namedargdef('dir=workdir', 'str', 'The directory where the file to be opened is located', argdefault='.')
36
+ self.add_namedargdef('verb=open|...', 'str', 'Action to be performed.\nThe allowed actions are application dependent.\nSome commonly available actions include\n-edit: Launches an editor and opens the document for editing\n-find: Initiates a search starting from the specified directory\n-open: Launches an application. If this file is not an executable file, its associated application is launched\nprint: Prints the document file\nproperties: Displays the objects properties', argdefault='open')
37
+ self.add_namedargdef('showCmd=0..11','int', 'Specifies how an application is to be displayed when it is opened\n The map between numerical values 0 to 11 and symbolic names can be found here:\nhttps://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-showwindow', argdefault=0)
38
+
39
+ def execute(self):
40
+ if self.dohelp():
41
+ return
42
+ if os.name != 'nt':
43
+ self.tool_error('shellexecute only for MS Windows', print_help=False)
44
+
45
+ self.process_args()
46
+ pargs = self.posargs[0].split()
47
+
48
+ import ctypes
49
+ try:
50
+ rc = ctypes.windll.shell32.ShellExecuteW(None, self.namedargs_val("verb"), pargs[0], ' '.join(pargs[1:]), self.namedargs_val("dir"), self.namedargs_val("showCmd"))
51
+ if rc < 32:
52
+ self.tool_error(ctypes.WinError())
53
+ except Exception as e:
54
+ self.tool_error(str(e), print_help=False)