fix: adapt to faststream 0.7.6, and make the AsyncAPI document non-blank - #85
Merged
Merged
Conversation
0.7.6 removed the try_it_out registry hook, made SubscriberSpec/PublisherSpec carry an address, made channel_labels abstract, narrowed dependencies to Sequence, and dropped add_task's return value. Registration is now declarative and the channel key comes from the base, so title_ names the channel too.
Upstream collects channels only for brokers that reach its broker_servers mapping, which it fills inside `for url in specification.url`. TimersBroker passed url=[], so the whole document rendered blank while every per-endpoint get_schema() stayed correct. The url is rebuilt from the pool's connection parameters, never the caller's DSN, so no credential reaches the document.
lesnik512
force-pushed
the
fix/faststream-0-7-6
branch
from
September 20, 2026 11:46
cb0ec8f to
7435bfb
Compare
This was referenced Sep 20, 2026
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
FastStream 0.7.6 released today and broke this package five ways at once.
uv.lockis gitignored, so CI resolves fresh on every run: lint and all six pytest jobs on #83 are red on this right now.A sixth fix is folded in: the assembled AsyncAPI document was blank, and has been since long before 0.7.6.
The five 0.7.6 changes
1.
try_it_out._get_broker_registryis gone.__init__.pymonkeypatched it inside a baretry/except Exception: pass, so the failure was silent — the AsyncAPI "try it out" page just stopped knowing aboutTimersBroker. 0.7.6 replaces it with a declarative hook, so the 20-line block and its imports are deleted and the class statement carriesbroker=TimersBroker.2.
SubscriberSpecandPublisherSpecnow requireaddress. The channel key istopic:Handle/topic:Publisher, which names nothing subscribable;addressis the field a reader can act on. Both get the prefixed topic, since a broker-prefixed deployment addressed by the bare topic points at a topic nothing reads.3.
SubscriberSpecification.channel_labelsis abstract.TimersSubscriberSpecificationcould not be instantiated at all. Thenameoverride is replaced bychannel_labels, and the base's_channel_keybuilds the key.4.
dependenciesnarrowed fromIterable[Dependant]toSequence[Dependant]inbroker.py,router.pyandregistrator.py.5.
TasksMixin.add_taskno longer returns the task. The only change upstream was dropping thereturn taskline — the supervisor andrestart_on_failurebehaviour are byte-identical — butsubscriber/usecase.pydidawait consume_taskon the result, so a timed-out start raisedTypeError: 'NoneType' object can't be awaitedinstead of cancelling its poll task. Now readsself.tasks[-1], whichstop()has not cleared yet at that point.6. The AsyncAPI document was blank, and predates all of this
AsyncAPI(broker).to_specification()returned no servers, no channels and no operations for aTimersBroker. I reproduced it onmainagainst faststream 0.7.5 before concluding anything, so it is not from the 0.7.6 work.Upstream collects channels only for brokers that reach its
broker_serversmapping, and it fills that mapping inside:TimersBrokerpassedurl=[], so it never entered the mapping andget_broker_channelswas never called for it. Every per-endpointget_schema()stayed correct throughout, which is exactly why specification-level tests could not see it — and why the fix in items 2 and 3 above would otherwise have shipped into a document nobody could read.The URL is now derived from the client, and rebuilt from the pool's connection parameters rather than the caller's DSN. The document is published — FastStream serves it from the ASGI app — so echoing back a
Redis.from_url("redis://user:secret@...")would publish the password. Username and password are never read, so there is nothing to mask.Before / after, same broker:
built from
Redis.from_url("redis://user:secret@cache.example:6399/3"), with"secret" in json.dumps(spec)returningFalse.One behaviour change worth noticing
Handing the channel key to the base means
title_now names the channel, not just the operation. The oldnameoverride ignoredtitle_entirely. This matches the publisher and every built-in broker, and it changes the generated key for any subscriber declared withtitle_. Covered bytest_subscriber_title_names_the_channel_not_only_the_operation.Floor, and the cap from #84
#84 capped
faststream<0.7.6to unblock CI, with "lift once this adapts" on the line. It adapts now, so that cap is replaced by a floor offaststream>=0.7.6,<0.8. Items 1–3 use APIs that do not exist below it. The old>=0.7.1did still import cleanly today — I checked before changing it — but it becomes a lie the moment this lands, and nothing in CI resolves at the lower bound to catch that.Tests
Written first, red before each change:
The two pre-existing
test_isolation.pyfailures cover item 5 and are green again.Two notes on test quality, since both let real defects read as passing:
"my-topic" in nameandassert schema, which is why a specification naming an unaddressable channel looked fine.test_specification_url_shapescovers the unix-socket and clientless branches explicitly. The coverage gate was already satisfied for them by aMagicMockclient —mock.connection_pool.connection_kwargs.get("path")is truthy, so it walked into the socket branch by accident. 100% line coverage was not evidence that branch worked.Verification
just lint-ciclean (eof-fixer,ruff format,ruff check,ty). Full suite against Redis 8: 167 passed, 100% coverage.Separately, not addressed here
Under
TestTimersBroker, a publisher declared on a prefixed router gets a spurious extra fake subscriber:create_publisher_fake_subscribermatches onfull_topicbut falls back tobroker.subscriber(publisher.config.topic), which re-registers the unprefixed topic. It shows up as a strayreminders:PublisherResponseSubscriberchannel alongside the correctapp:reminders:*ones. Test-broker path only, unrelated to 0.7.6, and out of scope here.