attr.validate() is not recursive

Open
#727 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
5/5
Estimated time
Over a week
Newbie friendliness
25/100
Issue type
Feature
Clarity
Mostly clear
Activity status
Stale
Tech stack
python
Domain
tooling

Research direction

Start with the documented behavior of attrs.validate and set_run_validators, then run the supplied nested Inner/Outer reproduction. Resolve whether the issue calls for clearer documentation or a recursive validation option; done means the selected behavior is clearly specified and demonstrated by the example.

Written by the indexing model from the issue text.

Description

Feature

I am using attrs to manage the configuration of a database system. I was hoping to use set_run_validators to temporarily disable validation during a multi-step evolution of a large data structure composed of nested attr classes, and deferring the validators until all the evolutions are complete.

It surprised me to see that attrs.validate is not recursive -- it only invokes the validators of the top-level fields of a class, and won't invoke the attr validators on any attr instances on that field.

The wording in the docs is technically correct but a rewording may be helpful.

Also, would there be any reason not to add something like a recursive=True option?

The script below illustrates the behavior.

def log_validation(cls, _, _2):
    print(f"in log_validation for {cls}")


@attr.s(frozen=True)
class Inner:
    vi: int = attr.ib(validator=log_validation)

@attr.s(frozen=True)
class Outer:
    vo: str = attr.ib(validator=log_validation)
    i: Inner = attr.ib()

attr.set_run_validators(False)
x = Outer(vo=None, i=Inner(vi=123))
attr.set_run_validators(True)

attr.validate(x)
# output:
# in log_validation for Inner(vi=123)

My assumption is that it would validate the entire tree, much as we would get if we serialized and deserialized the instance:

cattr.structure(cattr.unstructure(x), Outer)
# output:
# in log_validation for Inner(vi=123)
# in log_validation for Outer(vo='None', i=Inner(vi=123))

I'm using attrs 19.3.0.

Thanks!

Dominant language
Python
Stars
5.8k
Forks
480
Avg merge
2h 15m
Merged PRs (30d)
2

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from python-attrs/attrs

All issues in python-attrs/attrs

Similar issues

More Python issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.