python-progressor
Advanced tools
+1
-1
| Metadata-Version: 2.1 | ||
| Name: python-progressor | ||
| Version: 0.1.1 | ||
| Version: 0.1.2 | ||
| Summary: | ||
@@ -5,0 +5,0 @@ Home-page: https://github.com/40ants/python-progressor |
+119
-27
@@ -1,8 +0,10 @@ | ||
| #/usr/bin/env python3 | ||
| #!/usr/bin/env python3 | ||
| # coding: utf-8 | ||
| import time | ||
| import socket | ||
| import json | ||
| import contextlib | ||
| import sys | ||
| from typing import Sized, Iterable | ||
| from collections import Sized, Iterable | ||
| from jsonrpc_requests import Server as BaseRPCClient | ||
@@ -22,17 +24,25 @@ | ||
| decoded = self.body.decode('utf-8') | ||
| headers, body = decoded.split('\r\n\r\n') | ||
| return json.loads(body) | ||
| return json.loads(decoded) | ||
| class CommunicationError(RuntimeError): | ||
| pass | ||
| class UnableToSendRequest(CommunicationError): | ||
| pass | ||
| class UnableToReadResponse(CommunicationError): | ||
| pass | ||
| class RPCClient(BaseRPCClient): | ||
| def __init__(self, host='localhost', port=7890): | ||
| self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | ||
| # self.socket.setblocking(False) | ||
| self.host = host | ||
| self.port = port | ||
| self.connected = False | ||
| self.next_command_id = 0 | ||
| self.socket = None | ||
| def __enter__(self): | ||
| self.socket.connect((self.host, self.port)) | ||
| self.connected = True | ||
| self.reconnect() | ||
| return self | ||
@@ -42,4 +52,14 @@ | ||
| self.socket.close() | ||
| self.connected = False | ||
| self.socket = None | ||
| def reconnect(self): | ||
| if self.socket: | ||
| self.socket.close() | ||
| self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | ||
| try: | ||
| self.socket.connect_ex((self.host, self.port)) | ||
| except: | ||
| self.socket = None | ||
| def send_request(self, method_name, is_notification, params): | ||
@@ -53,9 +73,56 @@ # content = self.serialize(method_name, params, is_notification).encode('utf-8') | ||
| request = header + content | ||
| self.socket.sendall(request.encode('utf-8')) | ||
| try: | ||
| self.socket.sendall(request.encode('utf-8')) | ||
| except socket.error: | ||
| raise UnableToSendRequest() | ||
| if not is_notification: | ||
| response = self.socket.recv(1024 * 4) | ||
| return self.parse_response(Response(response)) | ||
| response = self.read_response() | ||
| return self.parse_response(response) | ||
| def read_response(self): | ||
| approximate_header_size = len('Content-Length:') * 4 | ||
| delimiter = '\r\n\r\n' | ||
| header = self.socket.recv(approximate_header_size) | ||
| if not header: | ||
| raise UnableToReadResponse('No data was received') | ||
| if delimiter not in header: | ||
| raise UnableToReadResponse('No Content-Length header') | ||
| headers, body = header.split(delimiter) | ||
| def parse_header(line): | ||
| name, value = line.split(':', 1) | ||
| return ( | ||
| name.strip().lower(), | ||
| value.strip().lower(), | ||
| ) | ||
| headers = dict(map(parse_header, headers.split('\n'))) | ||
| if 'content-length' not in headers: | ||
| raise UnableToReadResponse('No Content-Length header') | ||
| try: | ||
| content_length = int(headers['content-length']) | ||
| except ValueError: | ||
| raise UnableToReadResponse('Bad value in Content-Length header') | ||
| block_size = 1024 | ||
| remaining_length = content_length - len(body) | ||
| while remaining_length > 0: | ||
| received = self.socket.recv(min(block_size, remaining_length)) | ||
| if not received: | ||
| raise UnableToReadResponse('Error during fetching response body') | ||
| body += received | ||
| remaining_length = content_length - len(body) | ||
| return Response(body) | ||
| class Progress(): | ||
@@ -73,13 +140,29 @@ def __init__(self, | ||
| self.current = current | ||
| self.pending_increments = 0 | ||
| def increment(self, value=1): | ||
| self.client.increment( | ||
| id=self.id, | ||
| value=value, | ||
| ) | ||
| self.pending_increments += value | ||
| try: | ||
| self.client.increment( | ||
| id=self.id, | ||
| value=self.pending_increments, | ||
| ) | ||
| self.pending_increments = 0 | ||
| except CommunicationError: | ||
| self.client.reconnect() | ||
| def create_progress(client, id=None, description=None, total=None, current=0, ttl=DEFAULT_TTL): | ||
| if id is None: | ||
| id = str(int(time.time())) | ||
| @contextlib.contextmanager | ||
| def create_progress(id=None, | ||
| description=None, | ||
| total=None, | ||
| current=0, | ||
| ttl=DEFAULT_TTL, | ||
| host=DEFAULT_HOST, | ||
| port=DEFAULT_PORT): | ||
| with RPCClient() as client: | ||
| if id is None: | ||
| id = str(int(time.time())) | ||
| response = client.create( | ||
@@ -92,3 +175,3 @@ id=id, | ||
| ) | ||
| return Progress(client, **response) | ||
| yield Progress(client, **response) | ||
@@ -108,9 +191,9 @@ | ||
| with RPCClient() as client: | ||
| progress = create_progress( | ||
| client, | ||
| with create_progress( | ||
| host=host, | ||
| port=port, | ||
| total=total, | ||
| description=description, | ||
| ttl=ttl, | ||
| ) | ||
| ) as progress: | ||
| for item in obj: | ||
@@ -122,6 +205,15 @@ yield item | ||
| if __name__ == '__main__': | ||
| for i in p(range(100), | ||
| description='От 1 до 100', | ||
| to_number = 100 | ||
| description = 'From 1 to {}'.format(to_number) | ||
| if len(sys.argv) > 1: | ||
| description = sys.argv[1] | ||
| if len(sys.argv) > 2: | ||
| to_number = int(sys.argv[2]) | ||
| for i in p(range(to_number), | ||
| description=description, | ||
| ttl=3600): | ||
| time.sleep(0.1) | ||
| print(i) |
+2
-2
| [tool.poetry] | ||
| name = "python-progressor" | ||
| module_name = "progressor" | ||
| version = "0.1.1" | ||
| version = "0.1.2" | ||
| description = "" | ||
@@ -16,3 +16,3 @@ authors = ["Alexander Artemenko <svetlyak.40wt@gmail.com>"] | ||
| [tool.poetry.dev-dependencies] | ||
| pytest = "^3.0" | ||
| # pytest = "^3.0" | ||
@@ -19,0 +19,0 @@ [build-system] |
+1
-1
@@ -11,3 +11,3 @@ # -*- coding: utf-8 -*- | ||
| 'name': 'python-progressor', | ||
| 'version': '0.1.1', | ||
| 'version': '0.1.2', | ||
| 'description': '', | ||
@@ -14,0 +14,0 @@ 'long_description': None, |
Alert delta unavailable
Currently unable to show alert delta for PyPI packages.
7531
48.36%184
60%