Repository navigation
refactor(enums): make RedisVL's string enums StrEnum subclasses - #811
Draft
vishal-bala wants to merge 2 commits into
Draft
vishal-bala wants to merge 2 commits into
vishal-bala wants to merge 2 commits into
Conversation
str() and f-strings on a (str, Enum) member give "Cls.MEMBER" on Python 3.11+, so error messages and query strings built from members printed the class name. StrEnum returns the value. Serialisation, YAML output and the FT.CREATE arguments sent to Redis already used the value and are unchanged. Drops the getattr(..., "value", ...) workarounds in the MCP tools and the .value calls that existed only to format a member, and pins the visible string form in tests/unit/test_str_enums.py.
The hybrid-policy, stored-role and MCP error-code checks passed under (str, Enum) as well and duplicate existing coverage; the integration test already pins the stored ChatRole bytes.
vishal-bala
force-pushed
the
refactor/str-enum
branch
from
November 3, 2026 12:08
f9658e8 to
dfe48d3
Compare
This branch has not been deployed
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
On Python 3.11 and later,
str()and f-strings on a(str, Enum)member return"Cls.MEMBER", not the member's value. Measured on 3.11.9,f"{VectorDataType.INT8}"gives'VectorDataType.INT8'; on 3.10.19 it gave'INT8', andstr()has given the class-qualified form on every version. RedisVL builds error messages and query strings from these members, so they now print the class name: an SVS-VAMANA field with anint8datatype fails with "Got: VectorDataType.INT8", andTag("role") == [ChatRole.USER, ChatRole.TOOL]renders@role:{ChatRole\.USER|ChatRole\.TOOL}, which matches nothing. With Python 3.10 dropped,enum.StrEnumis available everywhere RedisVL runs, and its members stringify to their value.Changes
StrEnum
Nine classes move from
(str, Enum)toStrEnum, with their member values unchanged:FieldTypes,VectorDistanceMetric,VectorDataType,VectorIndexAlgorithmandCompressionTypeinredisvl/schema/fields.py,HybridPolicyinredisvl/query/query.py,Inclusiveinredisvl/query/filter.py,ChatRoleinredisvl/extensions/message_history/schema.pyandMCPErrorCodeinredisvl/mcp/errors.py.str(),format()and%son a member now return its value. Nothing that already went through the value changes: equality and hashing against plain strings,repr(),json.dumps, pydanticmodel_dump()in both modes,IndexSchema.to_dict()andto_yaml(), and the FT.CREATE arguments redis-py encodes. The plainEnumclasses, such asStorageTypeandFilterOperator, are untouched.Stringification call sites
Where code reached for
.valueorgetattr(member, "value", member)only to format a member, it now uses the member directly: the field-type list in the MCPlist-indexestool and the search tool's filter hint,_vector_dtypein the MCP upsert tool, theHYBRID_POLICYclause ofVectorQuery, and the SVS-VAMANA compression error. Other.valuecalls stay, since they remain correct. Error messages that interpolate a member without.valuenow name the value, for example "is a text field" in the MCP lock-injection check.Tests
tests/unit/test_str_enums.pypins the string form of every member, the encoded FT.CREATE arguments, the schema's pydantic and YAML output, and the error and query strings above. A new integration test intests/integration/test_message_history.pystores messages withChatRolemembers, reads the raw hash field back asb"user",b"tool"andb"assistant", and filters on a list of members.Notes
redisvl/schema/validation.pychecks JSONint8anduint8vectors against their ranges by comparingstr(datatype).upper()with"INT8"and"UINT8". Under(str, Enum)that comparison never matched, so the range check never ran; withStrEnumit does. This PR leaves the file alone, because the separate fix onfix/int8-uint8-vector-range-checkrewrites that comparison to use the members directly and adds the boundary tests. The two merge cleanly in either order, and the Release Notes below mention the range check so the behaviour change is not lost if this PR lands first.The MCP error code does not reach MCP clients: FastMCP turns a raised
RedisVLMCPErrorinto a tool error whose text is the exception message alone, so the tool error payload is unchanged.This PR is stacked on the Python 3.10 drop (#810) and should merge after it. It also overlaps #805, which fixes the INT8/UINT8 range check directly; whichever merges second should drop its duplicate test.
Release Notes
str()and f-strings on members of RedisVL's string enums (VectorDataType,VectorDistanceMetric,VectorIndexAlgorithm,CompressionType,FieldTypes,HybridPolicy,Inclusive,ChatRoleandMCPErrorCode) now return the member's value, such as"INT8", rather than"VectorDataType.INT8"; code that matched the old form should compare with the member or its value. Schema validation now rejects JSONint8vectors with elements outside -128..127 anduint8vectors outside 0..255.Reviewer Brief
Start here:
redisvl/schema/fields.py, the five enum classes andBaseVectorFieldAttributes.field_data. Field attributes hold these members and pass them to redis-py unchanged, so this is where a change in how members turn into strings would reach Redis.Where it could fail
redisvl/schema/validation.py:178: unchanged in this diff, but itsstr(datatype).upper()comparison now matches, sovalidate_objectandload(..., validate_on_load=True)start rejecting out-of-range JSONint8/uint8vectors that used to load.str(member)or an f-string with"VectorDataType.INT8"-style text now gets the bare value; nothing inredisvl/,tests/ordocs/does this.Not verified: cluster tests and live provider API tests, neither of which this change touches; Python 3.12, 3.14 and 3.15, which CI covers but this review did not run; the LeanVec cases in
tests/integration/test_svs_integration.py, where 7 of 19 fail locally with zero documents indexed, identically on the parent commit.Beyond CI: a before-and-after dump of every member's
str,format,%s,repr, JSON and redis-py encoding, plus the schema'sto_dict,to_yaml, bothmodel_dumpmodes and the encoded FT.CREATE arguments, differs only instr,formatand%sand in the three strings built from them (the SVS-VAMANA datatype error, aTagfilter given a list of members, and the INT8 range check), identically on 3.11.9 and 3.13.9; 42 of the 44 new unit tests fail against the parent commit, and the other 2 pin output that must not change.Reviewed
239973b8(rebased unchanged frome31bacbd), fixes indfe48d35· Claude Code (claude-opus-5-5) · lenses: correctness, security, design, tests, docs, Redis behaviour