gamsapi 52.2.0__cp314-cp314-win_amd64.whl → 52.4.0__cp314-cp314-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 +2 -2
- gams/_version.py +1 -1
- gams/connect/__init__.py +2 -2
- gams/connect/agents/__init__.py +2 -2
- gams/connect/agents/_excel/__init__.py +2 -2
- gams/connect/agents/_excel/excelagent.py +2 -2
- gams/connect/agents/_excel/workbook.py +2 -2
- gams/connect/agents/_sqlconnectors/__init__.py +2 -2
- gams/connect/agents/_sqlconnectors/_accesshandler.py +2 -2
- gams/connect/agents/_sqlconnectors/_databasehandler.py +2 -2
- gams/connect/agents/_sqlconnectors/_mysqlhandler.py +2 -2
- gams/connect/agents/_sqlconnectors/_postgreshandler.py +2 -2
- gams/connect/agents/_sqlconnectors/_pyodbchandler.py +2 -2
- gams/connect/agents/_sqlconnectors/_sqlalchemyhandler.py +2 -2
- gams/connect/agents/_sqlconnectors/_sqlitehandler.py +2 -2
- gams/connect/agents/_sqlconnectors/_sqlserverhandler.py +2 -2
- gams/connect/agents/concatenate.py +2 -2
- gams/connect/agents/connectagent.py +2 -2
- gams/connect/agents/csvreader.py +2 -2
- gams/connect/agents/csvwriter.py +2 -2
- gams/connect/agents/domainwriter.py +2 -2
- gams/connect/agents/excelreader.py +2 -2
- gams/connect/agents/excelwriter.py +2 -2
- gams/connect/agents/filter.py +2 -2
- gams/connect/agents/gamsreader.py +2 -2
- gams/connect/agents/gamswriter.py +2 -2
- gams/connect/agents/gdxreader.py +2 -2
- gams/connect/agents/gdxwriter.py +2 -2
- gams/connect/agents/labelmanipulator.py +2 -2
- gams/connect/agents/projection.py +2 -2
- gams/connect/agents/pythoncode.py +2 -2
- gams/connect/agents/rawcsvreader.py +2 -2
- gams/connect/agents/rawexcelreader.py +2 -2
- gams/connect/agents/sqlreader.py +2 -2
- gams/connect/agents/sqlwriter.py +2 -2
- gams/connect/connectdatabase.py +2 -2
- gams/connect/connectvalidator.py +2 -2
- gams/connect/errors.py +2 -2
- gams/control/__init__.py +2 -2
- gams/control/database.py +2 -2
- gams/control/execution.py +2 -2
- gams/control/options.py +2 -2
- gams/control/workspace.py +2 -2
- gams/core/__init__.py +2 -2
- gams/core/cfg/__init__.py +2 -2
- gams/core/cfg/_cfgmcc.cp314-win_amd64.pyd +0 -0
- gams/core/dct/__init__.py +2 -2
- gams/core/dct/_dctmcc.cp314-win_amd64.pyd +0 -0
- gams/core/embedded/__init__.py +2 -2
- gams/core/embedded/gamsemb.py +2 -2
- gams/core/emp/__init__.py +2 -2
- gams/core/emp/emplexer.py +2 -2
- gams/core/emp/empyacc.py +2 -2
- gams/core/gdx/__init__.py +2 -2
- gams/core/gdx/_gdxcc.cp314-win_amd64.pyd +0 -0
- gams/core/gev/__init__.py +2 -2
- gams/core/gev/_gevmcc.cp314-win_amd64.pyd +0 -0
- gams/core/gmd/__init__.py +2 -2
- gams/core/gmd/_gmdcc.cp314-win_amd64.pyd +0 -0
- gams/core/gmo/__init__.py +2 -2
- gams/core/gmo/_gmomcc.cp314-win_amd64.pyd +0 -0
- gams/core/idx/__init__.py +2 -2
- gams/core/idx/_idxcc.cp314-win_amd64.pyd +0 -0
- gams/core/numpy/__init__.py +2 -2
- gams/core/numpy/_gams2numpy.cp314-win_amd64.pyd +0 -0
- gams/core/numpy/gams2numpy.py +2 -2
- gams/core/opt/__init__.py +2 -2
- gams/core/opt/_optcc.cp314-win_amd64.pyd +0 -0
- gams/engine/__init__.py +193 -16
- gams/engine/api/__init__.py +13 -3
- gams/engine/api/auth_api.py +7545 -3618
- gams/engine/api/cleanup_api.py +712 -320
- gams/engine/api/default_api.py +838 -369
- gams/engine/api/hypercube_api.py +2576 -1198
- gams/engine/api/jobs_api.py +5170 -2458
- gams/engine/api/licenses_api.py +2170 -1014
- gams/engine/api/namespaces_api.py +7663 -3557
- gams/engine/api/usage_api.py +5575 -1867
- gams/engine/api/users_api.py +5880 -2382
- gams/engine/api_client.py +579 -641
- gams/engine/api_response.py +21 -0
- gams/engine/configuration.py +233 -102
- gams/engine/exceptions.py +86 -29
- gams/engine/models/__init__.py +83 -68
- 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 +141 -229
- gams/magic/__init__.py +2 -2
- gams/magic/gams_magic.py +2 -2
- gams/magic/interactive.py +2 -2
- gams/tools/__init__.py +2 -2
- gams/tools/errors.py +2 -2
- gams/tools/toolcollection/__init__.py +2 -2
- gams/tools/toolcollection/alg/__init__.py +2 -2
- gams/tools/toolcollection/alg/rank.py +2 -2
- gams/tools/toolcollection/data/__init__.py +2 -2
- gams/tools/toolcollection/data/csvread.py +2 -2
- gams/tools/toolcollection/data/exceldump.py +2 -2
- gams/tools/toolcollection/data/sqlitewrite.py +2 -2
- gams/tools/toolcollection/gdxservice/__init__.py +2 -2
- gams/tools/toolcollection/gdxservice/gdxencoding.py +2 -2
- gams/tools/toolcollection/gdxservice/gdxrename.py +2 -2
- gams/tools/toolcollection/linalg/__init__.py +2 -2
- gams/tools/toolcollection/linalg/cholesky.py +2 -2
- gams/tools/toolcollection/linalg/eigenvalue.py +2 -2
- gams/tools/toolcollection/linalg/eigenvector.py +2 -2
- gams/tools/toolcollection/linalg/invert.py +2 -2
- gams/tools/toolcollection/linalg/ols.py +2 -2
- gams/tools/toolcollection/tooltemplate.py +2 -2
- gams/tools/toolcollection/win32/__init__.py +2 -2
- gams/tools/toolcollection/win32/excelmerge.py +2 -2
- gams/tools/toolcollection/win32/exceltalk.py +2 -2
- gams/tools/toolcollection/win32/msappavail.py +2 -2
- gams/tools/toolcollection/win32/shellexecute.py +2 -2
- gams/tools/tools.py +2 -2
- gams/transfer/__init__.py +2 -2
- gams/transfer/_abcs/__init__.py +2 -2
- gams/transfer/_abcs/container_abcs.py +2 -2
- gams/transfer/_internals/__init__.py +2 -2
- gams/transfer/_internals/algorithms.py +2 -2
- gams/transfer/_internals/casepreservingdict.py +2 -2
- gams/transfer/_internals/constants.py +2 -2
- gams/transfer/_internals/domainviolation.py +2 -2
- gams/transfer/_internals/specialvalues.py +2 -2
- gams/transfer/containers/__init__.py +2 -2
- gams/transfer/containers/_container.py +2 -2
- gams/transfer/containers/_io/__init__.py +2 -2
- gams/transfer/containers/_io/containers.py +2 -2
- gams/transfer/containers/_io/gdx.py +2 -2
- gams/transfer/containers/_io/gmd.py +2 -2
- gams/transfer/containers/_mixins/__init__.py +2 -2
- gams/transfer/containers/_mixins/ccc.py +2 -2
- gams/transfer/syms/__init__.py +2 -2
- gams/transfer/syms/_methods/__init__.py +2 -2
- gams/transfer/syms/_methods/tables.py +2 -2
- gams/transfer/syms/_methods/toDict.py +2 -2
- gams/transfer/syms/_methods/toList.py +2 -2
- gams/transfer/syms/_methods/toValue.py +2 -2
- gams/transfer/syms/_mixins/__init__.py +2 -2
- gams/transfer/syms/_mixins/equals.py +2 -2
- gams/transfer/syms/_mixins/generateRecords.py +2 -2
- gams/transfer/syms/_mixins/pivot.py +2 -2
- gams/transfer/syms/_mixins/pve.py +2 -2
- gams/transfer/syms/_mixins/sa.py +2 -2
- gams/transfer/syms/_mixins/sapve.py +2 -2
- gams/transfer/syms/_mixins/saua.py +2 -2
- gams/transfer/syms/_mixins/sauapve.py +2 -2
- gams/transfer/syms/_mixins/spve.py +2 -2
- gams/transfer/syms/_mixins/ve.py +2 -2
- gams/transfer/syms/container_syms/__init__.py +2 -2
- gams/transfer/syms/container_syms/_alias.py +2 -2
- gams/transfer/syms/container_syms/_equation.py +2 -2
- gams/transfer/syms/container_syms/_parameter.py +2 -2
- gams/transfer/syms/container_syms/_set.py +2 -2
- gams/transfer/syms/container_syms/_universe_alias.py +2 -2
- gams/transfer/syms/container_syms/_variable.py +2 -2
- {gamsapi-52.2.0.dist-info → gamsapi-52.4.0.dist-info}/METADATA +12 -10
- gamsapi-52.4.0.dist-info/RECORD +257 -0
- {gamsapi-52.2.0.dist-info → gamsapi-52.4.0.dist-info}/licenses/LICENSE +2 -2
- gams/engine/apis/__init__.py +0 -25
- gams/engine/model/__init__.py +0 -5
- gams/engine/model/bad_input.py +0 -259
- gams/engine/model/cleanable_job_result.py +0 -285
- gams/engine/model/cleanable_job_result_page.py +0 -277
- gams/engine/model/engine_license.py +0 -263
- gams/engine/model/files_not_found.py +0 -267
- gams/engine/model/forwarded_token_response.py +0 -275
- gams/engine/model/generic_key_value_pair.py +0 -259
- gams/engine/model/hypercube.py +0 -331
- gams/engine/model/hypercube_page.py +0 -273
- gams/engine/model/hypercube_summary.py +0 -263
- gams/engine/model/hypercube_token.py +0 -265
- gams/engine/model/identity_provider.py +0 -287
- gams/engine/model/identity_provider_ldap.py +0 -303
- gams/engine/model/identity_provider_oauth2.py +0 -309
- gams/engine/model/identity_provider_oauth2_scope.py +0 -259
- gams/engine/model/identity_provider_oauth2_with_secret.py +0 -321
- gams/engine/model/identity_provider_oidc.py +0 -299
- gams/engine/model/identity_provider_oidc_with_secret.py +0 -319
- gams/engine/model/inex.py +0 -259
- gams/engine/model/invitation.py +0 -309
- gams/engine/model/invitation_quota.py +0 -263
- gams/engine/model/invitation_token.py +0 -255
- gams/engine/model/job.py +0 -337
- gams/engine/model/job_no_text_entry.py +0 -313
- gams/engine/model/job_no_text_entry_page.py +0 -273
- gams/engine/model/license.py +0 -263
- gams/engine/model/log_piece.py +0 -263
- gams/engine/model/message.py +0 -255
- gams/engine/model/message_and_token.py +0 -269
- gams/engine/model/model_auth_token.py +0 -255
- gams/engine/model/model_configuration.py +0 -268
- gams/engine/model/model_hypercube_job.py +0 -273
- gams/engine/model/model_hypercube_usage.py +0 -303
- gams/engine/model/model_instance_info.py +0 -285
- gams/engine/model/model_instance_info_full.py +0 -289
- gams/engine/model/model_job_labels.py +0 -295
- gams/engine/model/model_job_usage.py +0 -299
- gams/engine/model/model_usage.py +0 -267
- gams/engine/model/model_userinstance_info.py +0 -273
- gams/engine/model/model_version.py +0 -263
- gams/engine/model/models.py +0 -297
- gams/engine/model/namespace.py +0 -269
- gams/engine/model/namespace_quota.py +0 -263
- gams/engine/model/namespace_with_permission.py +0 -263
- gams/engine/model/not_found.py +0 -263
- gams/engine/model/perm_and_username.py +0 -259
- gams/engine/model/quota.py +0 -275
- gams/engine/model/quota_exceeded.py +0 -265
- gams/engine/model/result_user.py +0 -263
- gams/engine/model/status_code_meaning.py +0 -259
- gams/engine/model/stream_entry.py +0 -259
- gams/engine/model/system_wide_license.py +0 -255
- gams/engine/model/text_entries.py +0 -255
- gams/engine/model/text_entry.py +0 -263
- gams/engine/model/time_span.py +0 -259
- gams/engine/model/token_forward_error.py +0 -255
- gams/engine/model/user.py +0 -283
- gams/engine/model/user_group_member.py +0 -269
- gams/engine/model/user_groups.py +0 -279
- gams/engine/model/webhook.py +0 -292
- gams/engine/model_utils.py +0 -2037
- gamsapi-52.2.0.dist-info/RECORD +0 -248
- {gamsapi-52.2.0.dist-info → gamsapi-52.4.0.dist-info}/WHEEL +0 -0
- {gamsapi-52.2.0.dist-info → gamsapi-52.4.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
GAMS Engine
|
|
5
|
+
|
|
6
|
+
With GAMS Engine you can register and solve GAMS models. It has a namespace management system, so you can restrict your users to certain models.
|
|
7
|
+
|
|
8
|
+
The version of the OpenAPI document: latest
|
|
9
|
+
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
|
10
|
+
|
|
11
|
+
Do not edit the class manually.
|
|
12
|
+
""" # noqa: E501
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
import pprint
|
|
17
|
+
import re # noqa: F401
|
|
18
|
+
import json
|
|
19
|
+
|
|
20
|
+
from pydantic import BaseModel, ConfigDict, StrictStr, field_validator
|
|
21
|
+
from typing import Any, ClassVar, Dict, List, Optional
|
|
22
|
+
from typing import Optional, Set
|
|
23
|
+
from typing_extensions import Self
|
|
24
|
+
|
|
25
|
+
class WebhookParameterizedEvent(BaseModel):
|
|
26
|
+
"""
|
|
27
|
+
WebhookParameterizedEvent
|
|
28
|
+
""" # noqa: E501
|
|
29
|
+
event: Optional[StrictStr] = None
|
|
30
|
+
parameters: Optional[List[StrictStr]] = None
|
|
31
|
+
__properties: ClassVar[List[str]] = ["event", "parameters"]
|
|
32
|
+
|
|
33
|
+
@field_validator('event')
|
|
34
|
+
def event_validate_enum(cls, value):
|
|
35
|
+
"""Validates the enum"""
|
|
36
|
+
if value is None:
|
|
37
|
+
return value
|
|
38
|
+
|
|
39
|
+
if value not in set(['ALL', 'JOB_FINISHED', 'HC_JOB_FINISHED', 'JOB_OUT_OF_RESOURCES', 'HC_JOB_OUT_OF_RESOURCES', 'VOLUME_QUOTA_THRESHOLD', 'JOB_DURATION_THRESHOLD', 'HC_JOB_DURATION_THRESHOLD', 'INVALIDATE_CACHE']):
|
|
40
|
+
raise ValueError("must be one of enum values ('ALL', 'JOB_FINISHED', 'HC_JOB_FINISHED', 'JOB_OUT_OF_RESOURCES', 'HC_JOB_OUT_OF_RESOURCES', 'VOLUME_QUOTA_THRESHOLD', 'JOB_DURATION_THRESHOLD', 'HC_JOB_DURATION_THRESHOLD', 'INVALIDATE_CACHE')")
|
|
41
|
+
return value
|
|
42
|
+
|
|
43
|
+
model_config = ConfigDict(
|
|
44
|
+
populate_by_name=True,
|
|
45
|
+
validate_assignment=True,
|
|
46
|
+
protected_namespaces=(),
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def to_str(self) -> str:
|
|
51
|
+
"""Returns the string representation of the model using alias"""
|
|
52
|
+
return pprint.pformat(self.model_dump(by_alias=True))
|
|
53
|
+
|
|
54
|
+
def to_json(self) -> str:
|
|
55
|
+
"""Returns the JSON representation of the model using alias"""
|
|
56
|
+
# TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead
|
|
57
|
+
return json.dumps(self.to_dict())
|
|
58
|
+
|
|
59
|
+
@classmethod
|
|
60
|
+
def from_json(cls, json_str: str) -> Optional[Self]:
|
|
61
|
+
"""Create an instance of WebhookParameterizedEvent from a JSON string"""
|
|
62
|
+
return cls.from_dict(json.loads(json_str))
|
|
63
|
+
|
|
64
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
65
|
+
"""Return the dictionary representation of the model using alias.
|
|
66
|
+
|
|
67
|
+
This has the following differences from calling pydantic's
|
|
68
|
+
`self.model_dump(by_alias=True)`:
|
|
69
|
+
|
|
70
|
+
* `None` is only added to the output dict for nullable fields that
|
|
71
|
+
were set at model initialization. Other fields with value `None`
|
|
72
|
+
are ignored.
|
|
73
|
+
"""
|
|
74
|
+
excluded_fields: Set[str] = set([
|
|
75
|
+
])
|
|
76
|
+
|
|
77
|
+
_dict = self.model_dump(
|
|
78
|
+
by_alias=True,
|
|
79
|
+
exclude=excluded_fields,
|
|
80
|
+
exclude_none=True,
|
|
81
|
+
)
|
|
82
|
+
return _dict
|
|
83
|
+
|
|
84
|
+
@classmethod
|
|
85
|
+
def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
|
|
86
|
+
"""Create an instance of WebhookParameterizedEvent from a dict"""
|
|
87
|
+
if obj is None:
|
|
88
|
+
return None
|
|
89
|
+
|
|
90
|
+
if not isinstance(obj, dict):
|
|
91
|
+
return cls.model_validate(obj)
|
|
92
|
+
|
|
93
|
+
_obj = cls.model_validate({
|
|
94
|
+
"event": obj.get("event"),
|
|
95
|
+
"parameters": obj.get("parameters")
|
|
96
|
+
})
|
|
97
|
+
return _obj
|
|
98
|
+
|
|
99
|
+
|
gams/engine/py.typed
ADDED
|
File without changes
|
gams/engine/rest.py
CHANGED
|
@@ -1,54 +1,68 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
|
|
1
3
|
"""
|
|
2
4
|
GAMS Engine
|
|
3
5
|
|
|
4
|
-
With GAMS Engine you can register and solve GAMS models. It has a namespace management system, so you can restrict your users to certain models.
|
|
6
|
+
With GAMS Engine you can register and solve GAMS models. It has a namespace management system, so you can restrict your users to certain models.
|
|
5
7
|
|
|
6
8
|
The version of the OpenAPI document: latest
|
|
7
|
-
Generated by
|
|
8
|
-
|
|
9
|
+
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
|
10
|
+
|
|
11
|
+
Do not edit the class manually.
|
|
12
|
+
""" # noqa: E501
|
|
9
13
|
|
|
10
14
|
|
|
11
15
|
import io
|
|
12
16
|
import json
|
|
13
|
-
import logging
|
|
14
17
|
import re
|
|
15
18
|
import ssl
|
|
16
|
-
|
|
17
|
-
from urllib.parse import urlparse
|
|
18
|
-
from urllib.request import proxy_bypass_environment
|
|
19
|
+
|
|
19
20
|
import urllib3
|
|
20
|
-
import ipaddress
|
|
21
21
|
|
|
22
|
-
from gams.engine.exceptions import ApiException,
|
|
22
|
+
from gams.engine.exceptions import ApiException, ApiValueError
|
|
23
23
|
|
|
24
|
+
SUPPORTED_SOCKS_PROXIES = {"socks5", "socks5h", "socks4", "socks4a"}
|
|
25
|
+
RESTResponseType = urllib3.HTTPResponse
|
|
24
26
|
|
|
25
|
-
|
|
27
|
+
|
|
28
|
+
def is_socks_proxy_url(url):
|
|
29
|
+
if url is None:
|
|
30
|
+
return False
|
|
31
|
+
split_section = url.split("://")
|
|
32
|
+
if len(split_section) < 2:
|
|
33
|
+
return False
|
|
34
|
+
else:
|
|
35
|
+
return split_section[0].lower() in SUPPORTED_SOCKS_PROXIES
|
|
26
36
|
|
|
27
37
|
|
|
28
38
|
class RESTResponse(io.IOBase):
|
|
29
39
|
|
|
30
|
-
def __init__(self, resp):
|
|
31
|
-
self.
|
|
40
|
+
def __init__(self, resp) -> None:
|
|
41
|
+
self.response = resp
|
|
32
42
|
self.status = resp.status
|
|
33
43
|
self.reason = resp.reason
|
|
34
|
-
self.data =
|
|
44
|
+
self.data = None
|
|
45
|
+
|
|
46
|
+
def read(self):
|
|
47
|
+
if self.data is None:
|
|
48
|
+
self.data = self.response.data
|
|
49
|
+
return self.data
|
|
35
50
|
|
|
36
51
|
def getheaders(self):
|
|
37
52
|
"""Returns a dictionary of the response headers."""
|
|
38
|
-
return self.
|
|
53
|
+
return self.response.headers
|
|
39
54
|
|
|
40
55
|
def getheader(self, name, default=None):
|
|
41
56
|
"""Returns a given response header."""
|
|
42
|
-
return self.
|
|
57
|
+
return self.response.headers.get(name, default)
|
|
43
58
|
|
|
44
59
|
|
|
45
|
-
class RESTClientObject
|
|
60
|
+
class RESTClientObject:
|
|
46
61
|
|
|
47
|
-
def __init__(self, configuration
|
|
62
|
+
def __init__(self, configuration) -> None:
|
|
48
63
|
# urllib3.PoolManager will pass all kw parameters to connectionpool
|
|
49
64
|
# https://github.com/shazow/urllib3/blob/f9409436f83aeb79fbaf090181cd81b784f1b8ce/urllib3/poolmanager.py#L75 # noqa: E501
|
|
50
65
|
# https://github.com/shazow/urllib3/blob/f9409436f83aeb79fbaf090181cd81b784f1b8ce/urllib3/connectionpool.py#L680 # noqa: E501
|
|
51
|
-
# maxsize is the number of requests to host that are allowed in parallel # noqa: E501
|
|
52
66
|
# Custom SSL certificates and client certificates: http://urllib3.readthedocs.io/en/latest/advanced-usage.html # noqa: E501
|
|
53
67
|
|
|
54
68
|
# cert_reqs
|
|
@@ -57,70 +71,80 @@ class RESTClientObject(object):
|
|
|
57
71
|
else:
|
|
58
72
|
cert_reqs = ssl.CERT_NONE
|
|
59
73
|
|
|
60
|
-
|
|
74
|
+
pool_args = {
|
|
75
|
+
"cert_reqs": cert_reqs,
|
|
76
|
+
"ca_certs": configuration.ssl_ca_cert,
|
|
77
|
+
"cert_file": configuration.cert_file,
|
|
78
|
+
"key_file": configuration.key_file,
|
|
79
|
+
"ca_cert_data": configuration.ca_cert_data,
|
|
80
|
+
}
|
|
61
81
|
if configuration.assert_hostname is not None:
|
|
62
|
-
|
|
82
|
+
pool_args['assert_hostname'] = (
|
|
83
|
+
configuration.assert_hostname
|
|
84
|
+
)
|
|
63
85
|
|
|
64
86
|
if configuration.retries is not None:
|
|
65
|
-
|
|
87
|
+
pool_args['retries'] = configuration.retries
|
|
88
|
+
|
|
89
|
+
if configuration.tls_server_name:
|
|
90
|
+
pool_args['server_hostname'] = configuration.tls_server_name
|
|
91
|
+
|
|
66
92
|
|
|
67
93
|
if configuration.socket_options is not None:
|
|
68
|
-
|
|
94
|
+
pool_args['socket_options'] = configuration.socket_options
|
|
69
95
|
|
|
70
|
-
if
|
|
71
|
-
|
|
72
|
-
maxsize = configuration.connection_pool_maxsize
|
|
73
|
-
else:
|
|
74
|
-
maxsize = 4
|
|
96
|
+
if configuration.connection_pool_maxsize is not None:
|
|
97
|
+
pool_args['maxsize'] = configuration.connection_pool_maxsize
|
|
75
98
|
|
|
76
99
|
# https pool manager
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
100
|
+
self.pool_manager: urllib3.PoolManager
|
|
101
|
+
|
|
102
|
+
if configuration.proxy:
|
|
103
|
+
if is_socks_proxy_url(configuration.proxy):
|
|
104
|
+
from urllib3.contrib.socks import SOCKSProxyManager
|
|
105
|
+
pool_args["proxy_url"] = configuration.proxy
|
|
106
|
+
pool_args["headers"] = configuration.proxy_headers
|
|
107
|
+
self.pool_manager = SOCKSProxyManager(**pool_args)
|
|
108
|
+
else:
|
|
109
|
+
pool_args["proxy_url"] = configuration.proxy
|
|
110
|
+
pool_args["proxy_headers"] = configuration.proxy_headers
|
|
111
|
+
self.pool_manager = urllib3.ProxyManager(**pool_args)
|
|
89
112
|
else:
|
|
90
|
-
self.pool_manager = urllib3.PoolManager(
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
body=None, post_params=None, _preload_content=True,
|
|
102
|
-
_request_timeout=None):
|
|
113
|
+
self.pool_manager = urllib3.PoolManager(**pool_args)
|
|
114
|
+
|
|
115
|
+
def request(
|
|
116
|
+
self,
|
|
117
|
+
method,
|
|
118
|
+
url,
|
|
119
|
+
headers=None,
|
|
120
|
+
body=None,
|
|
121
|
+
post_params=None,
|
|
122
|
+
_request_timeout=None
|
|
123
|
+
):
|
|
103
124
|
"""Perform requests.
|
|
104
125
|
|
|
105
126
|
:param method: http request method
|
|
106
127
|
:param url: http request url
|
|
107
|
-
:param query_params: query parameters in the url
|
|
108
128
|
:param headers: http request headers
|
|
109
129
|
:param body: request json body, for `application/json`
|
|
110
130
|
:param post_params: request post parameters,
|
|
111
131
|
`application/x-www-form-urlencoded`
|
|
112
132
|
and `multipart/form-data`
|
|
113
|
-
:param _preload_content: if False, the urllib3.HTTPResponse object will
|
|
114
|
-
be returned without reading/decoding response
|
|
115
|
-
data. Default is True.
|
|
116
133
|
:param _request_timeout: timeout setting for this request. If one
|
|
117
134
|
number provided, it will be total request
|
|
118
135
|
timeout. It can also be a pair (tuple) of
|
|
119
136
|
(connection, read) timeouts.
|
|
120
137
|
"""
|
|
121
138
|
method = method.upper()
|
|
122
|
-
assert method in [
|
|
123
|
-
|
|
139
|
+
assert method in [
|
|
140
|
+
'GET',
|
|
141
|
+
'HEAD',
|
|
142
|
+
'DELETE',
|
|
143
|
+
'POST',
|
|
144
|
+
'PUT',
|
|
145
|
+
'PATCH',
|
|
146
|
+
'OPTIONS'
|
|
147
|
+
]
|
|
124
148
|
|
|
125
149
|
if post_params and body:
|
|
126
150
|
raise ApiValueError(
|
|
@@ -132,60 +156,83 @@ class RESTClientObject(object):
|
|
|
132
156
|
|
|
133
157
|
timeout = None
|
|
134
158
|
if _request_timeout:
|
|
135
|
-
if isinstance(_request_timeout, (int, float)):
|
|
159
|
+
if isinstance(_request_timeout, (int, float)):
|
|
136
160
|
timeout = urllib3.Timeout(total=_request_timeout)
|
|
137
|
-
elif (
|
|
138
|
-
|
|
161
|
+
elif (
|
|
162
|
+
isinstance(_request_timeout, tuple)
|
|
163
|
+
and len(_request_timeout) == 2
|
|
164
|
+
):
|
|
139
165
|
timeout = urllib3.Timeout(
|
|
140
|
-
connect=_request_timeout[0],
|
|
166
|
+
connect=_request_timeout[0],
|
|
167
|
+
read=_request_timeout[1]
|
|
168
|
+
)
|
|
141
169
|
|
|
142
170
|
try:
|
|
143
171
|
# For `POST`, `PUT`, `PATCH`, `OPTIONS`, `DELETE`
|
|
144
172
|
if method in ['POST', 'PUT', 'PATCH', 'OPTIONS']:
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
if
|
|
149
|
-
|
|
150
|
-
|
|
173
|
+
|
|
174
|
+
# no content type provided or payload is json
|
|
175
|
+
content_type = headers.get('Content-Type')
|
|
176
|
+
if (
|
|
177
|
+
not content_type
|
|
178
|
+
or re.search('json', content_type, re.IGNORECASE)
|
|
179
|
+
):
|
|
151
180
|
request_body = None
|
|
152
181
|
if body is not None:
|
|
153
182
|
request_body = json.dumps(body)
|
|
154
183
|
r = self.pool_manager.request(
|
|
155
|
-
method,
|
|
184
|
+
method,
|
|
185
|
+
url,
|
|
156
186
|
body=request_body,
|
|
157
|
-
preload_content=_preload_content,
|
|
158
187
|
timeout=timeout,
|
|
159
|
-
headers=headers
|
|
160
|
-
|
|
188
|
+
headers=headers,
|
|
189
|
+
preload_content=False
|
|
190
|
+
)
|
|
191
|
+
elif content_type == 'application/x-www-form-urlencoded':
|
|
161
192
|
r = self.pool_manager.request(
|
|
162
|
-
method,
|
|
193
|
+
method,
|
|
194
|
+
url,
|
|
163
195
|
fields=post_params,
|
|
164
196
|
encode_multipart=False,
|
|
165
|
-
preload_content=_preload_content,
|
|
166
197
|
timeout=timeout,
|
|
167
|
-
headers=headers
|
|
168
|
-
|
|
198
|
+
headers=headers,
|
|
199
|
+
preload_content=False
|
|
200
|
+
)
|
|
201
|
+
elif content_type == 'multipart/form-data':
|
|
169
202
|
# must del headers['Content-Type'], or the correct
|
|
170
203
|
# Content-Type which generated by urllib3 will be
|
|
171
204
|
# overwritten.
|
|
172
205
|
del headers['Content-Type']
|
|
206
|
+
# Ensures that dict objects are serialized
|
|
207
|
+
post_params = [(a, json.dumps(b)) if isinstance(b, dict) else (a,b) for a, b in post_params]
|
|
173
208
|
r = self.pool_manager.request(
|
|
174
|
-
method,
|
|
209
|
+
method,
|
|
210
|
+
url,
|
|
175
211
|
fields=post_params,
|
|
176
212
|
encode_multipart=True,
|
|
177
|
-
preload_content=_preload_content,
|
|
178
213
|
timeout=timeout,
|
|
179
|
-
headers=headers
|
|
214
|
+
headers=headers,
|
|
215
|
+
preload_content=False
|
|
216
|
+
)
|
|
180
217
|
# Pass a `string` parameter directly in the body to support
|
|
181
|
-
# other content types than
|
|
182
|
-
# provided in serialized form
|
|
218
|
+
# other content types than JSON when `body` argument is
|
|
219
|
+
# provided in serialized form.
|
|
183
220
|
elif isinstance(body, str) or isinstance(body, bytes):
|
|
184
|
-
request_body = body
|
|
185
221
|
r = self.pool_manager.request(
|
|
186
|
-
method,
|
|
222
|
+
method,
|
|
223
|
+
url,
|
|
224
|
+
body=body,
|
|
225
|
+
timeout=timeout,
|
|
226
|
+
headers=headers,
|
|
227
|
+
preload_content=False
|
|
228
|
+
)
|
|
229
|
+
elif headers['Content-Type'].startswith('text/') and isinstance(body, bool):
|
|
230
|
+
request_body = "true" if body else "false"
|
|
231
|
+
r = self.pool_manager.request(
|
|
232
|
+
method,
|
|
233
|
+
url,
|
|
187
234
|
body=request_body,
|
|
188
|
-
preload_content=
|
|
235
|
+
preload_content=False,
|
|
189
236
|
timeout=timeout,
|
|
190
237
|
headers=headers)
|
|
191
238
|
else:
|
|
@@ -196,151 +243,16 @@ class RESTClientObject(object):
|
|
|
196
243
|
raise ApiException(status=0, reason=msg)
|
|
197
244
|
# For `GET`, `HEAD`
|
|
198
245
|
else:
|
|
199
|
-
r = self.pool_manager.request(
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
246
|
+
r = self.pool_manager.request(
|
|
247
|
+
method,
|
|
248
|
+
url,
|
|
249
|
+
fields={},
|
|
250
|
+
timeout=timeout,
|
|
251
|
+
headers=headers,
|
|
252
|
+
preload_content=False
|
|
253
|
+
)
|
|
204
254
|
except urllib3.exceptions.SSLError as e:
|
|
205
|
-
msg = "
|
|
255
|
+
msg = "\n".join([type(e).__name__, str(e)])
|
|
206
256
|
raise ApiException(status=0, reason=msg)
|
|
207
257
|
|
|
208
|
-
|
|
209
|
-
r = RESTResponse(r)
|
|
210
|
-
|
|
211
|
-
# log response body
|
|
212
|
-
logger.debug("response body: %s", r.data)
|
|
213
|
-
|
|
214
|
-
if not 200 <= r.status <= 299:
|
|
215
|
-
if r.status == 401:
|
|
216
|
-
raise UnauthorizedException(http_resp=r)
|
|
217
|
-
|
|
218
|
-
if r.status == 403:
|
|
219
|
-
raise ForbiddenException(http_resp=r)
|
|
220
|
-
|
|
221
|
-
if r.status == 404:
|
|
222
|
-
raise NotFoundException(http_resp=r)
|
|
223
|
-
|
|
224
|
-
if 500 <= r.status <= 599:
|
|
225
|
-
raise ServiceException(http_resp=r)
|
|
226
|
-
|
|
227
|
-
raise ApiException(http_resp=r)
|
|
228
|
-
|
|
229
|
-
return r
|
|
230
|
-
|
|
231
|
-
def GET(self, url, headers=None, query_params=None, _preload_content=True,
|
|
232
|
-
_request_timeout=None):
|
|
233
|
-
return self.request("GET", url,
|
|
234
|
-
headers=headers,
|
|
235
|
-
_preload_content=_preload_content,
|
|
236
|
-
_request_timeout=_request_timeout,
|
|
237
|
-
query_params=query_params)
|
|
238
|
-
|
|
239
|
-
def HEAD(self, url, headers=None, query_params=None, _preload_content=True,
|
|
240
|
-
_request_timeout=None):
|
|
241
|
-
return self.request("HEAD", url,
|
|
242
|
-
headers=headers,
|
|
243
|
-
_preload_content=_preload_content,
|
|
244
|
-
_request_timeout=_request_timeout,
|
|
245
|
-
query_params=query_params)
|
|
246
|
-
|
|
247
|
-
def OPTIONS(self, url, headers=None, query_params=None, post_params=None,
|
|
248
|
-
body=None, _preload_content=True, _request_timeout=None):
|
|
249
|
-
return self.request("OPTIONS", url,
|
|
250
|
-
headers=headers,
|
|
251
|
-
query_params=query_params,
|
|
252
|
-
post_params=post_params,
|
|
253
|
-
_preload_content=_preload_content,
|
|
254
|
-
_request_timeout=_request_timeout,
|
|
255
|
-
body=body)
|
|
256
|
-
|
|
257
|
-
def DELETE(self, url, headers=None, query_params=None, body=None,
|
|
258
|
-
_preload_content=True, _request_timeout=None):
|
|
259
|
-
return self.request("DELETE", url,
|
|
260
|
-
headers=headers,
|
|
261
|
-
query_params=query_params,
|
|
262
|
-
_preload_content=_preload_content,
|
|
263
|
-
_request_timeout=_request_timeout,
|
|
264
|
-
body=body)
|
|
265
|
-
|
|
266
|
-
def POST(self, url, headers=None, query_params=None, post_params=None,
|
|
267
|
-
body=None, _preload_content=True, _request_timeout=None):
|
|
268
|
-
return self.request("POST", url,
|
|
269
|
-
headers=headers,
|
|
270
|
-
query_params=query_params,
|
|
271
|
-
post_params=post_params,
|
|
272
|
-
_preload_content=_preload_content,
|
|
273
|
-
_request_timeout=_request_timeout,
|
|
274
|
-
body=body)
|
|
275
|
-
|
|
276
|
-
def PUT(self, url, headers=None, query_params=None, post_params=None,
|
|
277
|
-
body=None, _preload_content=True, _request_timeout=None):
|
|
278
|
-
return self.request("PUT", url,
|
|
279
|
-
headers=headers,
|
|
280
|
-
query_params=query_params,
|
|
281
|
-
post_params=post_params,
|
|
282
|
-
_preload_content=_preload_content,
|
|
283
|
-
_request_timeout=_request_timeout,
|
|
284
|
-
body=body)
|
|
285
|
-
|
|
286
|
-
def PATCH(self, url, headers=None, query_params=None, post_params=None,
|
|
287
|
-
body=None, _preload_content=True, _request_timeout=None):
|
|
288
|
-
return self.request("PATCH", url,
|
|
289
|
-
headers=headers,
|
|
290
|
-
query_params=query_params,
|
|
291
|
-
post_params=post_params,
|
|
292
|
-
_preload_content=_preload_content,
|
|
293
|
-
_request_timeout=_request_timeout,
|
|
294
|
-
body=body)
|
|
295
|
-
|
|
296
|
-
# end of class RESTClientObject
|
|
297
|
-
def is_ipv4(target):
|
|
298
|
-
""" Test if IPv4 address or not
|
|
299
|
-
"""
|
|
300
|
-
try:
|
|
301
|
-
chk = ipaddress.IPv4Address(target)
|
|
302
|
-
return True
|
|
303
|
-
except ipaddress.AddressValueError:
|
|
304
|
-
return False
|
|
305
|
-
|
|
306
|
-
def in_ipv4net(target, net):
|
|
307
|
-
""" Test if target belongs to given IPv4 network
|
|
308
|
-
"""
|
|
309
|
-
try:
|
|
310
|
-
nw = ipaddress.IPv4Network(net)
|
|
311
|
-
ip = ipaddress.IPv4Address(target)
|
|
312
|
-
if ip in nw:
|
|
313
|
-
return True
|
|
314
|
-
return False
|
|
315
|
-
except ipaddress.AddressValueError:
|
|
316
|
-
return False
|
|
317
|
-
except ipaddress.NetmaskValueError:
|
|
318
|
-
return False
|
|
319
|
-
|
|
320
|
-
def should_bypass_proxies(url, no_proxy=None):
|
|
321
|
-
""" Yet another requests.should_bypass_proxies
|
|
322
|
-
Test if proxies should not be used for a particular url.
|
|
323
|
-
"""
|
|
324
|
-
|
|
325
|
-
parsed = urlparse(url)
|
|
326
|
-
|
|
327
|
-
# special cases
|
|
328
|
-
if parsed.hostname in [None, '']:
|
|
329
|
-
return True
|
|
330
|
-
|
|
331
|
-
# special cases
|
|
332
|
-
if no_proxy in [None , '']:
|
|
333
|
-
return False
|
|
334
|
-
if no_proxy == '*':
|
|
335
|
-
return True
|
|
336
|
-
|
|
337
|
-
no_proxy = no_proxy.lower().replace(' ','');
|
|
338
|
-
entries = (
|
|
339
|
-
host for host in no_proxy.split(',') if host
|
|
340
|
-
)
|
|
341
|
-
|
|
342
|
-
if is_ipv4(parsed.hostname):
|
|
343
|
-
for item in entries:
|
|
344
|
-
if in_ipv4net(parsed.hostname, item):
|
|
345
|
-
return True
|
|
346
|
-
return proxy_bypass_environment(parsed.hostname, {'no': no_proxy} )
|
|
258
|
+
return RESTResponse(r)
|
gams/magic/__init__.py
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#
|
|
2
2
|
# GAMS - General Algebraic Modeling System Python API
|
|
3
3
|
#
|
|
4
|
-
# Copyright (c) 2017-
|
|
5
|
-
# Copyright (c) 2017-
|
|
4
|
+
# Copyright (c) 2017-2026 GAMS Development Corp. <support@gams.com>
|
|
5
|
+
# Copyright (c) 2017-2026 GAMS Software GmbH <support@gams.com>
|
|
6
6
|
#
|
|
7
7
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
8
|
# of this software and associated documentation files (the "Software"), to deal
|
gams/magic/gams_magic.py
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#
|
|
2
2
|
# GAMS - General Algebraic Modeling System Python API
|
|
3
3
|
#
|
|
4
|
-
# Copyright (c) 2017-
|
|
5
|
-
# Copyright (c) 2017-
|
|
4
|
+
# Copyright (c) 2017-2026 GAMS Development Corp. <support@gams.com>
|
|
5
|
+
# Copyright (c) 2017-2026 GAMS Software GmbH <support@gams.com>
|
|
6
6
|
#
|
|
7
7
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
8
|
# of this software and associated documentation files (the "Software"), to deal
|
gams/magic/interactive.py
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#
|
|
2
2
|
# GAMS - General Algebraic Modeling System Python API
|
|
3
3
|
#
|
|
4
|
-
# Copyright (c) 2017-
|
|
5
|
-
# Copyright (c) 2017-
|
|
4
|
+
# Copyright (c) 2017-2026 GAMS Development Corp. <support@gams.com>
|
|
5
|
+
# Copyright (c) 2017-2026 GAMS Software GmbH <support@gams.com>
|
|
6
6
|
#
|
|
7
7
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
8
|
# of this software and associated documentation files (the "Software"), to deal
|
gams/tools/__init__.py
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#
|
|
2
2
|
# GAMS - General Algebraic Modeling System Python API
|
|
3
3
|
#
|
|
4
|
-
# Copyright (c) 2017-
|
|
5
|
-
# Copyright (c) 2017-
|
|
4
|
+
# Copyright (c) 2017-2026 GAMS Development Corp. <support@gams.com>
|
|
5
|
+
# Copyright (c) 2017-2026 GAMS Software GmbH <support@gams.com>
|
|
6
6
|
#
|
|
7
7
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
8
|
# of this software and associated documentation files (the "Software"), to deal
|
gams/tools/errors.py
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#
|
|
2
2
|
# GAMS - General Algebraic Modeling System Python API
|
|
3
3
|
#
|
|
4
|
-
# Copyright (c) 2017-
|
|
5
|
-
# Copyright (c) 2017-
|
|
4
|
+
# Copyright (c) 2017-2026 GAMS Development Corp. <support@gams.com>
|
|
5
|
+
# Copyright (c) 2017-2026 GAMS Software GmbH <support@gams.com>
|
|
6
6
|
#
|
|
7
7
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
8
|
# of this software and associated documentation files (the "Software"), to deal
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#
|
|
2
2
|
# GAMS - General Algebraic Modeling System Python API
|
|
3
3
|
#
|
|
4
|
-
# Copyright (c) 2017-
|
|
5
|
-
# Copyright (c) 2017-
|
|
4
|
+
# Copyright (c) 2017-2026 GAMS Development Corp. <support@gams.com>
|
|
5
|
+
# Copyright (c) 2017-2026 GAMS Software GmbH <support@gams.com>
|
|
6
6
|
#
|
|
7
7
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
8
|
# of this software and associated documentation files (the "Software"), to deal
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#
|
|
2
2
|
# GAMS - General Algebraic Modeling System Python API
|
|
3
3
|
#
|
|
4
|
-
# Copyright (c) 2017-
|
|
5
|
-
# Copyright (c) 2017-
|
|
4
|
+
# Copyright (c) 2017-2026 GAMS Development Corp. <support@gams.com>
|
|
5
|
+
# Copyright (c) 2017-2026 GAMS Software GmbH <support@gams.com>
|
|
6
6
|
#
|
|
7
7
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
8
|
# of this software and associated documentation files (the "Software"), to deal
|