mcsmapi 0.1.1__py3-none-any.whl → 0.1.3__py3-none-any.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.
@@ -0,0 +1,112 @@
1
+ from typing import List, Optional
2
+ from pydantic import BaseModel
3
+
4
+
5
+ class DockerConfig(BaseModel):
6
+ containerName: str = ""
7
+ image: str = "mcsm-ubuntu:22.04"
8
+ memory: int = 1024 # in MB
9
+ ports: List[str] = ["25565:25565/tcp"]
10
+ extraVolumes: List[str] = []
11
+ maxSpace: Optional[int] = None
12
+ network: Optional[str] = None
13
+ io: Optional[str] = None
14
+ networkMode: str = "bridge"
15
+ networkAliases: List[str] = []
16
+ cpusetCpus: str = ""
17
+ cpuUsage: int = 100
18
+ workingDir: str = ""
19
+ env: List[str] = []
20
+
21
+
22
+ class DockerImageItem(BaseModel):
23
+ Id: str = ""
24
+ ParentId: str = ""
25
+ RepoTags: List[str] = []
26
+ RepoDigests: List[str] = []
27
+ Created: int = 0
28
+ Size: int = 0
29
+ VirtualSize: int = 0
30
+ SharedSize: int = 0
31
+ Labels: dict[str, str] = {}
32
+ Containers: int = 0
33
+
34
+
35
+ class DockerContainerItemPort(BaseModel):
36
+ PrivatePort: int = 0
37
+ PublicPort: Optional[int] = None
38
+ Type: str = ""
39
+
40
+
41
+ class DockerContainerItemNetworkSettingsNetwork(BaseModel):
42
+ NetworkID: str = ""
43
+ EndpointID: str = ""
44
+ Gateway: str = ""
45
+ IPAddress: str = ""
46
+ IPPrefixLen: int = 0
47
+ IPv6Gateway: str = ""
48
+ GlobalIPv6Address: str = ""
49
+ GlobalIPv6PrefixLen: int = 0
50
+ MacAddress: str = ""
51
+
52
+
53
+ class DockerContainerItemNetworkSettings(BaseModel):
54
+ Networks: dict[str, DockerContainerItemNetworkSettingsNetwork] = {}
55
+
56
+
57
+ class DockerContainerItemMount(BaseModel):
58
+ Name: str = ""
59
+ Source: str = ""
60
+ Destination: str = ""
61
+ Driver: str = ""
62
+ Mode: str = ""
63
+ RW: bool = False
64
+ Propagation: str = ""
65
+
66
+
67
+ class DockerContainerItemHostConfig(BaseModel):
68
+ NetworkMode: str = ""
69
+
70
+
71
+ class DockerContainerItem(BaseModel):
72
+ Id: str = ""
73
+ Names: List[str] = []
74
+ Image: str = ""
75
+ ImageID: str = ""
76
+ Command: str = ""
77
+ Created: int = 0
78
+ State: str = ""
79
+ Status: str = ""
80
+ Ports: List[DockerContainerItemPort] = []
81
+ Labels: dict[str, str] = {}
82
+ SizeRw: int = 0
83
+ SizeRootFs: int = 0
84
+ HostConfig: DockerContainerItemHostConfig = DockerContainerItemHostConfig()
85
+ NetworkSettings: DockerContainerItemNetworkSettings = (
86
+ DockerContainerItemNetworkSettings()
87
+ )
88
+ Mounts: List[DockerContainerItemMount] = []
89
+
90
+
91
+ class DockerNetworkItemIPAMConfig(BaseModel):
92
+ Subnet: str = ""
93
+
94
+
95
+ class DockerNetworkItemIPAM(BaseModel):
96
+ Driver: str = ""
97
+ Config: List[DockerNetworkItemIPAMConfig] = []
98
+
99
+
100
+ class DockerNetworkItem(BaseModel):
101
+ Name: str = ""
102
+ Id: str = ""
103
+ Created: str = ""
104
+ Scope: str = ""
105
+ Driver: str = ""
106
+ EnableIPv6: bool = False
107
+ Internal: bool = False
108
+ Attachable: bool = False
109
+ Ingress: bool = False
110
+ IPAM: DockerNetworkItemIPAM = DockerNetworkItemIPAM()
111
+ Options: dict[str, str]
112
+ Containers: Optional[dict[str, dict]] = {}
@@ -0,0 +1,204 @@
1
+ from typing import List, Dict
2
+ from pydantic import BaseModel
3
+ from .image import DockerConfig
4
+
5
+
6
+ class TerminalOption(BaseModel):
7
+ haveColor: bool = False
8
+ pty: bool = True
9
+
10
+
11
+ class EventTask(BaseModel):
12
+ autoStart: bool = False
13
+ autoRestart: bool = True
14
+ ignore: bool = False
15
+
16
+
17
+ class PingConfig(BaseModel):
18
+ ip: str = ""
19
+ port: int = 25565
20
+ type: int = 1
21
+
22
+
23
+ class InstanceConfig(BaseModel):
24
+ nickname: str = "New Name"
25
+ startCommand: str = "cmd.exe"
26
+ stopCommand: str = "^C"
27
+ cwd: str = ""
28
+ ie: str = "gbk" # 输入编码
29
+ oe: str = "gbk" # 输出编码
30
+ createDatetime: int = 0
31
+ lastDatetime: int = 0
32
+ type: str = "universal"
33
+ tag: List[str] = []
34
+ endTime: int = 0
35
+ fileCode: str = "gbk"
36
+ processType: str = "docker"
37
+ updateCommand: str = "shutdown -s"
38
+ actionCommandList: List[str] = []
39
+ crlf: int = 2
40
+ docker: "DockerConfig" = DockerConfig()
41
+ enableRcon: bool = True
42
+ rconPassword: str = ""
43
+ rconPort: int = 2557
44
+ rconIp: str = ""
45
+ terminalOption: TerminalOption = TerminalOption()
46
+ eventTask: EventTask = EventTask()
47
+ pingConfig: PingConfig = PingConfig()
48
+
49
+
50
+ class ProcessInfo(BaseModel):
51
+ cpu: int = 0
52
+ memory: int = 0
53
+ ppid: int = 0
54
+ pid: int = 0
55
+ ctime: int = 0
56
+ elapsed: int = 0
57
+ timestamp: int = 0
58
+
59
+
60
+ class InstanceInfo(BaseModel):
61
+ currentPlayers: int = -1
62
+ fileLock: int = 0
63
+ maxPlayers: int = -1
64
+ openFrpStatus: bool = False
65
+ playersChart: List[Dict] = []
66
+ version: str = ""
67
+
68
+
69
+ class InstanceDetail(BaseModel):
70
+ config: InstanceConfig = InstanceConfig()
71
+ info: InstanceInfo = InstanceInfo()
72
+ daemonId: str = ""
73
+ instanceUuid: str = ""
74
+ processInfo: ProcessInfo = ProcessInfo()
75
+ space: int = 0
76
+ started: int = 0 # 启动次数
77
+ status: int = 0 # -1 = 忙碌, 0 = 停止, 1 = 停止中, 2 = 启动中, 3 = 运行中
78
+
79
+ def start(self) -> str | bool:
80
+ """
81
+ 启动该实例。
82
+
83
+ **返回:**
84
+ - str|bool: str|bool: 返回结果中的 "instanceUuid" 字段值,如果未找到该字段,则默认返回True。
85
+ """
86
+ from ..apis.instance import Instance
87
+
88
+ return Instance().start(self.daemonId, self.instanceUuid)
89
+
90
+ def stop(self) -> str | bool:
91
+ """
92
+ 停止该实例。
93
+
94
+ **返回:**
95
+ - str|bool: 返回结果中的 "instanceUuid" 字段值,如果未找到该字段,则默认返回True。
96
+ """
97
+ from ..apis.instance import Instance
98
+
99
+ return Instance().stop(self.daemonId, self.instanceUuid)
100
+
101
+ def restart(self) -> str | bool:
102
+ """
103
+ 重启该实例。
104
+
105
+ **返回:**
106
+ - str|bool: 返回结果中的 "instanceUuid" 字段值,如果未找到该字段,则默认返回True。
107
+ """
108
+ from ..apis.instance import Instance
109
+
110
+ return Instance().restart(self.daemonId, self.instanceUuid)
111
+
112
+ def kill(self) -> str | bool:
113
+ """
114
+ 强制关闭该实例。
115
+
116
+ **返回:**
117
+ - str|bool: 返回结果中的 "instanceUuid" 字段值,如果未找到该字段,则默认返回True。
118
+ """
119
+ from ..apis.instance import Instance
120
+
121
+ return Instance().kill(self.daemonId, self.instanceUuid)
122
+
123
+ def delete(self, deleteFile=False) -> str:
124
+ """
125
+ 删除该实例。
126
+
127
+ **返回:**
128
+ - str: 被删除的实例的uuid。
129
+ """
130
+ from ..apis.instance import Instance
131
+
132
+ return Instance().delete(self.daemonId, [self.instanceUuid], deleteFile)[0]
133
+
134
+ def update(self) -> bool:
135
+ """
136
+ 升级实例。
137
+
138
+ **返回:**
139
+ - bool: 返回操作结果,成功时返回True。
140
+ """
141
+ from ..apis.instance import Instance
142
+
143
+ return Instance().update(self.daemonId, self.instanceUuid)
144
+
145
+ def updateConfig(self, config: dict) -> str | bool:
146
+ """
147
+ 更新该实例配置。
148
+
149
+ **参数:**
150
+ - config (dict): 新的实例配置,以字典形式提供,缺失内容由使用原实例配置填充。
151
+
152
+ **返回:**
153
+ - str|bool: 更新成功后返回更新的实例UUID,如果未找到该字段,则默认返回True。
154
+ """
155
+ from ..apis.instance import Instance
156
+
157
+ updated_config = self.config.dict()
158
+ updated_config.update(config)
159
+
160
+ instance_config = InstanceConfig(**updated_config).dict()
161
+
162
+ return Instance().updateConfig(
163
+ self.daemonId, self.instanceUuid, instance_config
164
+ )
165
+
166
+ def reinstall(self, targetUrl: str, title: str = "", description: str = "") -> bool:
167
+ """
168
+ 重装实例。
169
+
170
+ **参数:**
171
+ - targetUrl (str): 重装文件的目标URL。
172
+ - title (str): 重装文件的标题。
173
+ - description (str, optional): 重装文件的描述,默认为空字符串。
174
+
175
+ **返回:**
176
+ - bool: 返回操作结果,成功时返回True
177
+ """
178
+ from ..apis.instance import Instance
179
+
180
+ return Instance().reinstall(
181
+ self.daemonId, self.instanceUuid, targetUrl, title, description
182
+ )
183
+
184
+
185
+ class InstanceCreateResult(BaseModel):
186
+ instanceUuid: str = ""
187
+ config: InstanceConfig = InstanceConfig()
188
+
189
+
190
+ class InstanceSearchList(BaseModel):
191
+ pageSize: int = 0
192
+ maxPage: int = 0
193
+ data: List[InstanceDetail] = []
194
+ daemonId: str = ""
195
+
196
+ def __init__(self, **data: str):
197
+ super().__init__(**data)
198
+ for instance in self.data:
199
+ instance.daemonId = self.daemonId
200
+
201
+
202
+ class UserInstancesList(BaseModel):
203
+ instanceUuid: str = ""
204
+ daemonId: str = ""
@@ -0,0 +1,63 @@
1
+ from typing import Dict, List, Optional
2
+ from pydantic import BaseModel
3
+ from .daemon import DaemonModel
4
+
5
+
6
+ class SystemUser(BaseModel):
7
+ uid: int = 0
8
+ gid: int = 0
9
+ username: str = ""
10
+ homedir: str = ""
11
+ shell: Optional[str] = None
12
+
13
+
14
+ class SystemInfo(BaseModel):
15
+ user: SystemUser = SystemUser()
16
+ time: int = 0
17
+ totalmem: int = 0
18
+ freemem: int = 0
19
+ type: str = ""
20
+ version: str = ""
21
+ node: str = ""
22
+ hostname: str = ""
23
+ loadavg: List[float] = []
24
+ platform: str = ""
25
+ release: str = ""
26
+ uptime: float = 0
27
+ cpu: float = 0
28
+
29
+
30
+
31
+ class RecordInfo(BaseModel):
32
+ logined: int = 0
33
+ illegalAccess: int = 0
34
+ banips: int = 0
35
+ loginFailed: int = 0
36
+
37
+
38
+ class ChartInfo(BaseModel):
39
+ system: List[Dict[str, float]] = []
40
+ request: List[Dict[str, int]] = []
41
+
42
+
43
+ class ProcessInfo(BaseModel):
44
+ cpu: int = 0
45
+ memory: int = 0
46
+ cwd: str = ""
47
+
48
+
49
+ class RemoteCountInfo(BaseModel):
50
+ total: int = 0
51
+ available: int = 0
52
+
53
+
54
+ class OverviewModel(BaseModel):
55
+ version: str = ""
56
+ specifiedDaemonVersion: str = ""
57
+ system: SystemInfo = SystemInfo()
58
+ record: RecordInfo = RecordInfo()
59
+ process: ProcessInfo = ProcessInfo()
60
+ chart: ChartInfo = ChartInfo()
61
+ remoteCount: RemoteCountInfo = RemoteCountInfo()
62
+ remote: List["DaemonModel"] = []
63
+
mcsmapi/models/user.py ADDED
@@ -0,0 +1,76 @@
1
+ from typing import Any, List
2
+ from pydantic import BaseModel
3
+ from ..models.instance import InstanceDetail, UserInstancesList
4
+
5
+
6
+ class UserModel(BaseModel):
7
+ uuid: str = ""
8
+ userName: str = ""
9
+ passWord: str = ""
10
+ passWordType: int = 0
11
+ salt: str = ""
12
+ permission: int = 1 # 1=用户, 10=管理员, -1=被封禁的用户
13
+ registerTime: str = ""
14
+ loginTime: str = ""
15
+ apiKey: str = ""
16
+ isInit: bool = False
17
+ secret: str = ""
18
+ open2FA: bool = False
19
+ instances: List["UserInstancesList"] = []
20
+
21
+ def delete(self) -> bool:
22
+ """
23
+ 删除该用户。
24
+
25
+ **返回:**
26
+ - bool: 删除成功后返回True。
27
+ """
28
+ from ..apis.user import User
29
+
30
+ return User().delete([self.uuid])
31
+
32
+ def update(self, config: dict[str, Any]) -> bool:
33
+ """
34
+ 更新该用户的信息。
35
+
36
+ 参数:
37
+ - config (dict[str, Any]): 用户的新信息,以字典形式提供,缺失内容使用原用户信息填充。
38
+
39
+ 返回:
40
+ - bool: 更新成功后返回True。
41
+ """
42
+ from ..apis.user import User
43
+
44
+ updated_config = self.dict()
45
+ updated_config.update(config)
46
+ # 过滤用户信息中不需要的字段
47
+ user_config_dict = {
48
+ key: updated_config[key]
49
+ for key in UserConfig.__fields__.keys()
50
+ if key in updated_config
51
+ }
52
+
53
+ user_config = UserConfig(**user_config_dict).dict()
54
+
55
+ return User().update(self.uuid, user_config)
56
+
57
+
58
+ class SearchUserModel(BaseModel):
59
+ total: int = 0
60
+ page: int = 0
61
+ page_size: int = 0
62
+ max_page: int = 0
63
+ data: List[UserModel] = []
64
+
65
+
66
+ class UserConfig(BaseModel):
67
+ uuid: str
68
+ userName: str
69
+ loginTime: str
70
+ registerTime: str
71
+ instances: List[InstanceDetail]
72
+ permission: int # 1=用户, 10=管理员, -1=被封禁的用户
73
+ apiKey: str
74
+ isInit: bool
75
+ secret: str
76
+ open2FA: bool
mcsmapi/pool.py ADDED
@@ -0,0 +1,14 @@
1
+ from enum import Enum
2
+
3
+
4
+ class ApiPool(Enum):
5
+ def __str__(self):
6
+ return self.value
7
+
8
+ AUTH = "api/auth"
9
+ OVERVIEW = "api/overview"
10
+ INSTANCE = "api/instance"
11
+ PROTECTED_INSTANCE = "api/protected_instance"
12
+ SERVICE = "api/service"
13
+ FILE = "api/files"
14
+ IMAGE = "api/environment"
mcsmapi/request.py ADDED
@@ -0,0 +1,94 @@
1
+ from typing import Any
2
+ import requests
3
+ import urllib.parse
4
+ from .exceptions import MCSMError
5
+
6
+
7
+ class Request:
8
+ mcsm_url = ""
9
+ timeout = 5
10
+ session = requests.Session()
11
+ apikey = None
12
+ token = None
13
+
14
+ @classmethod
15
+ def set_mcsm_url(cls, url):
16
+ """设置类级别的 mcsm_url"""
17
+ cls.mcsm_url = url
18
+
19
+ @classmethod
20
+ def set_timeout(cls, timeout):
21
+ """设置类级别的 timeout"""
22
+ cls.timeout = timeout
23
+
24
+ @classmethod
25
+ def set_apikey(cls, apikey):
26
+ """设置类级别的 apikey"""
27
+ cls.apikey = apikey
28
+
29
+ @classmethod
30
+ def set_token(cls, token):
31
+ """设置类级别的 token"""
32
+ cls.token = token
33
+
34
+ @classmethod
35
+ def __init__(cls, mcsm_url=None, timeout=None):
36
+ """初始化时使用类变量,或者使用传入的参数覆盖默认值"""
37
+ cls.mcsm_url = mcsm_url or cls.mcsm_url
38
+ cls.timeout = timeout or cls.timeout
39
+
40
+ @classmethod
41
+ def send(cls, method: str, endpoint: Any, params=None, data=None) -> Any:
42
+ """发送 HTTP 请求"""
43
+ if params is None:
44
+ params = {}
45
+ if data is None:
46
+ data = {}
47
+ if not isinstance(endpoint, str):
48
+ endpoint = str(endpoint)
49
+
50
+ url = urllib.parse.urljoin(cls.mcsm_url, endpoint)
51
+ if cls.apikey is not None:
52
+ params["apikey"] = cls.apikey
53
+ data["apikey"] = cls.apikey
54
+ if cls.token is not None:
55
+ params["token"] = cls.token
56
+ data["token"] = cls.token
57
+
58
+ response = cls.session.request(
59
+ method.upper(),
60
+ url,
61
+ params=params,
62
+ data=data,
63
+ timeout=cls.timeout,
64
+ )
65
+ try:
66
+ response.raise_for_status()
67
+ return response.json()["data"]
68
+ except requests.exceptions.HTTPError as e:
69
+ raise MCSMError(
70
+ response.status_code, response.json().get("data", response.text)
71
+ ) from e
72
+
73
+ @classmethod
74
+ async def upload(cls, url: str, file: bytes) -> bool:
75
+ """上传文件"""
76
+
77
+ response = cls.session.request(
78
+ "POST",
79
+ url,
80
+ headers={"Content-Type": "multipart/form-data"},
81
+ files={"file": file},
82
+ timeout=cls.timeout,
83
+ )
84
+ try:
85
+ response.raise_for_status()
86
+ return True
87
+ except requests.exceptions.HTTPError as e:
88
+ raise MCSMError(
89
+ response.status_code, response.json().get("data", response.text)
90
+ ) from e
91
+
92
+
93
+ send = Request().send
94
+ upload = Request().upload
@@ -0,0 +1,83 @@
1
+ Metadata-Version: 2.2
2
+ Name: mcsmapi
3
+ Version: 0.1.3
4
+ Summary: Shortcut the pypi package of MCSM./快捷操作MCSM的pypi包
5
+ Author-email: molanp <molanpp@outlook.com>
6
+ Project-URL: Source, https://github.com/molanp/mcsmapi
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Description-Content-Type: text/markdown
10
+ License-File: LICENSE
11
+ Requires-Dist: requests
12
+ Requires-Dist: pydantic
13
+
14
+ # MCSM API
15
+
16
+ ![Supported MCSManager Versions](https://img.shields.io/badge/Supported%20MCSManager%20Versions-10.x-blue)
17
+ ![Python Version](https://img.shields.io/badge/Python%20Version-%3E%3D3.7-blue)
18
+ ![PyPI Downloads](https://img.shields.io/pypi/dm/mcsmapi)
19
+
20
+ English|[Chinese Simplified](README_zh-cn.md)
21
+
22
+ > [!important]
23
+ > We need your help, the documentation for this project has not been written yet, if you are willing, please submit pr to help us write the documentation.
24
+
25
+ ## Introduction
26
+
27
+ `mcsmapi` is a PyPI package based on [MCSManager](https://github.com/MCSManager/MCSManager), designed to simplify interactions with the MCSM API.
28
+
29
+ With this library, you can more easily access and operate the various features provided by MCSM.
30
+
31
+ ## Installation
32
+
33
+ You can install `mcsmapi` using `pip`:
34
+
35
+ ```bash
36
+ pip install mcsmapi
37
+ ```
38
+
39
+ ## Supported Features
40
+
41
+ - [x] Dashboard data ([Overview](doc/en/Overview.md))
42
+ - [x] User management ([User](doc/en/User.md))
43
+ - [x] Instance management (`Instance`)
44
+ - [x] Daemon management (`Daemon`)
45
+ - [x] File management (`File`)
46
+ - [x] Image management (`Image`)
47
+
48
+ ## Supported MCSM Versions
49
+
50
+ | MCSM Version | Support Status |
51
+ | :---: | :---: |
52
+ | 10.x | ✅ |
53
+
54
+ ### Quick Example
55
+
56
+ ```python
57
+ from mcsmapi import MCSMAPI
58
+
59
+ # Initialize
60
+ mcsm = MCSMAPI("https://example.com")
61
+
62
+ # Log in with username and password (API permissions depend on the account permissions)
63
+ mcsm.login("username", "password")
64
+
65
+ # Log in with API key (API permissions depend on the API key permissions)
66
+ mcsm.login_with_apikey("apikey")
67
+
68
+ # Get dashboard data
69
+ overview = mcsm.overview()
70
+
71
+ # Get MCSM version
72
+ mcsm_version = mcsm.overview().version
73
+ ```
74
+
75
+ ## Contributing
76
+
77
+ If you encounter any issues or have suggestions for improvements, feel free to submit an [Issue](https://github.com/molanp/mcsmapi/issues) or create a [Pull Request](https://github.com/molanp/mcsmapi/pulls).
78
+
79
+ ## License
80
+
81
+ `mcsmapi` is licensed under the [MIT License](https://opensource.org/licenses/MIT).
82
+
83
+ Please refer to the [LICENSE](LICENSE) file for more details.
@@ -0,0 +1,21 @@
1
+ mcsmapi/__init__.py,sha256=MUAbGnG0qSVKcG9YTCkZru42x1UxcfzfJF9WJzDjU8Q,1451
2
+ mcsmapi/exceptions.py,sha256=mHsAHyoX9SiFDGBMEhesA_ao9hhZZ38EGTp97K7VDp8,184
3
+ mcsmapi/pool.py,sha256=CoOYbyECp4FoXkzwFN7WgtS3vgZtvWO8e93i18vhOEI,308
4
+ mcsmapi/request.py,sha256=5mCzKgrh4OPFKvBo22kIDpX_D1zqCza1nglYUeGWveg,2618
5
+ mcsmapi/apis/daemon.py,sha256=a0351ca2I68S2lFRg5wtV52FuLsaT-_dnqhuBXpE-tQ,1960
6
+ mcsmapi/apis/file.py,sha256=UKD295UK9755Y_fEANZCxPyS9uwpkJ6KcqnNlM2YHMY,10592
7
+ mcsmapi/apis/image.py,sha256=kGuO2U3D3OM8p1jo31U3ACKv-DD-60pkhn1LNiEhhM4,2890
8
+ mcsmapi/apis/instance.py,sha256=GTSMSfwaYElrSO3DO4IBbU8OJvd1A34DzgsL_xgU6I0,10968
9
+ mcsmapi/apis/overview.py,sha256=tBiZZEXVQukzMqw3EvAVbjkG6h2KO115ylpNRONSJ9s,607
10
+ mcsmapi/apis/user.py,sha256=Xza7jAmy8ORkeO2NS-nzKPkG5Immp4FUtskEN0Hd9Z4,2950
11
+ mcsmapi/models/daemon.py,sha256=u7leIa_91eVeia00rhD8HiYiaRKFCOiWFtqSI4WEC2g,3521
12
+ mcsmapi/models/file.py,sha256=qI_3e5C7cHUc0botBP7YWU90J-Uu2-JILzBTQ-PicRA,2760
13
+ mcsmapi/models/image.py,sha256=akx0b7aUnpl-9F2AHUbkinUP15hLHAnSdLlZZxM3bcI,2773
14
+ mcsmapi/models/instance.py,sha256=eDQng8BAVep_ufDYbLHc-sM5JIPn0-AeNqgkOh8wFEM,5595
15
+ mcsmapi/models/overview.py,sha256=kImr_Dy1Mkyf2jJ7bq5E5IAYGyEYzHZ7inrRNxV0u6k,1307
16
+ mcsmapi/models/user.py,sha256=CDJjiG9cY8gW4rYD8SDnxvMGnn1cdeUU801NucPfnrA,1940
17
+ mcsmapi-0.1.3.dist-info/LICENSE,sha256=kn0yZGn5uLIJtr2aAXy8pz_wJqal15ZGnynTU1fCnLQ,1063
18
+ mcsmapi-0.1.3.dist-info/METADATA,sha256=CgoVwe46VfW-2efVTqnpYXcKwic8DhaPOqGkO-o3rVI,2456
19
+ mcsmapi-0.1.3.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
20
+ mcsmapi-0.1.3.dist-info/top_level.txt,sha256=8MUYHd1Or4cbSCd93IaqLA72w0weEuKieopVwIfVlWo,8
21
+ mcsmapi-0.1.3.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (72.1.0)
2
+ Generator: setuptools (75.8.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5