Skip to content

Share schema and value conversion helpers - #2071

Merged
davisagli merged 7 commits into
mainfrom
issue-2061-schema-helpers
Nov 1, 2026
Merged

davisagli merged 7 commits into
mainfrom
issue-2061-schema-helpers

Conversation

@sneridagh

@sneridagh sneridagh commented Oct 19, 2026 •

Copy link
Copy Markdown
Member

Control panels, content rules, and the upcoming @content-types service all build JSON schemas and convert values for plain zope.schema interfaces. Each had its own copy of that logic. This PR moves it to plone.restapi.types.utils and switches control panels and content rules over, with unchanged output.

Step 2a of #2061, stacked on #2069. Review it against issue-2061-acceptance-server. #2070 builds on it.

Shared helpers

  • SchemaValues is a transient context that provides IDexterityContent, so the content field converters and JSON schema providers work for any schema. It replaces the three FakeDXContext copies, and FakeDXContext stays as an alias.
  • get_jsonschema_for_schema() returns properties, required, and fieldsets in the control panel format. It marks read-only and display-mode fields readOnly and leaves them out of required. Hidden fields are still submitted by forms, so they aren't marked.
  • serialize_schema_values() / deserialize_schema_values() convert values through the registered field adapters.
    • The default lenient mode keeps the control panel behavior: unknown fields are ignored and read-only fields skipped.
    • A strict mode reports unknown, read-only, and missing required fields. It also checks schema invariants against the merged current values, so partial updates are validated correctly.
  • format_errors() translates error messages and masks Python error classes, as control panels did before.

Bug fixes

  • JSON schema of schema.Object fields: see the next section.
  • Bool fields: these accepted any string and silently stored False for everything except "true", and numbers were stored as they were. They now accept JSON booleans, "true", "false", and null, and reject anything else.

JSON schema of schema.Object fields

ObjectJsonSchemaProvider (types/adapters.py) is used for every schema.Object field in @types, control panels, and content rules. It was written for file and image fields, and described every other schema.Object field as a file as well.

What changes, by the schema of the field:

Field schema factory before factory after Property names required
INamedBlobImage Image Image dotted, unchanged not added
INamedImage (not blob) File Image dotted, unchanged not added
INamedFile, INamedBlobFile File File dotted, unchanged not added
Any other schema File none plain field names added

For example, schema.Object(title="Range", schema=IRange), where IRange has a required start and an optional end.

Before:

{
  "type": "object",
  "title": "Range",
  "factory": "File",
  "properties": {
    "range.start": {"type": "integer", "title": "Start"},
    "range.end": {"type": "integer", "title": "End"}
  }
}

After:

{
  "type": "object",
  "title": "Range",
  "properties": {
    "start": {"type": "integer", "title": "Start"},
    "end": {"type": "integer", "title": "End"}
  },
  "required": ["start"]
}

Compatibility:

  • File and image fields keep their exact previous output, including the dotted property names such as image.data, apart from non-blob NamedImage fields, which now report Image instead of File. @types responses for the default content types and the userschema example don't change.
  • Other schema.Object fields no longer pose as files, so a frontend doesn't pick a file widget for them. Their nested properties are now valid JSON schema, keyed by field name, with a required list that leaves out read-only fields.
  • Schema output only. restapi still has no converter for schema.Object values. An earlier version of this PR added ObjectFieldSerializer and ObjectFieldDeserializer, but removed them for two reasons:
    • They broke serialization of collective.z3cform.datagridfield rows, whose DictRow subclasses schema.Object but stores plain dicts.
    • Content schema.Object fields would have started storing restapi's SchemaValues objects in the ZODB.

Why it is part of this PR: it came up while sharing the schema helpers, and get_jsonschema_for_schema() relies on the provider for nested schemas. #2070 no longer has any schema.Object setting, since its allowed content types are two flat fields, so nothing in the #2061 stack depends on this fix. It's covered by test_object in test_types.py and by test_nested_object_schema and test_file_objects_keep_legacy_shape in test_types_schema_helpers.py.

Validation

  • Full suite passes: 1441 tests.
  • Control panel and content rules http-examples regenerate without changes.
  • New test_types_schema_helpers.py covers the helpers, strict and lenient modes, invariants with partial data, context source binders, and the nested Object schema.

@read-the-docs-community

read-the-docs-community Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

Documentation build overview

📚 plone.restapi | 🛠️ Build #35245927 | 📁 Comparing 2964f0b against latest (e26b660)

  🔍 Preview build  

1 file changed
± contributing/index.html

@sneridagh
sneridagh requested a review from davisagli October 19, 2026 16:04
Base automatically changed from issue-2061-acceptance-server to main October 20, 2026 04:46

@davisagli davisagli left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sneridagh I only started reviewing it, I have to continue tomorrow.

Comment thread news/2061.bugfix Resolved
Comment thread src/plone/restapi/types/utils.py Resolved
@sneridagh

Copy link
Copy Markdown
Member Author

@jenkins-plone-org please run jobs

@sneridagh

Copy link
Copy Markdown
Member Author

@jenkins-plone-org please run jobs

sneridagh and others added 7 commits November 1, 2026 11:31
Control panels, content rules and new settings services all build JSON
schemas and convert values for plain zope.schema interfaces. Move that
logic to plone.restapi.types.utils:

- SchemaValues, a transient context providing IDexterityContent that
  replaces the three FakeDXContext copies (kept as an alias).
- get_jsonschema_for_schema, which also marks read-only and display
  fields as readOnly and leaves them out of required.
- serialize_schema_values and deserialize_schema_values, with a strict
  mode that reports unknown, read-only and missing fields and checks
  invariants against the merged current values.

Control panels and content rules now use them, with unchanged output.

Also describe and convert schema.Object fields that are not files or
images: no File factory, plain property names, required fields, and
JSON object values, including in lists.
Strings other than "true" and "false" used to become False silently,
and numbers were stored as they were.
Fields such as collective.z3cform.datagridfield's DictRow subclass
schema.Object but store plain dicts, and the new collection branch
failed to serialize them. Content Object fields would also have stored
SchemaValues instances. Keep the JSON schema fix for Object fields only.
- Prefix the shared schema helpers with an underscore, as they are not
  public API, and add type annotations.
- Define the FakeDXContext BBB aliases by assignment instead of a noqa
  import.
- Split the Bool fix into its own news entry.
- Test that control panel updates keep omitted fields and report
  invariant errors once.
@davisagli
davisagli force-pushed the issue-2061-schema-helpers branch from fd2070e to fd29194 Compare November 1, 2026 19:31
@davisagli

Copy link
Copy Markdown
Member

@jenkins-plone-org please run jobs

@davisagli
davisagli enabled stacked auto-merge (squash) November 1, 2026 19:58
@davisagli
davisagli merged commit 4e9ca29 into main Nov 1, 2026
20 checks passed
@davisagli
davisagli deleted the issue-2061-schema-helpers branch November 1, 2026 20:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants