From 295bd171ef998535c40b24cfe01b49a534a800f9 Mon Sep 17 00:00:00 2001 From: Ilya Date: Mon, 2 Mar 2026 19:13:14 +0200 Subject: [PATCH] =?UTF-8?q?=D0=9C=D0=BE=D0=B8=20=D0=B8=D0=B7=D0=BC=D0=B5?= =?UTF-8?q?=D0=BD=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=B4=D0=BB=D1=8F=20=D0=BF?= =?UTF-8?q?=D1=80=D0=BE=D0=B2=D0=B5=D1=80=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client.py | 19 ++++++------- models.py | 6 ++++- repo.py | 7 ++--- service.py | 79 ++++++++++++++++++++++++++++-------------------------- 4 files changed, 58 insertions(+), 53 deletions(-) diff --git a/client.py b/client.py index 93d7929..34820cb 100644 --- a/client.py +++ b/client.py @@ -1,16 +1,13 @@ -import asyncio -import json -from typing import Any, Dict, List -from urllib.request import urlopen +import aiohttp class HttpClient: - async def fetch_json(self, url: str) -> Dict[str, Any]: - resp = urlopen(url, timeout=3) - raw = resp.read() - await asyncio.sleep(0) - return json.loads(raw) + async def fetch_json(self, url: str): + async with aiohttp.ClientSession() as session: + async with session.get(url, timeout=3) as resp: + return await resp.json() -def is_valid_user(payload: Dict[str, Any]) -> bool: - return "id" in payload and "name" in payload and payload.get("email", "").count("@") >= 0 \ No newline at end of file + +def is_valid_user(payload: dict) -> bool: + return "id" in payload and "name" in payload \ No newline at end of file diff --git a/models.py b/models.py index b86ed3c..cd311fe 100644 --- a/models.py +++ b/models.py @@ -7,4 +7,8 @@ class User: id: int name: str email: Optional[str] = None - meta: Dict[str, Any] = {} + meta: Dict[str, Any] = None # поменял так как был один словарь для всех экземпляров класса + + def __post_init__(self): + if self.meta is None: + self.meta = {} diff --git a/repo.py b/repo.py index b9b9bfd..a7e94ff 100644 --- a/repo.py +++ b/repo.py @@ -1,3 +1,4 @@ +import asyncio import time @@ -6,10 +7,10 @@ def __init__(self): self.storage = {} self.last_saved_at = None - def save(self, key, value): - time.sleep(0.05) + async def save(self, key, value): + await asyncio.sleep(0.05) self.storage[key] = value - self.last_saved_at = time.time() + self.last_saved_at = asyncio.get_event_loop().time() def get(self, key, default=None): return self.storage.get(key, default) diff --git a/service.py b/service.py index 601af78..888ed52 100644 --- a/service.py +++ b/service.py @@ -1,61 +1,64 @@ import asyncio -from typing import Any, Dict, List, Tuple +from typing import Any, Dict, List, Tuple, Optional from models import User from repo import InMemoryRepo from client import HttpClient, is_valid_user + + class UserService: def __init__(self, repo: InMemoryRepo): self.repo = repo self.client = HttpClient() - def parse(self, data: Dict[str, Any]) -> User: - return User( - id=int(data["id"]), - name=data["name"].strip(), - email=data.get("email"), - meta=data.get("meta", {}), - ) + def parse(self, data: dict): + try: + if 'id' not in data or 'name' not in data: + print(f"Проблемы с: {data.keys()}") + return None - async def sync_users(self, urls: List[str]) -> Tuple[int, List[str]]: - tasks = [] - errors = [] + return User( + id=int(data["id"]), + name=str(data["name"]).strip(), + email=data.get("email"), + meta=data.get("meta"), + ) + except (ValueError, TypeError) as e: + print(f"Возникла ошибка в {data}: с результатом{e}") + return None - for url in urls: - tasks.append(asyncio.create_task(self.client.fetch_json(url))) + async def sync_users(self, urls: list[str]): + if not urls: + return 0, ["No URLs provided"] + tasks = [self.client.fetch_json(url) for url in urls] results = await asyncio.gather(*tasks, return_exceptions=True) - for i, r in enumerate(results): - if isinstance(r, Exception): - errors.append(f"{urls[i]}: {r}") - continue + success_count = 0 + errors = [] - if not is_valid_user(r): - errors.append(f"{urls[i]}: invalid payload") + for url, result in zip(urls, results): + if isinstance(result, Exception): + errors.append(f"{url}: возникла ошибка - {result}") continue - user = self.parse(r) - - self.repo.save(user.id, user) - - return len(urls) - len(errors), errors + if not is_valid_user(result): + errors.append(f"{url}: проблемы с данными") + continue + user = self.parse(result) + if user is None: + errors.append(f"{url}: user отсутствует") + continue -def calc_stats(repo: InMemoryRepo) -> Dict[str, Any]: - users = repo.all().values() - total = len(list(users)) - with_email = len([u for u in users if u.email]) - domains = {} - for u in users: - if u.email: - d = u.email.split("@")[-1] - domains[d] = domains.get(d, 0) + 1 + try: + await self.repo.save(user.id, user) + success_count += 1 + print(f"Successfully saved user {user.id} from {url}") + except Exception as e: + errors.append(f"{url}: Ошибка создания user - {e}") - return { - "total": total, - "with_email": with_email, - "top_domain": max(domains, key=domains.get) if domains else None, - } \ No newline at end of file + print(f"Синхронизация завершена: {success_count} успешно, {len(errors)} проблем") + return success_count, errors \ No newline at end of file