From 538417922c42c0185c4a4b5d7813615137402a7e Mon Sep 17 00:00:00 2001 From: marys Date: Fri, 2 Oct 2026 10:27:51 +0200 Subject: [PATCH] unknown changes --- broadcast/__init__.py | 0 broadcast/broadcast_client.py | 52 ++++++++ broadcast/broadcast_server.py | 32 +++++ broadcast/models.py | 19 +++ faststream_app.py | 49 ++++++-- faststream_app2.py | 44 +++++++ faststream_publisher.py | 19 ++- faststream_publisher_sync.py | 3 +- models/__init__.py | 0 models/test_result.py | 114 ++++++++++++++++++ .../test/fixtures/asyncapi_1.yaml | 2 + pyproject.toml | 5 +- uv.lock | 109 ++++++++++++++++- 13 files changed, 428 insertions(+), 20 deletions(-) create mode 100644 broadcast/__init__.py create mode 100644 broadcast/broadcast_client.py create mode 100644 broadcast/broadcast_server.py create mode 100644 broadcast/models.py create mode 100644 faststream_app2.py create mode 100644 models/__init__.py create mode 100644 models/test_result.py diff --git a/broadcast/__init__.py b/broadcast/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/broadcast/broadcast_client.py b/broadcast/broadcast_client.py new file mode 100644 index 0000000..cbb861a --- /dev/null +++ b/broadcast/broadcast_client.py @@ -0,0 +1,52 @@ +import asyncio +import os + +from faststream.nats import NatsBroker +from faststream.nats.message import NatsMessage + +from broadcast.models import ProbeRegister, ProbeHeartBeat, ProbeUnregister + +NATS_SERVERS = os.getenv('NATS_URL', 'nats://localhost:4222').split(',') +NATS_TOKEN = os.getenv('NATS_TOKEN', '') + +broker = NatsBroker(servers=NATS_SERVERS, token=NATS_TOKEN) + +async def main(): + msg_register = ProbeRegister( + command="register", + probe_id="prvni", + capabilities="capabilities", + probe_type="mtr" + ) + + msg_heart_beat = ProbeHeartBeat( + command="hartbeat", + probe_id="prvni", + status="OK" + ) + + msg_unregister = ProbeUnregister( + command="unregister", + probe_id="prvni", + ) + + await broker.connect() + #response = await broker.publish(msg.model_dump(), subject=f"discovery.probe") + + response: NatsMessage = await broker.request( + msg_register.model_dump(), + subject="discovery.probe", + timeout=3, + ) + print(f"{await response.decode()=}") + + await asyncio.sleep(5) + await broker.publish(msg_heart_beat.model_dump(), subject=f"discovery.probe") + + await asyncio.sleep(5) + await broker.publish(msg_unregister.model_dump(), subject=f"discovery.probe") + + await broker.stop() + +if __name__ == "__main__": + asyncio.run(main()) \ No newline at end of file diff --git a/broadcast/broadcast_server.py b/broadcast/broadcast_server.py new file mode 100644 index 0000000..a353805 --- /dev/null +++ b/broadcast/broadcast_server.py @@ -0,0 +1,32 @@ +import asyncio +import os +from enum import Enum + +from typing import Any + +from pydantic import BaseModel, Field +from faststream import FastStream +from faststream.nats import NatsBroker + +from models import ProbeRegister, ProbeUnregister, ProbeHeartBeat + +NATS_SERVERS = os.getenv('NATS_URL', 'nats://localhost:4222').split(',') +NATS_TOKEN = os.getenv('NATS_TOKEN', '') + +broker = NatsBroker(servers=NATS_SERVERS, token=NATS_TOKEN) +app = FastStream(broker) + + + +@broker.subscriber(f"discovery.probe") +async def probe_discovery(data: ProbeRegister | ProbeHeartBeat | ProbeUnregister): + print(20*'-') + print(type(data), "->", data) + return True + +async def main(): + print("START") + await app.run() + +if __name__ == "__main__": + asyncio.run(main()) \ No newline at end of file diff --git a/broadcast/models.py b/broadcast/models.py new file mode 100644 index 0000000..8213470 --- /dev/null +++ b/broadcast/models.py @@ -0,0 +1,19 @@ +from pydantic import BaseModel + +class Probe(BaseModel): + command: str + probe_id: str + +class ProbeRegister(Probe): + capabilities: str + probe_type: str + +class ProbeHeartBeat(Probe): + status: str + +class ProbeUnregister(Probe): + pass + +class ProbeBroadcast(BaseModel): + command: str + probe_type: str diff --git a/faststream_app.py b/faststream_app.py index 44eca65..dbdfa57 100644 --- a/faststream_app.py +++ b/faststream_app.py @@ -1,13 +1,15 @@ -# python fastsream_publisher.py + import asyncio import os -import sys +from enum import Enum + +from typing import Any from pydantic import BaseModel, Field from faststream import FastStream from faststream.nats import NatsBroker -SUBJECT="jobs" +SUBJECT="mtr_client.discovery" NATS_SERVERS = os.getenv('NATS_URL', 'nats://localhost:4222').split(',') NATS_TOKEN = os.getenv('NATS_TOKEN', '') @@ -24,14 +26,39 @@ class JobResponse(BaseModel): job_id: str = Field(..., description="Job identifier") status: str = Field(..., description="Job status") -@broker.subscriber(f"{SUBJECT}") -async def handle_job(event: JobCreated): - print(f"{SUBJECT} received job_id={event.job_id} name={event.name}") - print(f"{event.__dict__=}") - response_msg = JobCreated(job_id=event.job_id, name="created1").model_dump() - print(f"{response_msg=}") - print("===", await broker.publish(response_msg, subject=f"{SUBJECT}.response")) - return f"Hello {event.name}" +class ProbeDiscover(BaseModel): + name: str = Field(..., description="Probe identifier") + type: str = Field(..., description="Probe name") + +class ProbeCommandTypeEnum(Enum): + ADD_PROBE = "add probe" + REMOVE_PROBE = "remove probe" + +class ProbeTypeEnum(Enum): + OTHER = 'other' + TAS_SERVER = 'tas server' + +class DiscoverApiResponseModel(BaseModel): + probe_type: ProbeTypeEnum + command: ProbeCommandTypeEnum + name: str + + +@broker.subscriber("test_topic.request") +async def handle_job(event: Any): + print(f"{SUBJECT}.broadcast received job_id={event}") + + #response_msg = JobCreated(job_id=event.job_id, name="created1").model_dump() + print(f"{event=}") + print(f"{ProbeTypeEnum.TAS_SERVER=}") + #response_msg = DiscoverApiResponseModel(name="TAS_ZAG", probe_type=ProbeTypeEnum.TAS_SERVER.value, command=ProbeCommandTypeEnum.REMOVE_NODE.value).model_dump() + response_msg = DiscoverApiResponseModel(name="TAS_BUD", probe_type=ProbeTypeEnum.TAS_SERVER, command=ProbeCommandTypeEnum.ADD_PROBE).model_dump() + print(response_msg) + #print(f"{response_msg=}") + #response_msg = {'name': 'TAS_ZAG', 'probe_type': 'tas server', 'command': 'add node'} + print("===", await broker.publish(response_msg, subject=f"test_topic.response")) + #print("===", await broker.publish("neco", subject="mtr")) + return f"Hello" async def main(): await app.run() diff --git a/faststream_app2.py b/faststream_app2.py new file mode 100644 index 0000000..d3af469 --- /dev/null +++ b/faststream_app2.py @@ -0,0 +1,44 @@ +# python fastsream_publisher.py +import asyncio +import os +import sys +import uuid +from typing import Any + +from pydantic import BaseModel, Field +from faststream import FastStream +from faststream.nats import NatsBroker + +#SUBJECT="mtr_test.request" +SUBJECT="mtr_client.discover" + +NATS_SERVERS = os.getenv('NATS_URL', 'nats://localhost:4222').split(',') +NATS_TOKEN = os.getenv('NATS_TOKEN', '') + +broker = NatsBroker(servers=NATS_SERVERS, token=NATS_TOKEN) +app = FastStream(broker) + +class JobCreated(BaseModel): + job_id: str = Field(..., description="Job identifier") + name: str = Field(..., description="Job name") + + +class JobResponse(BaseModel): + job_id: str = Field(..., description="Job identifier") + status: str = Field(..., description="Job status") + +@broker.subscriber(f"{SUBJECT}.response") +async def handle_job(event: Any): + #print(f"{SUBJECT} received job_id={event.job_id} name={event.name}") + print(f"{event=}") + # result = uuid.uuid4() + # await asyncio.sleep(1) + # print(f"{result=}") + # return result + +async def main(): + await app.run() + +if __name__ == "__main__": + #SUBJECT=sys.argv[1] + asyncio.run(main()) \ No newline at end of file diff --git a/faststream_publisher.py b/faststream_publisher.py index 9135b21..379e284 100644 --- a/faststream_publisher.py +++ b/faststream_publisher.py @@ -2,6 +2,7 @@ import asyncio import os +from models.test_result import TestResult from faststream.specification.asyncapi.v3_0_0.schema import servers from pydantic import BaseModel, Field @@ -23,13 +24,25 @@ class JobResponse(BaseModel): status: str = Field(..., description="Job status") async def main(): + print("START") await broker.connect() + print("CONNECTED") + result = TestResult( + to_server="localhost", + test_parameters_id=5) + + + print("ted to bude") await broker.publish( - JobCreated(job_id="123", name="build-image").model_dump(), - subject="jobs", + #message=JobCreated(job_id="123", name="build-image", subject="jobs.created").model_dump(), + #message=["text2", 'tyext3', ], + #message=str("text"), + message=result.model_dump(), + #subject="jobs", + subject="test_topic", ) - await broker.close() + await broker.stop() asyncio.run(main()) diff --git a/faststream_publisher_sync.py b/faststream_publisher_sync.py index c48cdf3..74b21e4 100644 --- a/faststream_publisher_sync.py +++ b/faststream_publisher_sync.py @@ -28,7 +28,8 @@ async def main(): async with broker: response: NatsMessage = await broker.request( JobCreated(job_id="123", name="build-image").model_dump(), - subject="jobs", + #"text2", + subject="test_topic", timeout=3, ) print(f"{await response.decode()=}") diff --git a/models/__init__.py b/models/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/models/test_result.py b/models/test_result.py new file mode 100644 index 0000000..20a2484 --- /dev/null +++ b/models/test_result.py @@ -0,0 +1,114 @@ +# coding: utf-8 + +""" + MTR testing API + + API for managing MTR tests and additional nodes. It is part of spirent-service. + + The version of the OpenAPI document: 1.0.0 + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +from __future__ import annotations +import pprint +import re # noqa: F401 +import json + + + + +from pydantic import BaseModel, ConfigDict, StrictFloat, StrictInt, StrictStr +from typing import Any, ClassVar, Dict, List, Optional, Union +try: + from typing import Self +except ImportError: + from typing_extensions import Self + +class TestResult(BaseModel): + """ + TestResult + """ # noqa: E501 + #from_tas: StrictStr + to_server: StrictStr + test_parameters_id: Optional[StrictInt] = None + to_server_hostname: Optional[StrictStr] = None + ttl: Optional[StrictInt] = None + host: Optional[List[StrictStr]] = None + loos: Optional[StrictInt] = None + sent: Optional[StrictInt] = None + average_time: Optional[Union[StrictFloat, StrictInt]] = None + best_time: Optional[Union[StrictFloat, StrictInt]] = None + worst_time: Optional[Union[StrictFloat, StrictInt]] = None + standard_deviation: Optional[Union[StrictFloat, StrictInt]] = None + worst_jitter: Optional[Union[StrictFloat, StrictInt]] = None + __properties: ClassVar[List[str]] = ["from_tas", "to_server", "test_parameters_id", "to_server_hostname", "ttl", "host", "loos", "sent", "average_time", "best_time", "worst_time", "standard_deviation", "worst_jitter"] + + model_config = { + "populate_by_name": True, + "validate_assignment": True, + "protected_namespaces": (), + } + + + def to_str(self) -> str: + """Returns the string representation of the model using alias""" + return pprint.pformat(self.model_dump(by_alias=True)) + + def to_json(self) -> str: + """Returns the JSON representation of the model using alias""" + # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead + return json.dumps(self.to_dict()) + + @classmethod + def from_json(cls, json_str: str) -> Self: + """Create an instance of TestResult from a JSON string""" + return cls.from_dict(json.loads(json_str)) + + def to_dict(self) -> Dict[str, Any]: + """Return the dictionary representation of the model using alias. + + This has the following differences from calling pydantic's + `self.model_dump(by_alias=True)`: + + * `None` is only added to the output dict for nullable fields that + were set at model initialization. Other fields with value `None` + are ignored. + """ + _dict = self.model_dump( + by_alias=True, + exclude={ + }, + exclude_none=True, + ) + return _dict + + @classmethod + def from_dict(cls, obj: Dict) -> Self: + """Create an instance of TestResult from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate({ + "from_tas": obj.get("from_tas"), + "to_server": obj.get("to_server"), + "test_parameters_id": obj.get("test_parameters_id"), + "to_server_hostname": obj.get("to_server_hostname"), + "ttl": obj.get("ttl"), + "host": obj.get("host"), + "loos": obj.get("loos"), + "sent": obj.get("sent"), + "average_time": obj.get("average_time"), + "best_time": obj.get("best_time"), + "worst_time": obj.get("worst_time"), + "standard_deviation": obj.get("standard_deviation"), + "worst_jitter": obj.get("worst_jitter") + }) + return _obj + + diff --git a/openapi_templete/test/fixtures/asyncapi_1.yaml b/openapi_templete/test/fixtures/asyncapi_1.yaml index 06eeac0..2c47386 100644 --- a/openapi_templete/test/fixtures/asyncapi_1.yaml +++ b/openapi_templete/test/fixtures/asyncapi_1.yaml @@ -106,6 +106,7 @@ components: type: array items: type: object + title: Items required: - productId - quantity @@ -122,3 +123,4 @@ components: totalAmount: type: number format: double + diff --git a/pyproject.toml b/pyproject.toml index fdee19a..40cfec0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,9 +3,12 @@ name = "nats-python" version = "0.1.0" requires-python = ">=3.13" dependencies = [ - "faststream[nats]>=0.6.7", + "fastapi>=0.138.0", + "faststream[nats]>=0.7.1", + "js>=1.0", "nats-py>=2.14.0", "pydantic>=2.13.4", + "uvicorn>=0.49.0", ] [dependency-groups] diff --git a/uv.lock b/uv.lock index d57dfcb..fd70366 100644 --- a/uv.lock +++ b/uv.lock @@ -247,6 +247,20 @@ http = [ { name = "httpx" }, ] +[[package]] +name = "fanstatic" +version = "1.7" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, + { name = "setuptools" }, + { name = "webob" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/38/c4/a1e1c04420c8d793d155eb4b7d0f857432e01c435d4fbb3168488414a38b/fanstatic-1.7.tar.gz", hash = "sha256:881f0a26f18f79ff658d037b9462273abd86bd8680ba7d77f7aa7361787f9f43", size = 83137 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5f/e3/bc7898f9413fe43d043a26dd41f47d14c08aade02a32fbf3d77f0938a074/fanstatic-1.7-py3-none-any.whl", hash = "sha256:a98ef5a429505160dec47ea23904c79c9836799a641daba26035b4886321c16e", size = 60005 }, +] + [[package]] name = "fast-depends" version = "3.0.8" @@ -265,18 +279,34 @@ pydantic = [ { name = "pydantic" }, ] +[[package]] +name = "fastapi" +version = "0.138.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-doc" }, + { name = "pydantic" }, + { name = "starlette" }, + { name = "typing-extensions" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5b/58/ff455d9fe47c60abadb34b9e05a304b1f05f5ab8000ac01565156b6f5e43/fastapi-0.138.0.tar.gz", hash = "sha256:d445a4877636ad191e7053e08c9bf98cb921a6756776848400bb773d1740c061", size = 419240 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6c/ff/8496d9847a5fedae775eb49460722d3efaa80487854273e9647ae876218c/fastapi-0.138.0-py3-none-any.whl", hash = "sha256:b6f54fd1bd72c80b0f899f172c61a600f6f7af9b43d4d772a018f35624048cb0", size = 126779 }, +] + [[package]] name = "faststream" -version = "0.6.7" +version = "0.7.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, { name = "fast-depends", extra = ["pydantic"] }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/19/7b/d02c069be0bc671b2eb8f805a1f824d2bfbe1852c9c3f4ad719a7ad3710b/faststream-0.6.7.tar.gz", hash = "sha256:c732eaf861c4cbddd9c7f9098608486a9f05dff67a72335686c3044039045346", size = 306185 } +sdist = { url = "https://files.pythonhosted.org/packages/5a/92/7f5edc7e1945968331c185ee197b690b413da861649d5859e3f377348acd/faststream-0.7.1.tar.gz", hash = "sha256:11816dd4ca678f6b173159c456619993b09684b684abe4010366d6a0c8059c58", size = 329453 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ba/23/9d51f352fbb656f5345030f57e20737b1c88167f0eac354ac548d577808b/faststream-0.6.7-py3-none-any.whl", hash = "sha256:a904a4b1e3babeaa244a9460821f5b05dd71b00c959c816360b2acbbe267cd5c", size = 513454 }, + { url = "https://files.pythonhosted.org/packages/12/2e/73d58856a305a73ac31d3d950f9b96a2ef4c1a6071e38b339d1b0b466418/faststream-0.7.1-py3-none-any.whl", hash = "sha256:d4f971f6ba7621a05a67a8fcb4436fdcf89b5f21b33eb107f193b1c9553738a0", size = 556454 }, ] [package.optional-dependencies] @@ -373,6 +403,25 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899 }, ] +[[package]] +name = "js" +version = "1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "fanstatic" }, + { name = "setuptools" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c0/ec/93bb7175ffcfb86eb9d46ae25fa6097b2e853caa362e3e38de8ab4e5eda1/js-1.0.tar.gz", hash = "sha256:9bade58e82ec88443ad9dd375674ef0d9597dfa6c773897e9019ebedc54d1f00", size = 2523 } + +[[package]] +name = "legacy-cgi" +version = "2.6.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f4/9c/91c7d2c5ebbdf0a1a510bfa0ddeaa2fbb5b78677df5ac0a0aa51cf7125b0/legacy_cgi-2.6.4.tar.gz", hash = "sha256:abb9dfc7835772f7c9317977c63253fd22a7484b5c9bbcdca60a29dcce97c577", size = 24603 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8c/7e/e7394eeb49a41cc514b3eb49020223666cbf40d86f5721c2f07871e6d84a/legacy_cgi-2.6.4-py3-none-any.whl", hash = "sha256:7e235ce58bf1e25d1fc9b2d299015e4e2cd37305eccafec1e6bac3fc04b878cd", size = 20035 }, +] + [[package]] name = "markdown-it-py" version = "4.2.0" @@ -478,9 +527,12 @@ name = "nats-python" version = "0.1.0" source = { virtual = "." } dependencies = [ + { name = "fastapi" }, { name = "faststream", extra = ["nats"] }, + { name = "js" }, { name = "nats-py" }, { name = "pydantic" }, + { name = "uvicorn" }, ] [package.dev-dependencies] @@ -491,9 +543,12 @@ dev = [ [package.metadata] requires-dist = [ - { name = "faststream", extras = ["nats"], specifier = ">=0.6.7" }, + { name = "fastapi", specifier = ">=0.138.0" }, + { name = "faststream", extras = ["nats"], specifier = ">=0.7.1" }, + { name = "js", specifier = ">=1.0" }, { name = "nats-py", specifier = ">=2.14.0" }, { name = "pydantic", specifier = ">=2.13.4" }, + { name = "uvicorn", specifier = ">=0.49.0" }, ] [package.metadata.requires-dev] @@ -730,6 +785,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl", hash = "sha256:33bd4ef74232fb73fe9279a257718407f169c09b78a87ad3d296f548e27de0bb", size = 310654 }, ] +[[package]] +name = "setuptools" +version = "82.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4f/db/cfac1baf10650ab4d1c111714410d2fbb77ac5a616db26775db562c8fab2/setuptools-82.0.1.tar.gz", hash = "sha256:7d872682c5d01cfde07da7bccc7b65469d3dca203318515ada1de5eda35efbf9", size = 1152316 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9d/76/f789f7a86709c6b087c5a2f52f911838cad707cc613162401badc665acfe/setuptools-82.0.1-py3-none-any.whl", hash = "sha256:a59e362652f08dcd477c78bb6e7bd9d80a7995bc73ce773050228a348ce2e5bb", size = 1006223 }, +] + [[package]] name = "shellingham" version = "1.5.4" @@ -748,6 +812,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050 }, ] +[[package]] +name = "starlette" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/e3/7c1dc7381d9f8ab7d854328ebfa884e62cb3f3d8549ddfd37c7814f42afa/starlette-1.3.1.tar.gz", hash = "sha256:05d0213193f2fbaae60e2ecb593b4add4262ad4e46536b54abe36f11a71724e0", size = 2703240 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl", hash = "sha256:c7372aae11c3c3f26a42df7bd626cec2f47d03483d261d369516a615a53714c6", size = 73632 }, +] + [[package]] name = "text-unidecode" version = "1.3" @@ -822,3 +898,28 @@ sdist = { url = "https://files.pythonhosted.org/packages/53/0c/06f8b233b8fd13b9e wheels = [ { url = "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897", size = 131087 }, ] + +[[package]] +name = "uvicorn" +version = "0.49.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c4/1f/fa18009dea8469069cca78a4e877a008ab78f08b064bfc9ab891579077ff/uvicorn-0.49.0.tar.gz", hash = "sha256:ebf4271aa580d9de97f93192d4595176df6e91f9aae919ca73e4fc07df1e66a3", size = 91284 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/fa/e1388bbcf24ef3274f45c0c1c7b501fd14971037c1b6ee23610553307497/uvicorn-0.49.0-py3-none-any.whl", hash = "sha256:ba3d14c3ee7e41c6c654c46c9eb489d33213cdd30aa1696eab1374337c13f68f", size = 71376 }, +] + +[[package]] +name = "webob" +version = "1.8.10" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "legacy-cgi" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/58/f9/974eafebfd0bd442b8848899fe7d30675c93f750c313e1a6fe61acbde1e3/webob-1.8.10.tar.gz", hash = "sha256:1c963a11f307bc3f624fbab9dde737701eae255f32981b7a5486a88db1767c2b", size = 280796 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/83/21/fce134877fb6fc6ad3c464e4a07ede0ee9219f705d26a981ae58ea36ca13/webob-1.8.10-py2.py3-none-any.whl", hash = "sha256:e68ad87fda378191081965ab02a185391c26e4e926adec855c3b0286a8369d49", size = 115825 }, +]