refactor(connection): remove RedisConnectionFactory.connect and the url= keyword - #728
Draft
vishal-bala wants to merge 2 commits into
Conversation
…url keyword connect() was a thin dispatcher over get_redis_connection and get_async_redis_connection, deprecated since v0.4.0, with no callers left anywhere in the library. The url keyword on the two async factories was deprecated in v0.11.0 in favour of redis_url. url is not simply dropped. Left unguarded it reaches is_cluster_url, which takes url positionally, so a caller would get "got multiple values for argument 'url'" — an error naming neither RedisVL nor the rename — or a REDIS_URL ValueError if that variable happened to be unset. All three factories now name the replacement instead. The removed-keyword table splits in two along entry points rather than gaining a fourth shared entry. url belongs to the connection factories and connection_args to the index constructors, and a single table would have told a factory caller that connection_args had been withdrawn when that door never accepted it. TestConnect loses the two tests that only asserted the dispatcher returned a sync or async client, which every fixture in the suite already does. Its three URL-resolution error paths survive on get_redis_connection and are covered nowhere else, so they move rather than go. The module-level filterwarnings that masked connect()'s own warning goes too; its comment already said to remove it with the method. test_url_deprecation.py goes with the keyword. Two of its four tests were degenerate — both asserted pytest.warns and passed on the unrelated "will become async" warning rather than on anything about url. The one property worth keeping, that the main async factory is warning-free on the modern spelling, moves next to the other tests for those factories. It is load-bearing: the cache builds its async client through that factory specifically to avoid warning users about an API they never called.
Six review perspectives ran against the removal. The substantive findings: The keyword guard covered three of five factory entry points. get_redis_cluster_connection and get_async_redis_cluster_connection never got it, so url= there still produced "got multiple values for argument 'url'" — the exact error the guard exists to replace, reaching the users most likely to be calling a factory by hand. All five are guarded now. get_async_redis_connection warned before validating, so a call about to be rejected still emitted advisory noise, and the warning would have become the surfaced error under -W error. It now validates first, and carries stacklevel so the warning points at the caller rather than at this module. Its text said the function "will become async", which describes the wrong thing: the substantive difference from _get_aredis_connection is that this is the one factory that never sends CLIENT SETINFO, so its client reports no library name and defers its first connection. The docstring says that, and says the function is not being removed and has no replacement to migrate to, rather than pointing users at a private sibling. owns_client made a latent path reachable. disconnect() nulls an owned client and the lazy accessor re-creates one, but a handed-over client leaves no redis_url to rebuild from, so it fell through to REDIS_URL and could silently connect to a different server than the caller supplied. Both accessors now refuse, naming the reason. The no-argument constructor still resolves from the environment, which is a documented path. get_redis_connection documented a url parameter its signature does not have and that this branch made fatal, and all three factories still told readers in Raises to pass it. The two tables also lost their leading underscore in the split, publishing module-level names that feed a private helper; both are private again, and the comment now says which door each table serves so a future entry lands in the right one. Tests: the "will become async" notice was asserted nowhere after the url-deprecation file went, so the warn() could have been deleted with the suite still green. The rejection test now covers all five guards rather than two, and pins that a url containing a password is not echoed into the message. test_missing_env_var restored REDIS_URL outside a finally, so a failed assertion would have left it unset and cascaded into every later test that resolves its URL from the environment; monkeypatch handles it.
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.
Motivation
RedisConnectionFactory.connect()was a thin dispatcher overget_redis_connectionandget_async_redis_connection, deprecated since v0.4.0, with no callers left anywhere in the library. Theurlkeyword on the two async factories was deprecated in v0.11.0 in favour ofredis_url.This is the third and last of three stacked pull requests removing the deprecated client and connection surface. With it, a Redis client reaches an index through exactly one route: the constructor, either as
redis_clientor asredis_url.Changes
urlis rejected, not merely droppedLeft unguarded,
url=would reachis_cluster_url, which takesurlpositionally, and raisegot multiple values for argument 'url'— an error naming neither RedisVL nor the rename. IfREDIS_URLhappened to be unset, aValueErrorabout that variable would arrive first instead. All five factory entry points now name the replacement.That count matters: the two cluster factories,
get_redis_cluster_connectionandget_async_redis_cluster_connection, had never carried the deprecated decorator but acceptedurlby the same keyword-forwarding accident, so guarding only the decorated ones would have left the obscure failure reachable through exactly the entry points a cluster user is most likely to call by hand.The removed-keyword table splits in two along entry points rather than gaining a fourth shared entry.
urlbelongs to the connection factories andconnection_argsto the index constructors, and one shared table would have told a factory caller thatconnection_argshad been withdrawn when that door never accepted it.get_async_redis_connectionnow tells the truth about itselfIt survives, but three things about it were wrong. It warned before validating, so a call about to be rejected still emitted advisory noise — and under
-W errorthe warning, not the helpfulTypeError, would have been the surfaced error. Its warning had nostacklevel, so it pointed at this module rather than at the caller. And its text said the function "will become async", which describes the wrong difference: what actually distinguishes it from_get_aredis_connectionis that it is the one factory that never sendsCLIENT SETINFO, so its client reports no library name and defers its first connection to the first command.The docstring now says that, and says plainly that the function is not being removed and has no replacement to migrate to, rather than pointing users at a private sibling.
A latent reconnection path, opened by
owns_clientdisconnect()nulls an owned client and the lazy accessor then re-creates one. For a client handed over withowns_client=Truethere is noredis_urlto rebuild from, so creation fell through toREDIS_URLand could silently connect to a different server than the caller supplied. Both accessors now refuse, naming the reason. The no-argument constructor still resolves from the environment, which is a documented path.This was unreachable before the first branch in this stack, because
redis_client=implied not-owned anddisconnect()returned early without nulling anything.Documentation that contradicted the code
get_redis_connectiondocumented a parameter namedurlthat its signature does not have and that this change makes fatal, and all three factories told readers inRaises:to pass it. None documented the newTypeError. The two tables also lost their leading underscore when the table split, publishing module-level names that feed a private helper.Notes
The
urlkeyword had a sharper consequence than an unhelpful error, and it is worth recording because it is now unreachable._get_aredis_connectionpoppedurland gave it precedence overredis_url, andAsyncSearchIndexforwardsconnection_kwargsverbatim into that factory. SoAsyncSearchIndex(redis_url="redis://intended", connection_kwargs={"url": "redis://elsewhere"})connected to the second address — connection-target confusion through a keyword the caller believed was deprecated and inert. The sync path already failed loudly, so this was async-only.get_async_redis_connection's signature-change notice was asserted nowhere after the url-deprecation tests were deleted; that file's only load-bearing assertion was the warning, despite its name suggesting otherwise. It is pinned again, so the warning cannot be deleted or reworded with the suite still green.Of the five tests removed here, two only asserted that the deleted dispatcher returned a sync or an async client, which every fixture in the suite already does. The three URL-resolution error paths it covered survive on
get_redis_connectionand are covered nowhere else, so they moved rather than went. One of them restoredREDIS_URLoutside afinally, so a failed assertion would have left the variable unset and cascaded into every later test that resolves its URL from the environment.Whether
get_async_redis_connectionshould become a coroutine, which is what its warning has been promising, is now a small and well-scoped decision: it has zero callers inside the library, every remaining reference is a test, and the async implementation already exists as_get_aredis_connection.The RESP2 pin these factories apply is unchanged and remains correct: RESP3 changes
FT.SEARCHandFT.AGGREGATEfrom an array to a map, which is the shape RedisVL parses. Worth knowing what it costs, though, sincesetdefaultleavesprotocol=3available to callers who want it: client-side caching and Smart Client Handoffs both require RESP3, so a user on Redis Cloud takes full disconnections during planned maintenance that a RESP3 client would ride through.Release Notes
RedisConnectionFactory.connect()is removed. Useget_redis_connection()orget_async_redis_connection()directly.The
urlkeyword is removed from the connection factories in favour ofredis_url. Passing it now raisesTypeErrornaming the replacement, on all five factory functions, rather than failing with an unrelated error from redis-py. Note thaturlpreviously took precedence overredis_urlon the async factory, so anAsyncSearchIndexbuilt with bothredis_urland aurlinsideconnection_kwargswould connect to the latter; that combination now raises.