From b4583b1f33f92f84575c541e107aafc7fa1aa037 Mon Sep 17 00:00:00 2001 From: dashabtv Date: Sun, 27 Sep 2026 15:15:58 +0300 Subject: [PATCH 1/2] hw1 --- hw1/app.py | 118 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 117 insertions(+), 1 deletion(-) diff --git a/hw1/app.py b/hw1/app.py index 6107b87..07f61be 100644 --- a/hw1/app.py +++ b/hw1/app.py @@ -1,4 +1,5 @@ from typing import Any, Awaitable, Callable +import json async def application( @@ -12,7 +13,122 @@ async def application( receive: Корутина для получения сообщений от клиента send: Корутина для отправки сообщений клиенту """ - # TODO: Ваша реализация здесь + + if scope["type"] == "lifespan": + while True: + message = await receive() + if message["type"] == "lifespan.startup": + await send({ + "type": "lifespan.startup.complete" + }) + elif message["type"] == "lifespan.shutdown": + await send({ + "type": "lifespan.shutdown.complete" + }) + return + if scope["type"] != "http": + return + + method = scope["method"] + path = scope["path"] + query_string = scope.get("query_string", b"").decode("utf-8") + + async def send_json(status, data): + body = json.dumps(data).encode("utf-8") + await send({ + "type": "http.response.start", + "status": status, + "headers": [ + (b"content-type", b"application/json") + ], + }) + await send({ + "type": "http.response.body", + "body": body, + }) + return + + + if path == "/factorial": + if method != "GET": + await send_json(422, {"error" : "unsupported method"}) + return + + if query_string == "": + await send_json(422, {"error" : "n is requiered"}) + return + + key, value = query_string.split("=", 1) + if key != "n": + await send_json(422, {"error" : "wrong param"}) + return + try: + n = int(value) + except ValueError: + await send_json(422, {"error": "n must be integer"}) + return + if n < 0: + await send_json(400, {"error" : "n must be positive"}) + return + + res = 1 + for i in range(1, n + 1): + res *= i + print("result=", res) + await send_json(200, {"result" : res}) + return + + if path.startswith("/fibonacci/"): + if method != "GET": + await send_json(422, {"error" : "unsupported method"}) + return + n_string = path[len("/fibonacci/"):] + try: + n = int(n_string) + except ValueError: + await send_json(422, {"error": "n must be integer"}) + return + if n < 0: + await send_json(400, {"error" : "n must be positive"}) + return + a, b = 0, 1 + for i in range(n): + a, b = b, a + b + await send_json(200, {"result" : b}) + return + + if path == "/mean": + if method != "GET": + await send_json(422, {"error": "unsupported method"}) + return + + message = await receive() + body = message.get("body", b"") + + if not body: + await send_json(422, {"error": "body is required"}) + return + + try: + nums = json.loads(body.decode("utf-8")) + except (json.JSONDecodeError, UnicodeDecodeError): + await send_json(422, {"error": "invalid json"}) + return + + if nums is None: + await send_json(422, {"error": "numbers are required"}) + return + + if nums == []: + await send_json(400, {"error": "numbers must not be empty"}) + return + + res = sum(nums) / len(nums) + await send_json(200, {"result": res}) + return + + await send_json(404, {"error": "not found"}) + return if __name__ == "__main__": import uvicorn From 699d140a3944f0f7ab8dfd88f1266ba96b543dce Mon Sep 17 00:00:00 2001 From: dashabtv Date: Sun, 4 Oct 2026 23:48:55 +0500 Subject: [PATCH 2/2] hw2 --- hw2/hw/shop_api/main.py | 302 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 301 insertions(+), 1 deletion(-) diff --git a/hw2/hw/shop_api/main.py b/hw2/hw/shop_api/main.py index f60a8c6..eaaacf4 100644 --- a/hw2/hw/shop_api/main.py +++ b/hw2/hw/shop_api/main.py @@ -1,3 +1,303 @@ -from fastapi import FastAPI +from fastapi import FastAPI, Query, HTTPException +from typing import Any, Annotated +from http import HTTPStatus +from fastapi.responses import JSONResponse app = FastAPI(title="Shop API") + +items: dict[int, dict[str, Any]] = {} +next_item_id = 1 + +carts: dict[int, dict[int, int]] = {} +next_cart_id = 1 + + +@app.post("/item") +def create_item(data: dict[str, Any]) -> JSONResponse: + global next_item_id + + if "name" not in data or "price" not in data: + raise HTTPException( + status_code=422, + detail="Item must contain name and price", + ) + + item = { + "id": next_item_id, + "name": data["name"], + "price": data["price"], + "deleted": False, + } + + items[next_item_id] = item + next_item_id += 1 + + return JSONResponse( + status_code=HTTPStatus.CREATED, + content=item, + ) + + +@app.get("/item/{id}") +def get_item(id: int) -> JSONResponse: + if id not in items or items[id]["deleted"]: + raise HTTPException( + status_code=HTTPStatus.NOT_FOUND, + detail="Item not found", + ) + + return JSONResponse( + status_code=HTTPStatus.OK, + content=items[id], + ) + + +@app.get("/item") +def get_items( + offset: Annotated[int,Query()] = 0, + limit: Annotated[int,Query()] = 10, + min_price: Annotated[float | None, Query()] = None, + max_price: Annotated[float | None, Query()] = None, + show_deleted: Annotated[bool, Query()] = False, +) -> JSONResponse: + if offset < 0: + raise HTTPException(status_code=422, detail="offset must be non-negative") + if limit <= 0: + raise HTTPException(status_code=422, detail="limit must be positive") + if min_price is not None and min_price < 0: + raise HTTPException(status_code=422, detail="min_price must be non-negative") + if max_price is not None and max_price < 0: + raise HTTPException(status_code=422, detail="max_price must be non-negative") + + result = [] + for item in items.values(): + if not show_deleted and item["deleted"]: + continue + if min_price is not None and item["price"] < min_price: + continue + if max_price is not None and item["price"] > max_price: + continue + result.append(item) + + result = result[offset : offset + limit] + return JSONResponse( + status_code=HTTPStatus.OK, + content=result, + ) + + +@app.put("/item/{id}") +def put_item(id: int, data: dict[str, Any]) -> JSONResponse: + if id not in items or items[id]["deleted"]: + raise HTTPException( + status_code=HTTPStatus.NOT_FOUND, + detail="Item not found", + ) + if "name" not in data or "price" not in data: + raise HTTPException( + status_code=422, + detail="Item must contain name and price", + ) + items[id] = { + "id": id, + "name": data["name"], + "price": data["price"], + "deleted": False, + } + + return JSONResponse( + status_code=HTTPStatus.OK, + content=items[id], + ) + + +@app.patch("/item/{id}") +def patch_item(id: int, data: dict[str, Any]) -> JSONResponse: + if id not in items: + raise HTTPException( + status_code=HTTPStatus.NOT_FOUND, + detail="Item not found", + ) + if items[id]["deleted"]: + raise HTTPException( + status_code=304, + detail="Item is deleted", + ) + for key in data: + if key not in ("name", "price"): + raise HTTPException( + status_code=422, + detail="You can change only name and price", + ) + + if "name" in data: + items[id]["name"] = data["name"] + if "price" in data: + items[id]["price"] = data["price"] + + return JSONResponse( + status_code=HTTPStatus.OK, + content=items[id], + ) + +@app.delete("/item/{id}") +def delete_item(id: int) -> JSONResponse: + if id not in items: + raise HTTPException( + status_code=HTTPStatus.NOT_FOUND, + detail="Item not found", + ) + + items[id]["deleted"] = True + return JSONResponse( + status_code=HTTPStatus.OK, + content=items[id], + ) + + +@app.post("/cart") +def create_cart() -> JSONResponse: + global next_cart_id + new_cart_id = next_cart_id + carts[new_cart_id] = {} + next_cart_id += 1 + return JSONResponse( + status_code=HTTPStatus.CREATED, + content={"id": new_cart_id}, + headers={"location": f"/cart/{new_cart_id}"}, + ) + + +@app.post("/cart/{cart_id}/add/{item_id}") +def add_item_to_cart(cart_id: int, item_id: int) -> JSONResponse: + if cart_id not in carts: + raise HTTPException( + status_code=HTTPStatus.NOT_FOUND, + detail="Cart not found", + ) + if item_id not in items or items[item_id]["deleted"]: + raise HTTPException( + status_code=HTTPStatus.NOT_FOUND, + detail="Item not found", + ) + if item_id in carts[cart_id]: + carts[cart_id][item_id] += 1 + else: + carts[cart_id][item_id] = 1 + + return JSONResponse( + status_code=HTTPStatus.OK, + content={"cart_id": cart_id, "item_id": item_id}, + ) + +@app.get("/cart/{id}") +def get_cart(id: int) -> JSONResponse: + if id not in carts: + raise HTTPException( + status_code=HTTPStatus.NOT_FOUND, + detail="Cart not found", + ) + + cart_items = [] + total_price = 0 + for item_id, quantity in carts[id].items(): + item = items[item_id] + cart_items.append( + { + "id": item_id, + "name": item["name"], + "quantity": quantity, + "available": not item["deleted"], + } + ) + total_price += item["price"] * quantity + + cart = { + "id": id, + "items": cart_items, + "price": total_price, + } + return JSONResponse( + status_code=HTTPStatus.OK, + content=cart, + ) + +@app.get("/cart") +def get_carts( + offset: Annotated[int, Query()] = 0, + limit: Annotated[int, Query()] = 10, + min_price: Annotated[float | None, Query()] = None, + max_price: Annotated[float | None, Query()] = None, + min_quantity: Annotated[int | None, Query()] = None, + max_quantity: Annotated[int | None, Query()] = None, +) -> JSONResponse: + if offset < 0: + raise HTTPException( + status_code=422, + detail="offset must be non-negative", + ) + if limit <= 0: + raise HTTPException( + status_code=422, + detail="limit must be positive", + ) + if min_price is not None and min_price < 0: + raise HTTPException( + status_code=422, + detail="min_price must be non-negative", + ) + if max_price is not None and max_price < 0: + raise HTTPException( + status_code=422, + detail="max_price must be non-negative", + ) + if min_quantity is not None and min_quantity < 0: + raise HTTPException( + status_code=422, + detail="min_quantity must be non-negative", + ) + if max_quantity is not None and max_quantity < 0: + raise HTTPException( + status_code=422, + detail="max_quantity must be non-negative", + ) + + result = [] + for cart_id in carts: + cart_items = [] + total_price = 0 + total_quantity = 0 + for item_id, quantity in carts[cart_id].items(): + item = items[item_id] + cart_items.append( + { + "id": item_id, + "name": item["name"], + "quantity": quantity, + "available": not item["deleted"], + } + ) + total_price += item["price"] * quantity + total_quantity += quantity + + if min_price is not None and total_price < min_price: + continue + if max_price is not None and total_price > max_price: + continue + if min_quantity is not None and total_quantity < min_quantity: + continue + if max_quantity is not None and total_quantity > max_quantity: + continue + result.append( + { + "id": cart_id, + "items": cart_items, + "price": total_price, + } + ) + + result = result[offset : offset + limit] + return JSONResponse( + status_code=HTTPStatus.OK, + content=result, + ) \ No newline at end of file