Skip to content

Match attribute names on their case only - #167

Merged
azmeuk merged 6 commits into
mainfrom
166-attr-aliases
Sep 20, 2026
Merged

azmeuk merged 6 commits into
mainfrom
166-attr-aliases

Conversation

@azmeuk

@azmeuk azmeuk commented Sep 19, 2026

Copy link
Copy Markdown
Member

Attribute names were normalised by stripping every non-alphanumeric character before folding the case, so:

  • userName, user_name and u.s.e.r.n.a.m.e all reached one field,
  • a field carrying an explicit alias reached none,
  • a schema declaring employee-id, employee_id and employeeId built two fields for three attributes, dumping one value twice and losing the others.

RFC7643 §2.1 makes attribute names case-insensitive and nothing else, its nameChar rule making $, - and _ part of a name, so only the case is folded now: every model carries a table naming each of its fields by the spellings a payload may use, the validation hook rewrites each key through it, and pydantic reads the attribute under the name SCIM spells it with, which is the name an error and a published JSON schema then carry.

from_schema builds a field for every attribute a schema declares, the one already spelled as its Python name keeping it and the others being held under their SCIM name, and only refuses two names that differ by case alone, which RFC7643 makes one attribute. This is a breaking change: a key differing from an attribute name only by its punctuation is now an unknown attribute that ScimPolicy.unknown governs, in payloads as in paths, filters and sortBy.

fixes #166

Four places answered the question of the name a field is serialized under,
each with its own fallback, and only one of them fell back on the camel-cased
field name. BaseModel._scim_name now answers it for all of them, so the name
the resolution reads cannot drift from the name the serialization writes.
RFC7643 §2.1 makes attribute names case-insensitive, and its nameChar rule
makes $, - and _ part of a name, but the normalisation stripped them all, so
userName, user_name and u.s.e.r.n.a.m.e reached one field and a field carrying
an explicit alias reached none. Every model now carries a table listing, for
each of its fields, the spellings a payload may use, the validation hook
rewrites each key through it, and pydantic reads the attribute under the SCIM
spelling, which an error and a published JSON schema then carry.
Two SCIM names may yield one Python name, as employee_id and employeeId both
yield employee_id, and the comprehension building the fields let the last one
win: a dump then reported one value twice while losing the other. Each of them
now gets a field, the attribute already spelled as that name keeping it and the
others being held under their SCIM name, which the order of declaration cannot
change. A schema declaring two names that only differ by case is still refused,
RFC7643 §2.1 making them one attribute.
The nameChar rule of RFC7643 §2.1 lists $ among the characters a name is made
of, and errata 8924 adds the leading one of $ref, but the pattern the grammar
interpolates only accepted it in first position, so an attribute a schema
declares as user$name could be read from a payload yet named by no path nor
filter. The keyword lookaheads widen accordingly, so an attribute named eq$x is
still not read as an operator.
The constraint checks of a pathless operation resolved each attribute name
themselves and gave up on the ones they could not, which an extension named by
its schema URN always was, so an operation unassigning an extension declared
required was answered success. The caller now resolves each name once, before
refusing the ones the schema does not declare, and hands the checks the field
that holds the constraints.
Pydantic advises against populate_by_name since 2.11 and will deprecate it in
v3, the pair of validate_by_name and validate_by_alias telling apart what the
single setting conflated. Both are set, which the documentation states to be
strictly equivalent to what the models declared until now.
@azmeuk
azmeuk merged commit 4a13290 into main Sep 20, 2026
25 checks passed
@azmeuk
azmeuk deleted the 166-attr-aliases branch September 20, 2026 07:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

The library doesn't comply with RFC 7643 attribute naming definitions

1 participant