Skip to content

glom.glom() silently mutates the spec argument #313

Description

@APITester26

glom.glom() silently mutates the spec argument

Environment

  • glom current release and main
  • Python 3.11.15

Reproduction

import glom
from glom import T

target = {'a': [{'k': 'v3'}, {'missing': 'x'}, {'k': None}], 'k': 'v0'}
spec = T
print(repr(spec))  # before
result = glom.glom(target, spec, default='nada', skip_exc=(Exception,), scope={'UP': None})
print(repr(spec))  # after — may be silently modified

Expected behavior

glom.glom() should be a read-only operation on its spec argument. The speclet object passed by the caller should be identical before and after the call, regardless of whether the glom operation succeeds or raises.

Cause

The internal spec-processing pipeline appears to modify the spec object in place — possibly by normalizing path components, resolving T-expressions, or attaching internal bookkeeping state. The metamorphic test detected that the spec parameter value changed after the call to glom.glom(), violating the non-mutation invariant.

Suggested fix

Process specs on a copy or ensure that internal transformations are non-destructive to the caller's object. Since specs can be complex nested structures (including T, Path, and other spec types), the cloning strategy should handle all speclet types.

A regression test should assert that spec is unchanged after a call to glom.glom() for common spec types (T, Path, dict specs, and combined specs).

How this was found

This was found by metamorphic testing of the non-mutation relation: the test asserts that calling an API should not silently modify its arguments. glom.mutation.glom violated this invariant by mutating the spec parameter, as detected by pre- and post-call comparison.

Thanks for maintaining glom and for reviewing this issue. I appreciate the time and effort put into improving the project.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions