Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ flowchart TB

```python
app.connect("config-inited", load_config_from_toml, priority=10) # Load TOML config
app.connect("config-inited", load_config) # Register extra options/directives
app.connect("config-inited", load_config) # Register extra fields/directives
app.connect("config-inited", merge_default_configs) # Merge defaults
app.connect("config-inited", check_configuration, priority=600) # Validate config
```
Expand All @@ -343,7 +343,7 @@ app.connect("env-before-read-docs", resolve_schemas_config). # Validates schema
app.connect("env-before-read-docs", load_external_needs) # Load external need files
```

The `prepare_env` function initializes `BuildEnvironment` variables, registers services (GitHub, OpenNeeds), registers dynamic functions, initializes extra options and link types, and optionally starts process timing.
The `prepare_env` function initializes `BuildEnvironment` variables, registers services (GitHub, OpenNeeds), registers dynamic functions, initializes extra fields and links, and optionally starts process timing.

#### Document Processing

Expand Down
6 changes: 3 additions & 3 deletions docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ Schema
FieldLiteralValue, LinkSchema, LinkDisplayConfig, LinksLiteralValue, AllowedTypes

.. automodule:: sphinx_needs.schema.config
:members: ExtraOptionStringSchemaType, ExtraOptionBooleanSchemaType,
ExtraOptionIntegerSchemaType, ExtraOptionNumberSchemaType,
ExtraOptionMultiValueSchemaType,
:members: FieldStringSchemaType, FieldBooleanSchemaType,
FieldIntegerSchemaType, FieldNumberSchemaType,
FieldMultiValueSchemaType,
ExtraLinkSchemaType, ExtraLinkItemSchemaType
3 changes: 2 additions & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
("py:class", "sphinx_needs.views._LazyIndexes"),
("py:class", "sphinx_needs.config.NeedsSphinxConfig"),
("py:class", "AllowedTypes"),
("py:class", "ExtraOptionSchemaTypes"),
("py:class", "FieldSchemaTypes"),
]

rst_epilog = """
Expand Down Expand Up @@ -268,6 +268,7 @@
r"http://127.0.0.1:\d+",
r"../.*",
r"http://sourceforge.net/projects/plantuml.*",
r"http?://beta.plantuml.net/plantuml.jar",
r"https?://useblocks.com/sphinx-needs/bench/index.html",
]

Expand Down
2 changes: 1 addition & 1 deletion docs/filter.rst
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ Additional variables for :ref:`need_part`:
* **id_complete** as Python string. Contains the concatenated ids of parent need and need_part.
(compare like ``id_complete != 'ABC_01.03'``)

.. note:: If extra options were specified using :ref:`needs_fields` then
.. note:: If extra fields were specified using :ref:`needs_fields` then
those will be available for use in filter expressions as well.

Finally, the following are available:
Expand Down
30 changes: 13 additions & 17 deletions docs/schema/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ See :ref:`migration_from_warnings_constraints` for details on how to migrate.
conform to their types are not created and lead to a warning.
- **JSON export**: Generated :ref:`needs.json <needs_builder>` files honor the user provided
types
- **Multi value extra options**: Array types for extra options are fully supported
- **Multi value extra fields**: Array types for extra fields are fully supported
- **Gradual migration**: Existing projects can migrate step-by-step to the new system,
with string types as default for untyped fields.
- **Safety**: The new type system core makes it possible to configure fields individually.
Expand Down Expand Up @@ -60,11 +60,11 @@ Schema configuration

The schema is configured in multiple places:

- :ref:`needs_fields` is the place to add new extra options that are then available
- :ref:`needs_fields` is the place to add new fields that are then available
for all need types. The type information for each field is globally set here, so it is valid
for all the usages of that field for any need type. This is required for a coherent data
storage, as it would be expected by a database system. If different data types are needed for the
same option, it means creating a new extra option with a different name and type.
same option, it means creating a new field with a different name and type.

Further, the ``schema`` field in ``needs_fields`` also supports setting global
schema constraints for that option, that will be checked for each need type. E.g.
Expand Down Expand Up @@ -111,9 +111,9 @@ Imagine the following modeling of need items:

There are a few things to note about this setup:

- the extra options ``efforts``, ``approval`` and
- the fields ``efforts``, ``approval`` and
``asil`` (for **A**\ utomotive **S**\ ecurity **I**\ ntegrity **L**\ evel) are typed
- the assigned extra options differ between need types
- the assigned fields differ between need types
- the fields may be optional for a need type, required or even not allowed
- some validation rules are local to the need itself, while others
require information from other needs (network validation)
Expand Down Expand Up @@ -180,25 +180,21 @@ For **primitive types** (string, integer, number, boolean):

.. code-block:: toml

[[needs.extra_options]]
name = "efforts"
[needs.fields.efforts]
schema.type = "integer"

[[needs.extra_options]]
name = "approval"
[needs.fields.approval]
schema.type = "boolean"

For **array types**, both the array type and the item type must be specified:

.. code-block:: toml

[[needs.extra_options]]
name = "tags"
[needs.fields.tags]
schema.type = "array"
schema.items.type = "string"

[[needs.extra_options]]
name = "priorities"
[needs.fields.priorities]
schema.type = "array"
schema.items.type = "integer"

Expand All @@ -209,12 +205,12 @@ Additional schema constraints can also be defined here, which will be validated

.. code-block:: toml

[[needs.extra_options]]
[needs.fields.asil]
name = "asil"
schema.type = "string"
schema.enum = ["QM", "A", "B", "C", "D"]

[[needs.extra_options]]
[needs.fields.efforts]
name = "efforts"
schema.type = "integer"
schema.minimum = 0
Expand All @@ -229,9 +225,9 @@ The ``schemas.json`` file (or :ref:`needs_schema_definitions`) also requires typ
validation, but:

- **If type is not specified** in schemas.json, it will be **automatically injected** from the
``needs.extra_options`` definition (or from core field definitions for built-in fields)
``needs.fields`` definition (or from core field definitions for built-in fields)
- **If type is specified** in schemas.json, it **must match** the type defined in
``needs.extra_options`` (or the core field definition)
``needs.fields`` (or the core field definition)

This ensures type consistency across your entire configuration while reducing duplication.
The injection to the schema rules is required for safe JSON schema validation.
Expand Down
2 changes: 1 addition & 1 deletion performance/performance_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ def start(
@click.option(
"--basic",
is_flag=True,
help="Use only default config of Sphinx-Needs (e.g. no extra options)",
help="Use only default config of Sphinx-Needs (e.g. no extra fields)",
)
def series(
profile,
Expand Down
12 changes: 6 additions & 6 deletions sphinx_needs/api/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from sphinx_needs.exceptions import NeedsApiConfigException
from sphinx_needs.functions.functions import DynamicFunction
from sphinx_needs.need_item import NeedItem
from sphinx_needs.schema.config import ExtraOptionSchemaTypes
from sphinx_needs.schema.config import FieldSchemaTypes

# TODO(mh) document exactly when API calls are allowed in the Sphinx event system

Expand Down Expand Up @@ -92,7 +92,7 @@ def add_extra_option(
name: str,
*,
description: str = "Added by add_extra_option API",
schema: ExtraOptionSchemaTypes | None = None,
schema: FieldSchemaTypes | None = None,
nullable: bool | None = None,
parse_variants: bool | None = None,
) -> None:
Expand Down Expand Up @@ -136,7 +136,7 @@ def add_field(
/,
description: str,
*,
schema: ExtraOptionSchemaTypes | None = None,
schema: FieldSchemaTypes | None = None,
nullable: bool | None = None,
parse_variants: bool | None = None,
) -> None:
Expand All @@ -151,9 +151,9 @@ def add_field(

add_field('my_field')

:param name: Name of the extra option
:param description: Description of the extra option
:param schema: Schema definition for the extra option
:param name: Name of the field
:param description: Description of the field
:param schema: Schema definition for the field
:param nullable: Whether the field allows unset values.
:param parse_variants: Whether variants are parsed in this field.
"""
Expand Down
26 changes: 13 additions & 13 deletions sphinx_needs/api/need.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ def generate_need(

:raises InvalidNeedException: If the data fails any validation issue.

``kwargs`` can contain options defined in ``needs_extra_options`` and ``needs_extra_links``.
``kwargs`` can contain options defined in ``needs_fields`` and ``needs_extra_links``.
If an entry is found in ``kwargs``, which *is not* specified in the configuration or registered e.g. via
``add_field``, an exception is raised.

Expand Down Expand Up @@ -185,7 +185,7 @@ def generate_need(
if unknown_kwargs:
raise InvalidNeedException(
"invalid_kwargs",
f"Options {unknown_kwargs!r} not in 'needs_extra_options' or 'needs_extra_links.",
f"{unknown_kwargs!r} not in 'needs_fields' or 'needs_extra_links.",
)

# get the need type data
Expand Down Expand Up @@ -277,8 +277,8 @@ def generate_need(
)
except Exception as err:
raise InvalidNeedException(
"invalid_extra_option",
f"Extra option {extra_field.name!r} is invalid: {err}",
"invalid_field_value",
f"Field {extra_field.name!r} is invalid: {err}",
) from err

links_no_defaults: dict[str, None | LinksLiteralValue | LinksFunctionArray] = {}
Expand Down Expand Up @@ -488,14 +488,14 @@ def generate_need(
for k, v in extras.items():
if (extra_schema := needs_schema.get_extra_field(k)) is None:
raise InvalidNeedException(
"invalid_extra_option",
f"Extra option {k!r} not in 'needs_fields'.",
"invalid_field_value",
f"Field {k!r} not in 'needs_fields'.",
)
if v is None:
if not extra_schema.nullable:
raise InvalidNeedException(
"invalid_extra_option",
f"Extra option {k!r} is not nullable, but no value or default was given.",
"invalid_field_value",
f"Field {k!r} is not nullable, but no value or default was given.",
)
extras_pre[k] = None
elif isinstance(v, FieldLiteralValue):
Expand All @@ -515,13 +515,13 @@ def generate_need(
extras_pre[k] = []
case other:
raise InvalidNeedException(
"invalid_extra_option",
f"Extra option {k!r} has unknown type {other!r}.",
"invalid_field_value",
f"Field {k!r} has unknown type {other!r}.",
)
else:
raise InvalidNeedException(
"invalid_extra_option",
f"Extra option {k!r} has unknown value {v!r}.",
"invalid_field_value",
f"Field {k!r} has unknown value {v!r}.",
)

links_pre: dict[str, list[str]] = {}
Expand Down Expand Up @@ -765,7 +765,7 @@ def add_need(
``add_need`` allows to create needs programmatically and use its returned node to be integrated in any
docutils based structure.

``kwargs`` can contain options defined in ``needs_extra_options`` and ``needs_extra_links``.
``kwargs`` can contain options defined in ``needs_fields`` and ``needs_extra_links``.
If an entry is found in ``kwargs``, which *is not* specified in the configuration or registered e.g. via
``add_field``, an exception is raised.

Expand Down
38 changes: 19 additions & 19 deletions sphinx_needs/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@
from sphinx_needs.logging import get_logger, log_warning
from sphinx_needs.schema.config import (
ExtraLinkSchemaType,
ExtraOptionBooleanSchemaType,
ExtraOptionIntegerSchemaType,
ExtraOptionMultiValueSchemaType,
ExtraOptionNumberSchemaType,
ExtraOptionSchemaTypes,
ExtraOptionStringSchemaType,
FieldBooleanSchemaType,
FieldIntegerSchemaType,
FieldMultiValueSchemaType,
FieldNumberSchemaType,
FieldSchemaTypes,
FieldStringSchemaType,
SchemasFileRootType,
)

Expand All @@ -42,11 +42,11 @@ class NewFieldParams:
nullable: bool | None = None
"""Whether the field allows unset values."""
schema: (
ExtraOptionStringSchemaType
| ExtraOptionBooleanSchemaType
| ExtraOptionIntegerSchemaType
| ExtraOptionNumberSchemaType
| ExtraOptionMultiValueSchemaType
FieldStringSchemaType
| FieldBooleanSchemaType
| FieldIntegerSchemaType
| FieldNumberSchemaType
| FieldMultiValueSchemaType
| None
)
"""A JSON schema for the option."""
Expand Down Expand Up @@ -110,11 +110,11 @@ def add_field(
name: str,
description: str,
*,
schema: ExtraOptionStringSchemaType
| ExtraOptionBooleanSchemaType
| ExtraOptionIntegerSchemaType
| ExtraOptionNumberSchemaType
| ExtraOptionMultiValueSchemaType
schema: FieldStringSchemaType
| FieldBooleanSchemaType
| FieldIntegerSchemaType
| FieldNumberSchemaType
| FieldMultiValueSchemaType
| None = None,
nullable: None | bool = None,
override: bool = False,
Expand Down Expand Up @@ -311,7 +311,7 @@ class NeedFields(TypedDict):

description: NotRequired[str]
"""A description of the field."""
schema: NotRequired[ExtraOptionSchemaTypes]
schema: NotRequired[FieldSchemaTypes]
"""
A JSON schema definition for the field.

Expand All @@ -328,7 +328,7 @@ class NeedFields(TypedDict):
"""Whether variants are parsed in this field."""


class NeedExtraOption(NeedFields):
class NeedField(NeedFields):
"""Defines an extra option for needs"""

name: str
Expand Down Expand Up @@ -620,7 +620,7 @@ def get_default(cls, name: str) -> Any:
_fields: dict[str, NeedFields] = field(
default_factory=dict, metadata={"rebuild": "html", "types": (dict,)}
)
_extra_options: list[str | NeedExtraOption] = field(
_extra_options: list[str | NeedField] = field(
default_factory=list, metadata={"rebuild": "html", "types": (list,)}
)
"""List of extra options for needs, that get added as directive options and need fields."""
Expand Down
2 changes: 1 addition & 1 deletion sphinx_needs/directives/needservice.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ def run(self) -> Sequence[nodes.Node]:
del datum["title"]

# We need to check if all given options from services are really available as configured
# extra_option or extra_link
# needs_fields or needs_extra_links
missing_options = {}
for element in datum:
if element not in defined_options:
Expand Down
4 changes: 2 additions & 2 deletions sphinx_needs/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def __init__(
type_: Literal[
"invalid_kwargs",
"invalid_type",
"invalid_extra_option",
"invalid_field_value",
"invalid_link_option",
"missing_id",
"invalid_id",
Expand Down Expand Up @@ -50,7 +50,7 @@ def type(
) -> Literal[
"invalid_kwargs",
"invalid_type",
"invalid_extra_option",
"invalid_field_value",
"invalid_link_option",
"missing_id",
"invalid_id",
Expand Down
Loading
Loading