From 0d56ef114834ed558bd218c8d2e9db55799529ad Mon Sep 17 00:00:00 2001 From: Pastukhov Nikita Date: Thu, 12 Sep 2024 20:50:55 +0300 Subject: [PATCH 1/2] feat: add explicit CLI import error (#1785) * feat: add explicit CLI import error * Proofread error msg --------- Co-authored-by: Kumaran Rajendhiran --- faststream/__main__.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/faststream/__main__.py b/faststream/__main__.py index 0778ba8f36..04378c618e 100644 --- a/faststream/__main__.py +++ b/faststream/__main__.py @@ -2,7 +2,20 @@ import warnings -from faststream.cli.main import cli +try: + from faststream.cli.main import cli +except ImportError: + has_typer = False +else: + has_typer = True + +if not has_typer: + raise ImportError( + "\n\nYou're trying to use the FastStream CLI, " + "\nbut you haven't installed the required dependencies." + "\nPlease install them using the following command: " + '\npip install "faststream[cli]"' + ) warnings.filterwarnings("default", category=ImportWarning, module="faststream") From 6a06a383d6dee922e28b76eed04dbda9e2b30856 Mon Sep 17 00:00:00 2001 From: Pastukhov Nikita Date: Thu, 12 Sep 2024 21:49:27 +0300 Subject: [PATCH 2/2] fix (#1780): replace / in generated json refs (#1786) Co-authored-by: Kumaran Rajendhiran --- faststream/asyncapi/generate.py | 8 +++- tests/asyncapi/base/arguments.py | 64 +++++++++++++++----------------- 2 files changed, 37 insertions(+), 35 deletions(-) diff --git a/faststream/asyncapi/generate.py b/faststream/asyncapi/generate.py index daec95ec00..a713e2d0ff 100644 --- a/faststream/asyncapi/generate.py +++ b/faststream/asyncapi/generate.py @@ -155,14 +155,18 @@ def _resolve_msg_payloads( one_of = m.payload.get("oneOf") if isinstance(one_of, dict): for p_title, p in one_of.items(): + p_title = p_title.replace("/", ".") payloads.update(p.pop(DEF_KEY, {})) if p_title not in payloads: payloads[p_title] = p one_of_list.append(Reference(**{"$ref": f"#/components/schemas/{p_title}"})) elif one_of is not None: + # Descriminator case for p in one_of: - p_title = next(iter(p.values())).split("/")[-1] + p_value = next(iter(p.values())) + p_title = p_value.split("/")[-1] + p_title = p_title.replace("/", ".") if p_title not in payloads: payloads[p_title] = p one_of_list.append(Reference(**{"$ref": f"#/components/schemas/{p_title}"})) @@ -170,6 +174,7 @@ def _resolve_msg_payloads( if not one_of_list: payloads.update(m.payload.pop(DEF_KEY, {})) p_title = m.payload.get("title", f"{channel_name}Payload") + p_title = p_title.replace("/", ".") if p_title not in payloads: payloads[p_title] = m.payload m.payload = {"$ref": f"#/components/schemas/{p_title}"} @@ -178,6 +183,7 @@ def _resolve_msg_payloads( m.payload["oneOf"] = one_of_list assert m.title # nosec B101 + m.title = m.title.replace("/", ".") messages[m.title] = m return Reference(**{"$ref": f"#/components/messages/{m.title}"}) diff --git a/tests/asyncapi/base/arguments.py b/tests/asyncapi/base/arguments.py index 4d5597f232..8c670b2d49 100644 --- a/tests/asyncapi/base/arguments.py +++ b/tests/asyncapi/base/arguments.py @@ -547,6 +547,36 @@ async def handle(user: Model): ... }, }, schema["components"] + def test_with_filter(self): + class User(pydantic.BaseModel): + name: str = "" + id: int + + broker = self.broker_class() + + sub = broker.subscriber("test/one") + + @sub( + filter=lambda m: m.content_type == "application/json", + ) + async def handle(id: int): ... + + @sub + async def handle_default(msg): ... + + schema = get_app_schema(self.build_app(broker)).to_jsonable() + + name, message = next(iter(schema["components"]["messages"].items())) + + assert name == IsStr(regex=r"test.one[\w:]*:Handle:Message"), name + + assert len(message["payload"]["oneOf"]) == 2 + + payload = schema["components"]["schemas"] + + assert "Handle:Message:Payload" in list(payload.keys()) + assert "HandleDefault:Message:Payload" in list(payload.keys()) + class ArgumentsTestcase(FastAPICompatible): dependency_builder = staticmethod(Depends) @@ -616,37 +646,3 @@ async def handle(id: int, user: Optional[str] = None, message=Context()): ... "type": "object", } ) - - def test_with_filter(self): - # TODO: move it to FastAPICompatible with FastAPI refactore - class User(pydantic.BaseModel): - name: str = "" - id: int - - broker = self.broker_class() - - sub = broker.subscriber("test") - - @sub( - filter=lambda m: m.content_type == "application/json", - ) - async def handle(id: int): ... - - @sub - async def handle_default(msg): ... - - schema = get_app_schema(self.build_app(broker)).to_jsonable() - - assert ( - len( - next(iter(schema["components"]["messages"].values()))["payload"][ - "oneOf" - ] - ) - == 2 - ) - - payload = schema["components"]["schemas"] - - assert "Handle:Message:Payload" in list(payload.keys()) - assert "HandleDefault:Message:Payload" in list(payload.keys())