diff --git a/.circleci/config.yml b/.circleci/config.yml index 346a509..d150c32 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -32,6 +32,7 @@ jobs: python3 -m venv venv . venv/bin/activate pip install -r requirements.txt + pip install -r dev-requirements.txt - save_cache: paths: @@ -49,6 +50,12 @@ jobs: command: | . venv/bin/activate python test.py + + - run: + name: Code Style Check + command: | + . venv/bin/activate + flake8 . test-3.7: <<: *test-template docker: diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..e76db2b --- /dev/null +++ b/.flake8 @@ -0,0 +1,10 @@ +[flake8] +ignore=E501,E401,F403,F401,F811,W293 +exclude = + .git, + __pycache__, + docs/source/conf.py, + old, + build, + dist + venv \ No newline at end of file diff --git a/dev-requirements.txt b/dev-requirements.txt new file mode 100644 index 0000000..1ae3ec6 --- /dev/null +++ b/dev-requirements.txt @@ -0,0 +1 @@ +flake8 \ No newline at end of file diff --git a/samples/benchmarks/template_engine.py b/samples/benchmarks/template_engine.py index e71d71e..881153c 100644 --- a/samples/benchmarks/template_engine.py +++ b/samples/benchmarks/template_engine.py @@ -41,4 +41,3 @@ async def render(): for _ in range(0, rounds): t.render({'x': b, 'y': y}) print('Jinja2: ', time.time() - t1) - diff --git a/tests/components.py b/tests/components.py index c2f9fcb..a82506e 100644 --- a/tests/components.py +++ b/tests/components.py @@ -78,8 +78,7 @@ async def home(test: TestComponent, test2: TestComponent2, name: str): response = await client.get('/test') self.assertEqual( response.content, - app.components[TestComponent].name + app.components[TestComponent2].name - + b'test' + app.components[TestComponent].name + app.components[TestComponent2].name + b'test' ) def test_loaded_component_class_instead_of_instance_expects_exception(self): diff --git a/vibora/client/response.py b/vibora/client/response.py index 88e8c28..fb9bb12 100644 --- a/vibora/client/response.py +++ b/vibora/client/response.py @@ -22,12 +22,16 @@ class ResponseStatus(Enum): class Response: - __slots__ = ('_connection', '_headers', '_content', '_parser', '_parser_status', '_cookies', - '_status_code', '_decode', '_chunk_size', '_decoder', '_encoding', - 'request', 'url') - - def __init__(self, url: str, connection: Connection, - request: Request, chunk_size: int= 1 * 1024 * 1024, decode: bool=True): + __slots__ = ('_connection', '_headers', '_content', '_parser', + '_parser_status', '_cookies', '_status_code', '_decode', + '_chunk_size', '_decoder', '_encoding', 'request', 'url') + + def __init__(self, + url: str, + connection: Connection, + request: Request, + chunk_size: int = 1 * 1024 * 1024, + decode: bool = True): self._connection = connection self._headers = {} self._content = bytearray() @@ -52,7 +56,7 @@ def json(self, *args, loads=None, **kwargs): loads = json.loads return loads(self.content.decode(self.encoding), *args, **kwargs) - def text(self, encoding: str=None) -> str: + def text(self, encoding: str = None) -> str: return self.content.decode(encoding=encoding or self.encoding) @property @@ -62,8 +66,9 @@ def status_code(self): :return: """ if self._parser_status == ResponseStatus.PENDING_HEADERS: - raise Exception('Status code not loaded yet. ' - 'In streaming mode you should manually call load_headers().') + raise Exception( + 'Status code not loaded yet. ' + 'In streaming mode you should manually call load_headers().') return self._status_code @property @@ -73,8 +78,9 @@ def headers(self): :return: """ if self._parser_status == ResponseStatus.PENDING_HEADERS: - raise Exception('Headers not loaded yet. ' - 'In streaming mode you should manually call load_headers().') + raise Exception( + 'Headers not loaded yet. ' + 'In streaming mode you should manually call load_headers().') return self._headers @property @@ -99,7 +105,8 @@ async def cookies(self): if self._cookies is None: self._cookies = CookiesJar() if self._headers.get('set-cookie'): - self._cookies.add_cookie(Cookie.from_header(self._headers['set-cookie'])) + self._cookies.add_cookie( + Cookie.from_header(self._headers['set-cookie'])) return self._cookies async def read_content(self): @@ -114,7 +121,8 @@ async def read_content(self): length = int(self._headers['Content-Length']) if not self._decoder: # Skipping the HTTP parser for performance. - self._content.extend(await self._connection.read_exactly(length)) + self._content.extend(await + self._connection.read_exactly(length)) self.on_message_complete() else: self._parser.feed(await self._connection.read_exactly(length)) @@ -159,10 +167,13 @@ async def _release_connection(self): :return: """ - await self._connection.pool.release_connection(self._connection, self._parser.should_keep_alive()) + await self._connection.pool.release_connection( + self._connection, self._parser.should_keep_alive()) - async def stream(self, chunk_size: int=1*1024*1024, chunk_timeout: int=10, - complete_timeout: int=300): + async def stream(self, + chunk_size: int = 1 * 1024 * 1024, + chunk_timeout: int = 10, + complete_timeout: int = 300): """ :param complete_timeout: @@ -170,7 +181,8 @@ async def stream(self, chunk_size: int=1*1024*1024, chunk_timeout: int=10, :param chunk_size: :return: """ - if self._parser_status not in (ResponseStatus.PENDING_HEADERS, ResponseStatus.PENDING_BODY): + if self._parser_status not in (ResponseStatus.PENDING_HEADERS, + ResponseStatus.PENDING_BODY): raise StreamAlreadyConsumed if self._parser_status == ResponseStatus.PENDING_HEADERS: await wait_for(self.receive_headers(), chunk_timeout) @@ -182,7 +194,8 @@ async def stream(self, chunk_size: int=1*1024*1024, chunk_timeout: int=10, bytes_to_read = min(remaining, chunk_size) task = self._connection.read_exactly(bytes_to_read) start_time = time.time() - self._parser.feed(await wait_for(task, min(chunk_timeout, complete_timeout))) + self._parser.feed(await wait_for( + task, min(chunk_timeout, complete_timeout))) complete_timeout -= time.time() - start_time remaining -= bytes_to_read yield bytes(self._content) @@ -194,9 +207,11 @@ async def stream(self, chunk_size: int=1*1024*1024, chunk_timeout: int=10, task = self._connection.read_until(b'\r\n') start_time = time.time() try: - self._parser.feed(await wait_for(task, min(chunk_timeout, complete_timeout))) + self._parser.feed(await wait_for( + task, min(chunk_timeout, complete_timeout))) except asyncio.LimitOverrunError as error: - self._parser.feed(await self._connection.read_exactly(error.consumed)) + self._parser.feed(await self._connection.read_exactly( + error.consumed)) complete_timeout -= time.time() - start_time while len(self._content) >= chunk_size: yield self._content[:chunk_size] @@ -248,7 +263,12 @@ def on_message_complete(self): except Exception as error: print(error) - def chunk_complete(self): pass + def chunk_complete(self): + """ + + :return: + """ + pass def __repr__(self): if 400 > self.status_code >= 300: diff --git a/vibora/client/websocket.py b/vibora/client/websocket.py index b5406d3..6893da2 100644 --- a/vibora/client/websocket.py +++ b/vibora/client/websocket.py @@ -5,12 +5,10 @@ from vibora.websockets import FrameParser from .request import WebsocketRequest - # https://websocket.org/echo.html class WebsocketProtocol(asyncio.Protocol): - def __init__(self, transport, loop): self.loop = loop self.transport = transport @@ -28,7 +26,6 @@ async def on_message(self, data): class WebsocketHandshake(asyncio.Protocol): - def __init__(self, client, loop): self.client = client self.loop = loop @@ -43,33 +40,64 @@ def connection_made(self, transport): :param transport: :return: """ - wr = WebsocketRequest(self.client.host, path=self.client.path, origin=self.client.origin) - transport.write(wr.encode()) + websocket_response = WebsocketRequest( + self.client.host, path=self.client.path, origin=self.client.origin) + transport.write(websocket_response.encode()) self.transport = transport print('connected') def data_received(self, data): + """ + + :param data: + :return: + """ self.parser.feed(data) print(f'Data received: {data}') def connection_lost(self, exc): + """ + + :param exc: + :return: + """ print('The server closed the connection') print('Stop the event loop') # Parser Callbacks - def on_body(self): pass + def on_body(self): + """ + + :return: + """ + pass def on_headers_complete(self, headers, status_code): + """ + + :param headers: + :param status_code: + :return: + """ self.current_status = status_code self.current_headers = headers def on_message_complete(self): - self.transport.set_protocol(WebsocketProtocol(self.transport, self.loop)) + """ + + :return: + """ + self.transport.set_protocol( + WebsocketProtocol(self.transport, self.loop)) class WebsocketClient: - - def __init__(self, host: str, port: int, path: str = '/', loop=None, origin: str = None): + def __init__(self, + host: str, + port: int, + path: str = '/', + loop=None, + origin: str = None): self.host = host self.port = port self.path = path @@ -80,12 +108,21 @@ def __init__(self, host: str, port: int, path: str = '/', loop=None, origin: str async def connect(self): factory = partial(WebsocketHandshake, self, self.loop) - await self.loop.create_connection(factory, host=self.host, port=self.port, ssl=True) + await self.loop.create_connection( + factory, host=self.host, port=self.port, ssl=True) async def send(self, msg): if not self.connected: await self.connect() pass - async def receive(self, max_size: int = 1 * 1024 * 1024, stream: bool = False): + async def receive(self, + max_size: int = 1 * 1024 * 1024, + stream: bool = False): + """ + + :param max_size: + :param stream: + :return: + """ pass diff --git a/vibora/limits.py b/vibora/limits.py index 75c96ef..3c4d6ef 100644 --- a/vibora/limits.py +++ b/vibora/limits.py @@ -1,12 +1,9 @@ - - class ServerLimits: - __slots__ = ('worker_timeout', 'keep_alive_timeout', 'response_timeout', 'max_body_size', 'max_headers_size', 'write_buffer') - def __init__(self, worker_timeout: int=60, keep_alive_timeout: int=30, - max_headers_size: int=1024 * 10, write_buffer: int=419430): + def __init__(self, worker_timeout: int = 60, keep_alive_timeout: int = 30, + max_headers_size: int = 1024 * 10, write_buffer: int = 419430): """ :param worker_timeout: @@ -20,11 +17,10 @@ def __init__(self, worker_timeout: int=60, keep_alive_timeout: int=30, class RouteLimits: - __slots__ = ('timeout', 'max_body_size', 'in_memory_threshold') - def __init__(self, max_body_size: int=1*1024*1024, timeout: int=30, - in_memory_threshold: int=1*1024*1024): + def __init__(self, max_body_size: int = 1 * 1024 * 1024, timeout: int = 30, + in_memory_threshold: int = 1 * 1024 * 1024): """ :param max_body_size: diff --git a/vibora/multipart/containers.py b/vibora/multipart/containers.py index 9e7c44d..1d55c43 100644 --- a/vibora/multipart/containers.py +++ b/vibora/multipart/containers.py @@ -19,10 +19,16 @@ def read(self, size): class FileUpload: - def __init__(self, name: str=None, path: str=None, content: bytes=None, iterable=None, - f=None, headers: list=None): + def __init__(self, + name: str = None, + path: str = None, + content: bytes = None, + iterable=None, + f=None, + headers: list = None): if not any([path, content, iterable, f]): - raise Exception('You must supply either: path, content, iterable, f') + raise Exception( + 'You must supply either: path, content, iterable, f') self.name = name if f: self.f = f @@ -41,9 +47,12 @@ def __init__(self, name: str=None, path: str=None, content: bytes=None, iterable class MultipartEncoder: - - def __init__(self, delimiter: bytes, params: dict, chunk_size: int=1*1024*1024, - loop=None, encoding: str='utf-8'): + def __init__(self, + delimiter: bytes, + params: dict, + chunk_size: int = 1 * 1024 * 1024, + loop=None, + encoding: str = 'utf-8'): self.delimiter = b'--' + delimiter self.params = params self.chunk_size = chunk_size @@ -59,9 +68,11 @@ def create_headers(self, name: str, value) -> bytes: :return: """ if isinstance(value, FileUpload): - return f'Content-Disposition: form-data; name="{name}"; filename="{value.name}"'.encode(self.encoding) + return f'Content-Disposition: form-data; name="{name}"; filename="{value.name}"'.encode( + self.encoding) else: - return f'Content-Disposition: form-data; name="{name}"'.encode(self.encoding) + return f'Content-Disposition: form-data; name="{name}"'.encode( + self.encoding) def stream_value(self, value) -> bytes: """ @@ -72,7 +83,8 @@ def stream_value(self, value) -> bytes: if isinstance(value, FileUpload): while True: if value.is_async: - chunk = self.loop.run_until_complete(value.f.read(self.chunk_size)) + chunk = self.loop.run_until_complete( + value.f.read(self.chunk_size)) else: chunk = value.f.read(self.chunk_size) size = len(chunk) @@ -95,7 +107,8 @@ def __iter__(self): if self.evaluated: raise Exception('Streaming encoder cannot be evaluated twice.') for name, value in self.params.items(): - header = self.delimiter + b'\r\n' + self.create_headers(name, value) + b'\r\n\r\n' + header = self.delimiter + b'\r\n' + self.create_headers( + name, value) + b'\r\n\r\n' yield header for chunk in self.stream_value(value): yield chunk diff --git a/vibora/protocol/definitions.py b/vibora/protocol/definitions.py index ae98607..f249c77 100644 --- a/vibora/protocol/definitions.py +++ b/vibora/protocol/definitions.py @@ -8,31 +8,69 @@ class ConnectionStatus: class Connection: + def __init__(self, app, loop): + pass - def __init__(self, app, loop): pass - - def connection_made(self, transport: Transport): pass + def connection_made(self, transport: Transport): + pass - def data_received(self, data): pass + def data_received(self, data): + """ + :param data: + :return: + """ + pass - def write_response(self, response): pass + def write_response(self, response): + """ + :param response: + :return: + """ + pass async def call_async_hooks(self, type_id: int, **kwargs) -> bool: + """ + :param type_id: + :param kwargs: + :return: + """ pass async def process_async_request(self, route, request, stream): pass - def connection_lost(self, exc): pass + def connection_lost(self, exc): + """ + :param exc: + :return: + """ + pass # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # HTTP PARSER CALLBACKS - def on_headers_complete(self, headers: dict, url: bytes, method: bytes): pass + def on_headers_complete(self, headers: dict, url: bytes, method: bytes): + """ + :param headers: + :param url: + :param method: + :return: + """ + pass - def on_body(self, body): pass + def on_body(self, body): + """ - def on_message_complete(self): pass + :param body: + :return: + """ + pass + + def on_message_complete(self): + """ + :return: + """ + pass def update_current_time() -> None: diff --git a/vibora/static.py b/vibora/static.py index 19ed41c..6f8cb6e 100644 --- a/vibora/static.py +++ b/vibora/static.py @@ -8,7 +8,7 @@ from .exceptions import StaticNotFound -def streaming_file(path: str, chunk_size: int=1 * 1024 * 1024): +def streaming_file(path: str, chunk_size: int = 1 * 1024 * 1024): with open(path, 'rb') as f: while True: data = f.read(chunk_size) @@ -21,7 +21,7 @@ class CacheEntry: mime = MimeTypes() - def __init__(self, path: str, available_cache_size: int=0): + def __init__(self, path: str, available_cache_size: int = 0): self.path = path self.content_type = self.mime.guess_type(path) self.etag = self.get_hash(path) @@ -38,7 +38,8 @@ def __init__(self, path: str, available_cache_size: int=0): with open(path, 'rb') as f: self.response = CachedResponse(f.read(), headers=self.headers) else: - self.response = StreamingResponse(partial(streaming_file, path), headers=self.headers) + self.response = StreamingResponse( + partial(streaming_file, path), headers=self.headers) @property def needs_update(self): @@ -57,8 +58,12 @@ def get_hash(path: str, chunk_size=1 * 1024 * 1024): class StaticHandler: - def __init__(self, paths: list, host=None, url_prefix='/static', max_cache_size=10 * 1024 * 1024, - default_responses: dict=None): + def __init__(self, + paths: list, + host=None, + url_prefix='/static', + max_cache_size=10 * 1024 * 1024, + default_responses: dict = None): self.paths = paths self.host = host self.url_prefix = url_prefix @@ -66,9 +71,7 @@ def __init__(self, paths: list, host=None, url_prefix='/static', max_cache_size= self.max_cache_size = max_cache_size self.current_cache_size = 0 self.default_responses = default_responses or {} - self.default_responses.update({ - 304: Response(b'', status_code=304) - }) + self.default_responses.update({304: Response(b'', status_code=304)}) @property def available_cache_size(self): @@ -111,15 +114,21 @@ def parse_response(self, request: Request, cache: CacheEntry): if len(pieces) == 2: start, end = int(pieces[0]), int(pieces[1]) headers = { - 'Content-Range': 'bytes {0}-{1}/{2}'.format(start, end, cache.content_length), - 'Content-Length': str((end - start)), - 'Accept-Ranges': 'bytes' + 'Content-Range': + 'bytes {0}-{1}/{2}'.format(start, end, + cache.content_length), + 'Content-Length': + str((end - start)), + 'Accept-Ranges': + 'bytes' } if request.method == 'HEAD': return Response(b'', headers=headers, status_code=206) else: - return StreamingResponse(RangeFile(cache.path, start, end).stream, - headers=headers, status_code=206) + return StreamingResponse( + RangeFile(cache.path, start, end).stream, + headers=headers, + status_code=206) # Handling HEAD requests if request.method == 'HEAD': @@ -129,7 +138,7 @@ def parse_response(self, request: Request, cache: CacheEntry): @staticmethod def get_range_pieces(header: str) -> list: - header = header[header.find('=')+1:] + header = header[header.find('=') + 1:] values = header.strip().split('-') return values diff --git a/vibora/templates/nodes.py b/vibora/templates/nodes.py index d79719c..3b7ce66 100644 --- a/vibora/templates/nodes.py +++ b/vibora/templates/nodes.py @@ -6,7 +6,7 @@ class Node: - def __init__(self, raw: str=''): + def __init__(self, raw: str = ''): self.children = [] self.raw = raw @@ -14,7 +14,7 @@ def __init__(self, raw: str=''): def check(node: str, is_tag: bool): return None - def compile(self, compiler, recursive: bool=True): + def compile(self, compiler, recursive: bool = True): if self.raw: compiler.add_comment(self.raw) if recursive: @@ -23,7 +23,6 @@ def compile(self, compiler, recursive: bool=True): class ForNode(Node): - def __init__(self, variables: str, target: str, raw: str): super().__init__(raw) self.target = target @@ -34,7 +33,7 @@ def check(node: str, is_tag: bool): if 'for' in node and 'in' in node: variables = node[node.find('for') + 3:node.find('in')] variables = [x.strip() for x in variables.split(',')] - target = node[node.find('in')+3:node.rfind('%')].strip() + target = node[node.find('in') + 3:node.rfind('%')].strip() return ForNode(variables, target, node), '{% endfor %}' @staticmethod @@ -54,15 +53,17 @@ def optimize_stm(content): except (AttributeError, ValueError): return None - def compile(self, compiler, recursive: bool=True): + def compile(self, compiler, recursive: bool = True): super().compile(compiler, recursive=False) var_name = ', '.join(self.variables) - stm = prepare_expression(self.target, compiler.context_var, compiler.current_scope) + stm = prepare_expression(self.target, compiler.context_var, + compiler.current_scope) optimized_stm = self.optimize_stm(stm) if optimized_stm: compiler.add_statement(f'for {var_name} in {stm}:') else: - compiler.add_statement(f'async for {var_name} in {smart_iter.__name__}({stm}):') + compiler.add_statement( + f'async for {var_name} in {smart_iter.__name__}({stm}):') compiler.indent() for variable in self.variables: compiler.current_scope.append(variable) @@ -87,9 +88,10 @@ def check(node: str, is_tag: bool): if found: return IfNode(found.groups()[0], node), '{% endif %}' - def compile(self, compiler, recursive: bool=True): + def compile(self, compiler, recursive: bool = True): super().compile(compiler, recursive=False) - expr = prepare_expression(self.expression, compiler.content_var, compiler.current_scope) + expr = prepare_expression(self.expression, compiler.content_var, + compiler.current_scope) compiler.add_statement('if ' + expr + ':') compiler.indent() for child in self.children: @@ -118,9 +120,10 @@ def check(node: str, is_tag: bool): if found: return ElifNode(found.groups()[0], node), None - def compile(self, compiler, recursive: bool=True): + def compile(self, compiler, recursive: bool = True): super().compile(compiler, recursive=False) - expr = prepare_expression(self.expression, compiler.content_var, compiler.current_scope) + expr = prepare_expression(self.expression, compiler.content_var, + compiler.current_scope) compiler.add_statement('elif ' + expr + ':') compiler.indent() rollback = True @@ -147,12 +150,11 @@ def check(node: str, is_tag: bool): if found: return ElseNode(found.groups()[0], node), None - def compile(self, compiler, recursive: bool=True): + def compile(self, compiler, recursive: bool = True): raise SyntaxError('ElseNodes should not be compiled') class EvalNode(Node): - def __init__(self, code: str, raw: str): super().__init__(raw) self.code = code @@ -171,7 +173,8 @@ def _compile_macro(self, compiler): raise Exception('Macros do not have access to the context.') def _compile_template(self, compiler): - stm = prepare_expression(self.code, compiler.context_var, compiler.current_scope) + stm = prepare_expression(self.code, compiler.context_var, + compiler.current_scope) compiler.add_statement(f'__temp__ = {stm}') compiler.add_statement(f'if iscoroutine(__temp__):') compiler.indent() @@ -182,7 +185,7 @@ def _compile_template(self, compiler): compiler.add_eval(f'str({stm})') compiler.rollback() - def compile(self, compiler, recursive: bool=True): + def compile(self, compiler, recursive: bool = True): super().compile(compiler, recursive=False) if compiler.flavor == CompilerFlavor.MACRO: self._compile_macro(compiler) @@ -191,7 +194,6 @@ def compile(self, compiler, recursive: bool=True): class TextNode(Node): - def __init__(self, text: str): super().__init__('') self.text = text @@ -262,7 +264,9 @@ def check(node: str, is_tag: bool): return StaticNode(groups[0], node), None def compile(self, compiler, recursive: bool = True): - raise SyntaxError('Static nodes should not be compiled. An extension should process them.') + raise SyntaxError( + 'Static nodes should not be compiled. An extension should process them.' + ) class UrlNode(Node): @@ -281,7 +285,9 @@ def check(node: str, is_tag: bool): return UrlNode(match.groups()[0], node), None def compile(self, compiler, recursive: bool = True): - raise SyntaxError('URL nodes should not be compiled. An extension should deal with them.') + raise SyntaxError( + 'URL nodes should not be compiled. An extension should deal with them.' + ) class MacroNode(Node): @@ -306,5 +312,6 @@ def compile(self, compiler, recursive: bool = True): new_compiler.current_scope += scope for child in self.children: child.compile(new_compiler) - new_compiler.add_statement('return \'\'.join(' + new_compiler.content_var + ')') + new_compiler.add_statement('return \'\'.join(' + + new_compiler.content_var + ')') compiler.functions.append(new_compiler.content) diff --git a/vibora/utils.py b/vibora/utils.py index 83c70b8..9f5ed74 100644 --- a/vibora/utils.py +++ b/vibora/utils.py @@ -14,7 +14,6 @@ except ImportError: import json - if os.environ.get('VIBORA_UVLOOP', 1) == '0': # noinspection PyUnresolvedReferences import asyncio as asynclib @@ -44,7 +43,11 @@ def __getattr__(self, item): class RangeFile: - def __init__(self, path: str, start: int, end: int, chunk_size=1 * 1024 * 1024): + def __init__(self, + path: str, + start: int, + end: int, + chunk_size=1 * 1024 * 1024): self.path = path self.current_pointer = start self.start = start @@ -86,7 +89,7 @@ def clean_route_name(prefix: str, name: str) -> str: if prefix[0] == ':': prefix = prefix[1:] if len(prefix) > 0: - if prefix[len(prefix)-1] == ':': + if prefix[len(prefix) - 1] == ':': prefix = prefix[:len(prefix) - 1] if len(prefix) > 0: return prefix + '.' + name @@ -112,7 +115,7 @@ def clean_methods(methods: Iterable[Union[str, bytes]]) -> Tuple[bytes]: return b'GET', -def get_free_port(address: str='127.0.0.1') -> tuple: +def get_free_port(address: str = '127.0.0.1') -> tuple: """ The reference of the socket is returned, otherwise the port could theoretically (highly unlikely) be used be someone else. @@ -123,7 +126,7 @@ def get_free_port(address: str='127.0.0.1') -> tuple: return sock, address, sock.getsockname()[1] -def wait_server_available(host: str, port: int, timeout: int=10) -> None: +def wait_server_available(host: str, port: int, timeout: int = 10) -> None: """ Wait until the server is available by trying to connect to the same. :param timeout: How many seconds wait before giving up. @@ -146,7 +149,7 @@ def wait_server_available(host: str, port: int, timeout: int=10) -> None: raise TimeoutError(f'Server is taking too long to get online.') -def wait_server_offline(host: str, port: int, timeout: int=10) -> None: +def wait_server_offline(host: str, port: int, timeout: int = 10) -> None: """ Wait until the server is offline. :param timeout: How many seconds wait before giving up. @@ -169,7 +172,8 @@ def wait_server_offline(host: str, port: int, timeout: int=10) -> None: raise TimeoutError(f'Server is still running after the timeout threshold.') -def cprint(message: str, color: str= '\033[35m', custom: bool=False) -> None: +def cprint(message: str, color: str = '\033[35m', + custom: bool = False) -> None: """ Colored prints in interactive terminals and PyCharm. :return: None