1
- import textwrap , time , copy , random , hashlib , json , os
1
+ import time , hashlib , json , os
2
2
from datetime import datetime , timedelta
3
3
from functools import wraps
4
4
from loguru import logger
5
5
from typing import *
6
6
from pathlib import Path
7
7
from io import BytesIO
8
- from fastapi import Body , File , Form , Body , Query , UploadFile
8
+ from fastapi import UploadFile
9
9
from tempfile import SpooledTemporaryFile
10
10
import json
11
+ import signal
12
+ import contextlib
13
+ import sys
14
+ import socket
11
15
12
16
13
17
DATE_FORMAT = "%Y-%m-%d %H:%M:%S"
@@ -124,4 +128,115 @@ def string_to_long_sha256(s: str) -> int:
124
128
def double_hashing (s : str , modulus : int = 10e12 ) -> int :
125
129
hash1 = string_to_long_sha256 (s )
126
130
hash2 = string_to_long_sha256 (s [::- 1 ]) # 用字符串的反序进行第二次hash
127
- return int ((hash1 + hash2 ) % modulus )
131
+ return int ((hash1 + hash2 ) % modulus )
132
+
133
+
134
+ @contextlib .contextmanager
135
+ def timer (seconds : Optional [Union [int , float ]] = None ) -> Generator :
136
+ """
137
+ A context manager that limits the execution time of a code block to a
138
+ given number of seconds.
139
+ The implementation of this contextmanager are borrowed from
140
+ https://github.com/openai/human-eval/blob/master/human_eval/execution.py
141
+
142
+ Note:
143
+ This function only works in Unix and MainThread,
144
+ since `signal.setitimer` is only available in Unix.
145
+
146
+ """
147
+ if (
148
+ seconds is None
149
+ or sys .platform == "win32"
150
+ or threading .currentThread ().name # pylint: disable=W4902
151
+ != "MainThread"
152
+ ):
153
+ yield
154
+ return
155
+
156
+ def signal_handler (* args : Any , ** kwargs : Any ) -> None :
157
+ raise TimeoutError ("timed out" )
158
+
159
+ signal .setitimer (signal .ITIMER_REAL , seconds )
160
+ signal .signal (signal .SIGALRM , signal_handler )
161
+
162
+ try :
163
+ # Enter the context and execute the code block.
164
+ yield
165
+ finally :
166
+ signal .setitimer (signal .ITIMER_REAL , 0 )
167
+
168
+
169
+ class ImportErrorReporter :
170
+ """Used as a placeholder for missing packages.
171
+ When called, an ImportError will be raised, prompting the user to install
172
+ the specified extras requirement.
173
+ The implementation of this ImportErrorReporter are borrowed from
174
+ https://github.com/modelscope/agentscope/src/agentscope/utils/common.py
175
+ """
176
+
177
+ def __init__ (self , error : ImportError , extras_require : str = None ) -> None :
178
+ """Init the ImportErrorReporter.
179
+
180
+ Args:
181
+ error (`ImportError`): the original ImportError.
182
+ extras_require (`str`): the extras requirement.
183
+ """
184
+ self .error = error
185
+ self .extras_require = extras_require
186
+
187
+ def __call__ (self , * args : Any , ** kwds : Any ) -> Any :
188
+ return self ._raise_import_error ()
189
+
190
+ def __getattr__ (self , name : str ) -> Any :
191
+ return self ._raise_import_error ()
192
+
193
+ def __getitem__ (self , __key : Any ) -> Any :
194
+ return self ._raise_import_error ()
195
+
196
+ def _raise_import_error (self ) -> Any :
197
+ """Raise the ImportError"""
198
+ err_msg = f"ImportError occorred: [{ self .error .msg } ]."
199
+ if self .extras_require is not None :
200
+ err_msg += (
201
+ f" Please install [{ self .extras_require } ] version"
202
+ " of agentscope."
203
+ )
204
+ raise ImportError (err_msg )
205
+
206
+
207
+ def _find_available_port () -> int :
208
+ """
209
+ Get an unoccupied socket port number.
210
+ The implementation of this _find_available_port are borrowed from
211
+ https://github.com/modelscope/agentscope/src/agentscope/utils/common.py
212
+ """
213
+ with socket .socket (socket .AF_INET , socket .SOCK_STREAM ) as s :
214
+ s .bind (("" , 0 ))
215
+ return s .getsockname ()[1 ]
216
+
217
+
218
+ def _check_port (port : Optional [int ] = None ) -> int :
219
+ """Check if the port is available.
220
+ The implementation of this _check_port are borrowed from
221
+ https://github.com/modelscope/agentscope/src/agentscope/utils/common.py
222
+
223
+ Args:
224
+ port (`int`):
225
+ the port number being checked.
226
+
227
+ Returns:
228
+ `int`: the port number that passed the check. If the port is found
229
+ to be occupied, an available port number will be automatically
230
+ returned.
231
+ """
232
+ if port is None :
233
+ new_port = _find_available_port ()
234
+ return new_port
235
+ with socket .socket (socket .AF_INET , socket .SOCK_STREAM ) as s :
236
+ try :
237
+ if s .connect_ex (("localhost" , port )) == 0 :
238
+ raise RuntimeError ("Port is occupied." )
239
+ except Exception :
240
+ new_port = _find_available_port ()
241
+ return new_port
242
+ return port
0 commit comments