CheeseAPI 0.0.1__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.
CheeseAPI/server.py ADDED
@@ -0,0 +1,100 @@
1
+ import os, datetime
2
+
3
+ import CheeseType, CheeseType.network
4
+
5
+ class Server:
6
+ def __init__(self, app):
7
+ from app import App
8
+
9
+ self._app: App = app
10
+ self.HOST: CheeseType.network.IPv4 = '127.0.0.1'
11
+ self.PORT: CheeseType.network.Port = 5214
12
+ self._WORKERS: CheeseType.NonNegativeInt = 1
13
+ self.IS_RELOAD: bool = False
14
+
15
+ self._IS_DEBUG: bool = False
16
+ self._IS_REQUEST_LOGGED: bool = True
17
+
18
+ self._STATIC_PATH: bool | str = False
19
+ self._LOG_FILENAME: bool | str = False
20
+
21
+ @property
22
+ def WORKERS(self) -> CheeseType.NonNegativeInt:
23
+ return self._WORKERS
24
+
25
+ @WORKERS.setter
26
+ def WORKERS(self, value):
27
+ value = CheeseType.NonNegativeInt(value)
28
+ if value == 0:
29
+ self._WORKERS = os.cpu_count() * 2
30
+ else:
31
+ self._WORKERS = value
32
+
33
+ @property
34
+ def IS_DEBUG(self) -> bool:
35
+ return self._IS_DEBUG
36
+
37
+ @IS_DEBUG.setter
38
+ def IS_DEBUG(self, value):
39
+ self._IS_DEBUG = CheeseType.Bool(value)
40
+ if isinstance(self._app.logger.filter, set):
41
+ if not self._IS_DEBUG:
42
+ self._app.logger.filter.add('DEBUG')
43
+ elif self._IS_DEBUG:
44
+ self._app.logger.filter.remove('DEBUG')
45
+
46
+ @property
47
+ def IS_REQUEST_LOGGED(self) -> bool:
48
+ return self._IS_REQUEST_LOGGED
49
+
50
+ @IS_REQUEST_LOGGED.setter
51
+ def IS_REQUEST_LOGGED(self, value):
52
+ self._IS_REQUEST_LOGGED = CheeseType.Bool(value)
53
+ if isinstance(self._app.logger.filter, set):
54
+ if not self._IS_REQUEST_LOGGED:
55
+ self._app.logger.filter.add('HTTP')
56
+ self._app.logger.filter.add('WEBSOCKET')
57
+ elif self._IS_REQUEST_LOGGED:
58
+ self._app.logger.filter.remove('HTTP')
59
+ self._app.logger.filter.add('WEBSOCKET')
60
+
61
+ @property
62
+ def LOG_FILENAME(self) -> str | bool:
63
+ return self._LOG_FILENAME
64
+
65
+ @LOG_FILENAME.setter
66
+ def LOG_FILENAME(self, value):
67
+ if self._app.process.name == 'MainProcess':
68
+ if value is not False:
69
+ if value is True:
70
+ self._LOG_FILENAME = datetime.datetime.now().strftime('%Y_%m_%d-%H_%M_%S.log')
71
+ else:
72
+ self._LOG_FILENAME = datetime.datetime.now().strftime(str(value))
73
+ self._app.logger.filePath = os.path.join(self._app.workspace.BASE_PATH + self._app.workspace.LOG_PATH + self.LOG_FILENAME)
74
+ elif value is False:
75
+ self._LOG_FILENAME = False
76
+ self._app.logger.filePath = None
77
+ else:
78
+ logPath = os.path.join(self._app.workspace.BASE_PATH + self._app.workspace.LOG_PATH)
79
+ logFiles = [ os.path.join(logPath, file) for file in os.listdir(logPath) if os.path.isfile(os.path.join(logPath, file)) ]
80
+ if not logFiles:
81
+ self._LOG_FILENAME = False
82
+ self._app.logger.filePath = None
83
+ else:
84
+ logFile = max(logFiles, key = os.path.getmtime)
85
+ self._LOG_FILENAME = logFile.split('/')[-1]
86
+ self._app.logger.filePath = logFile
87
+
88
+ @property
89
+ def STATIC_PATH(self) -> str | bool:
90
+ return self._STATIC_PATH
91
+
92
+ @STATIC_PATH.setter
93
+ def STATIC_PATH(self, value):
94
+ if value is not False:
95
+ if value is True:
96
+ self._STATIC_PATH = '/'
97
+ else:
98
+ self._STATIC_PATH = str(value)
99
+ elif value is False:
100
+ self._STATIC_PATH = False
CheeseAPI/system.py ADDED
@@ -0,0 +1,22 @@
1
+ import platform, pkg_resources
2
+
3
+ import CheeseType
4
+
5
+ class System:
6
+ def __init__(self):
7
+ systems = {
8
+ 'Windows': 'WINDOWS',
9
+ 'Linux': 'LINUX',
10
+ 'Darwin': 'MACOS'
11
+ }
12
+ system = platform.system()
13
+ if system in systems:
14
+ self.SYSTEM: CheeseType.System = CheeseType.System(systems[system])
15
+ else:
16
+ self.SYSTEM: CheeseType.System = CheeseType.System('OTHER')
17
+
18
+ self.PYTHON_VERSION: str = platform.python_version()
19
+ try:
20
+ self.CHEESEAPI_VERSION: str = pkg_resources.get_distribution('CheeseAPI').version
21
+ except:
22
+ self.CHEESEAPI_VERSION: str = None
CheeseAPI/websocket.py ADDED
@@ -0,0 +1,46 @@
1
+ from typing import Dict
2
+
3
+ import asyncio
4
+
5
+ class Websocket:
6
+ def __init__(self):
7
+ self._CLIENTS: Dict[str, asyncio.Queue] = {}
8
+
9
+ async def _send(self, message: any, sid: str):
10
+ if sid in self._CLIENTS:
11
+ if isinstance(message, bytes):
12
+ async def func(send):
13
+ await send({
14
+ 'type': 'websocket.send',
15
+ 'bytes': message
16
+ })
17
+ else:
18
+ async def func(send):
19
+ await send({
20
+ 'type': 'websocket.send',
21
+ 'text': str(message)
22
+ })
23
+ await self._CLIENTS[sid].put(func)
24
+
25
+ async def send(self, message: any, sid: str | list[str] | None = None):
26
+ if not sid:
27
+ for key in self._CLIENTS:
28
+ await self._send(message, key)
29
+ elif isinstance(sid, list):
30
+ for s in sid:
31
+ await self._send(message, s)
32
+ else:
33
+ await self._send(message, sid)
34
+
35
+ async def _close(self, send):
36
+ await send({
37
+ 'type': 'websocket.close'
38
+ })
39
+
40
+ async def close(self, sid: str):
41
+ await self._CLIENTS[sid].put(self._close)
42
+
43
+ def isOnline(self, sid: str) -> bool:
44
+ return sid in self._CLIENTS
45
+
46
+ websocket = Websocket()
CheeseAPI/workspace.py ADDED
@@ -0,0 +1,9 @@
1
+ import os
2
+
3
+ class Workspace:
4
+ def __init__(self):
5
+ self.CHEESEAPI_PATH: str = os.path.dirname(os.path.realpath(__file__))
6
+ self.BASE_PATH: str = os.getcwd()
7
+ self.STATIC_PATH: str = '/static/'
8
+ self.MEDIA_PATH: str = '/media/'
9
+ self.LOG_PATH: str = '/logs/'
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Cheese Unknown
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,290 @@
1
+ Metadata-Version: 2.1
2
+ Name: CheeseAPI
3
+ Version: 0.0.1
4
+ Summary: 一款基于uvicorn的web协程框架
5
+ Home-page: https://github.com/CheeseUnknown/CheeseAPI
6
+ Author: Cheese Unknown
7
+ Author-email: cheese@cheese.ren
8
+ License: MIT
9
+ Keywords: api framework backend asyncio
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Requires-Python: >=3.11
13
+ Description-Content-Type: text/markdown
14
+ License-File: LICENSE
15
+ Requires-Dist: uvicorn[standard]
16
+ Requires-Dist: CheeseType
17
+ Requires-Dist: CheeseLog
18
+ Requires-Dist: xmltodict
19
+
20
+ # **CheeseAPI**
21
+
22
+ ## **介绍**
23
+
24
+ 一款基于uvicorn的web协程框架,目前仍处于开发阶段,一些基础功能已经可以使用。
25
+
26
+ 目前仅保证支持python3.11。
27
+
28
+ ## **功能**
29
+
30
+ 1. 支持部分配置动态设置。
31
+
32
+ 2. 起飞般的请求速度。
33
+
34
+ 3. websocket支持。
35
+
36
+ 4. 类Django的项目结构。
37
+
38
+ 5. 外部模块导入。
39
+
40
+ ## **安装**
41
+
42
+ ```bash
43
+ pip install CheeseAPI
44
+ ```
45
+
46
+ ## **使用**
47
+
48
+ ### **简单的示例**
49
+
50
+ 创建一个入口文件:
51
+
52
+ ```python
53
+ # File path: /app.py
54
+
55
+ from CheeseAPI import App, Request, Response
56
+
57
+ app = App()
58
+
59
+ @app.route('/', [ 'GET' ])
60
+ async def index(request: Request):
61
+ return Response('你好,这里是CheeseAPI!')
62
+
63
+ if __name__ == '__main__':
64
+ app.run()
65
+ ```
66
+
67
+ 使用命令行启动服务器,你可以看到相应的信息打印在控制台上(默认为彩色打印):
68
+
69
+ ```bash
70
+ $ python app.py
71
+ (STARTING) 2023-08-01 00:44:11.143085 > Started CheeseAPI master process 92102
72
+ (STARTING) 2023-08-01 00:44:11.143122 > The application starts loading...
73
+ (STARTING) 2023-08-01 00:44:11.143133 > System information:
74
+ system: MacOS
75
+ python version: 3.11.4
76
+ CheeseAPI version: 0.0.1
77
+ (STARTING) 2023-08-01 00:44:11.143142 > Workspace information:
78
+ CheeseAPI path: /Users/cheese/Desktop/CheeseAPI/CheeseAPI
79
+ base path: /Users/cheese/Desktop/CheeseAPI
80
+ (STARTING) 2023-08-01 00:44:11.143155 > Server information:
81
+ host: 127.0.0.1
82
+ port: 5214
83
+ workers: 1
84
+ is reload: False
85
+ is debug: False
86
+ is request logged: True
87
+ (STARTING) 2023-08-01 00:44:11.143215 > The server running on http://127.0.0.1:5214
88
+ (STARTING) 2023-08-01 00:44:11.153093 > The server started, took 0.009919 seconds
89
+ ```
90
+
91
+ 此时访问`GET http://127.0.0.1:5214`,会返回相应的`Response`。
92
+
93
+ ### **项目结构**
94
+
95
+ CheeseAPI采用类Django的结构:
96
+
97
+ ```
98
+ | - User
99
+ | - model.py
100
+ | - api.py
101
+ | - service.py
102
+ | - decorator.py
103
+ | - Permission
104
+ | - model.py
105
+ | - api.py
106
+ | - service.py
107
+ | - decorator.py
108
+ | - app.py
109
+ ```
110
+
111
+ 在项目根目录下的文件夹(不包括隐藏文件夹)内的文件会在项目启动时自动导入。
112
+
113
+ 在CheeseAPI中并没有强制规定文件名与其代码的关联性,但建议的文件命名方式如下:
114
+
115
+ | 文件名 | 备注 |
116
+ | - | - |
117
+ | model.py | 模型类 |
118
+ | api.py | api接口 |
119
+ | service.py | 业务逻辑实现 |
120
+ | decorator.py | 装饰器 |
121
+
122
+ ### **用户的增删改查**
123
+
124
+ 该示例仅为演示,所用用户结构为普通的`class`构建,在正常项目中你应该使用`SQL`或`ORM`。
125
+
126
+ 在开始,首先需要创建一个用户类:
127
+
128
+ ```python
129
+ # File path: /User/model.py
130
+
131
+ import datetime, uuid
132
+ from enum import Enum
133
+ from typing import Optional
134
+
135
+ class Gender(Enum):
136
+ MALE = 0
137
+ FEMALE = 1
138
+ UNKNOWN = 2
139
+
140
+ class User:
141
+ def __init__(self, nickname: str, password: str, gender: Optional[Gender] = Gender.UNKNOWN):
142
+ self.id: uuid.UUID = uuid.uuid4()
143
+ self.nickname: str = nickname
144
+ self.password: str = password
145
+ self.gender: Gender = gender
146
+ self.join_date: datetime.datetime = datetime.datetime.now()
147
+ ```
148
+
149
+ 实现增删改查的逻辑代码:
150
+
151
+ ```python
152
+ # File path: /User/service.py
153
+
154
+ import uuid
155
+ from typing import Optional, Dict
156
+
157
+ from User.model import User, Gender
158
+
159
+ users: Dict[uuid.UUID, User] = {}
160
+ loginUsers: Dict[uuid.UUID, User] = {}
161
+
162
+ # 注册用户
163
+ def register(nickname: str, password: str, gender: Gender):
164
+ user = User(nickname, password, gender)
165
+ users[user.id] = user
166
+
167
+ # 登入用户
168
+ def login(nickname: str, password: str) -> User | None:
169
+ for id, user in users.item():
170
+ if user.nickname == nickname and user.password == password:
171
+ loginUsers[id] = user
172
+ return user
173
+ return None
174
+
175
+ # 登出用户
176
+ def logout(id: uuid.UUID):
177
+ if id in loginUsers:
178
+ del loginUsers[id]
179
+
180
+ # 获取用户
181
+ def get_user(id: uuid.UUID) -> User | None:
182
+ if id in users:
183
+ return users[id]
184
+ return None
185
+
186
+ # 修改用户信息
187
+ def set_user(id: uuid:UUID, nickname: str | None, password: str | None, gender: Gender | None) -> User | None:
188
+ if id in users:
189
+ user = users[id]
190
+ if nickname:
191
+ user.nickname = nickname
192
+ if password:
193
+ user.password = password
194
+ if gender:
195
+ user.gender = gender
196
+ return user
197
+ return None
198
+
199
+ # 删除用户
200
+ def delete_user(id: uuid.UUID) -> bool:
201
+ if id in loginUsers:
202
+ del loginUsers[id]
203
+ if id in users:
204
+ del users[id]
205
+ return True
206
+ return False
207
+ ```
208
+
209
+ 实现API接口,在实际项目中,你需要先进行数据的初步校验:
210
+
211
+ ```python
212
+ # File path:
213
+
214
+ import uuid
215
+
216
+ from CheeseAPI import app, Request, Route, Response, JsonResponse
217
+
218
+ from User.model import Gender
219
+ from User import service
220
+
221
+ route = Route('/User', app.route)
222
+
223
+ @route.post('/register')
224
+ def register(request: Request):
225
+ nickname = request.form.get('nickname')
226
+ password = request.form.get('password')
227
+ gender = Gender(request.form.get('gender', 2))
228
+ service.register(nickname, password, gender)
229
+ return Response('注册成功!')
230
+
231
+ @route.post('/login')
232
+ def login(request: Request):
233
+ nickname = request.form.get('nickname')
234
+ password = request.form.get('password')
235
+ user = service.login(nickname, password)
236
+ if user:
237
+ return JsonResponse(user.__dict__)
238
+ return Response('登入失败!', 401)
239
+
240
+ @route.post('/<id:uuid>/logout')
241
+ def logout(id: uuid.UUID):
242
+ service.logout(id)
243
+ return Response('登出成功!')
244
+
245
+ @route.get('/<id:uuid>')
246
+ def get_user(id: uuid.UUID):
247
+ user = service.get_user(id)
248
+ if user:
249
+ return JsonResponse(user.__dict__)
250
+ return Response('查找失败!', 404)
251
+
252
+ @route.put('/<id:uuid>')
253
+ def set_user(id: uuid:UUID):
254
+ nickname = request.form.get('nickname')
255
+ password = request.form.get('password')
256
+ gender = request.form.get('gender')
257
+ if gender:
258
+ gender = Gender(gender)
259
+ user = service.set_user(id, nickname, password, gender)
260
+ if user:
261
+ return JsonResponse(user.__dict__)
262
+ return Response('修改信息失败!', 404)
263
+
264
+ @route.delete('/<id:uuid>')
265
+ def delete_user(id: uuid:UUID):
266
+ flag = service.delete_user(id)
267
+ if flag:
268
+ return Response('删除用户成功!')
269
+ return Response('删除用户失败!', 404)
270
+ ```
271
+
272
+ 这样,一个简陋的用户系统就搭建完成了,其中有很多纰漏例如会把密码返回出去 :(
273
+
274
+ ## **更多...**
275
+
276
+ ### 1. **[详细配置](https://github.com/CheeseUnknown/CheeseAPI/tree/master/documents/detail.md)**
277
+
278
+ ### 2. **[模块](https://github.com/CheeseUnknown/CheeseAPI/tree/master/documents/module.md)**
279
+
280
+ ### 3. **[路由](https://github.com/CheeseUnknown/CheeseAPI/tree/master/documents/route.md)**
281
+
282
+ ### 4. **[请求](https://github.com/CheeseUnknown/CheeseAPI/tree/master/documents/request.md)**
283
+
284
+ ### 5. **[响应](https://github.com/CheeseUnknown/CheeseAPI/tree/master/documents/response.md)**
285
+
286
+ ### 6. **[装饰器](https://github.com/CheeseUnknown/CheeseAPI/tree/master/documents/decorator.md)**
287
+
288
+ ### 7. **[websocket](https://github.com/CheeseUnknown/CheeseAPI/tree/master/documents/websocket.md)**
289
+
290
+ ### 8. **[信号](https://github.com/CheeseUnknown/CheeseAPI/tree/master/documents/signal.md)**
@@ -0,0 +1,18 @@
1
+ CheeseAPI/__init__.py,sha256=NY0-i6bZ9UwySWJIUBTD8I6gPLjDDRqMwq8wYzFgoPg,326
2
+ CheeseAPI/app.py,sha256=OAIPBcCkv9SgEMQ1rXIMAEdv6hUEildlNNjswgOtuIQ,20884
3
+ CheeseAPI/cSignal.py,sha256=pz1CbPftk9g2_C69NIpB-LS3zg7dEk_ZWVzjC5XYe28,1153
4
+ CheeseAPI/exception.py,sha256=dQPyfbQrfcpf0WYxB0nEfhekGgMPXn_OvrZaP1O_CmM,492
5
+ CheeseAPI/file.py,sha256=igUcsROGUWGOTMEqQNGw2NOuXA2FynAT_DwARwRPH5c,2434
6
+ CheeseAPI/module.py,sha256=64SMJWH9e6Gqw20bR867S2TUGTKrs2Oy3nTE4MPDjk0,2287
7
+ CheeseAPI/request.py,sha256=LP5sZh2blcNDl-GU7HryVOu9B1IwDC5QaVocvQEOIps,3674
8
+ CheeseAPI/response.py,sha256=mUW3o2VrtRgXc1WO_X8ZorqnAnqOkAe4ddfU4Lv8xI4,12439
9
+ CheeseAPI/route.py,sha256=24uHLiBGPS9zrkafOIzKwB4qPdkNLCqdPxu0TJSREX8,4317
10
+ CheeseAPI/server.py,sha256=0uGVS2gosoMDozTq5PmvtkJMmq2BCkw_IbTvcrEgTtI,3525
11
+ CheeseAPI/system.py,sha256=fFxS4m7TLoPKmAMtrjyJ_qaqX1Yit8HO8SrBW_mYOqQ,676
12
+ CheeseAPI/websocket.py,sha256=I7viqhjafYcldYuLTdKgF_cCcImtpjddWqSdSrdhvGs,1345
13
+ CheeseAPI/workspace.py,sha256=5VeV5UsoCPqLpeYzQf5YC-fwwxnJqEzTEY1esyLBxyc,295
14
+ CheeseAPI-0.0.1.dist-info/LICENSE,sha256=5vFb3i4UDlskszJ3jGPh8bXrM_axJfDRRuvLu1M3bIs,1070
15
+ CheeseAPI-0.0.1.dist-info/METADATA,sha256=r79UWaYbloPPS-1HUpqqPCYEhHzgaKjptrboVGDDaBM,7749
16
+ CheeseAPI-0.0.1.dist-info/WHEEL,sha256=2wepM1nk4DS4eFpYrW1TTqPcoGNfHhhO_i5m4cOimbo,92
17
+ CheeseAPI-0.0.1.dist-info/top_level.txt,sha256=aNM-zieAGzzB3H4eD7fPJBbAtRaJfF8l8Dej4cGh2qY,10
18
+ CheeseAPI-0.0.1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: bdist_wheel (0.38.4)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ CheeseAPI