Skip to content

Commit 3baf4eb

Browse files
fix: changed how extra fields work
1 parent a679015 commit 3baf4eb

File tree

10 files changed

+55
-55
lines changed

10 files changed

+55
-55
lines changed

src/taskgraph/config.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,7 @@
88
import sys
99
from dataclasses import dataclass
1010
from pathlib import Path
11-
from typing import Any, Dict, List, Literal, Optional, Union
12-
13-
import msgspec
11+
from typing import Dict, List, Literal, Optional, Union
1412

1513
from .util.python_path import find_object
1614
from .util.schema import Schema, optionally_keyed_by, validate_schema
@@ -55,17 +53,18 @@ class Workers(Schema, rename=None):
5553
aliases: Dict[str, WorkerAlias]
5654

5755

58-
class Repository(Schema):
59-
"""Repository configuration."""
56+
class Repository(Schema, forbid_unknown_fields=False):
57+
"""Repository configuration.
58+
59+
This schema allows extra fields for repository-specific configuration.
60+
"""
6061

6162
# Required fields first
6263
name: str
6364

6465
# Optional fields
6566
project_regex: Optional[str] = None # Maps from "project-regex"
6667
ssh_secret_name: Optional[str] = None # Maps from "ssh-secret-name"
67-
# Allow extra fields for flexibility
68-
__extras__: Dict[str, Any] = msgspec.field(default_factory=dict)
6968

7069

7170
class RunConfig(Schema):
@@ -89,8 +88,11 @@ class TaskGraphConfig(Schema):
8988
run: Optional[RunConfig] = None
9089

9190

92-
class GraphConfigSchema(Schema):
93-
"""Main graph configuration schema."""
91+
class GraphConfigSchema(Schema, forbid_unknown_fields=False):
92+
"""Main graph configuration schema.
93+
94+
This schema allows extra fields for flexibility in graph configuration.
95+
"""
9496

9597
# Required fields first
9698
trust_domain: str # Maps from "trust-domain"
@@ -106,8 +108,6 @@ class GraphConfigSchema(Schema):
106108
None # Maps from "task-deadline-after", can be keyed-by project
107109
)
108110
task_expires_after: Optional[str] = None # Maps from "task-expires-after"
109-
# Allow extra fields for flexibility
110-
__extras__: Dict[str, Any] = msgspec.field(default_factory=dict)
111111

112112
def __post_init__(self):
113113
"""Validate keyed-by fields."""

src/taskgraph/transforms/chunking.py

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@
22
# License, v. 2.0. If a copy of the MPL was not distributed with this
33
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
44
import copy
5-
from typing import Any, Dict, List, Optional
6-
7-
import msgspec
5+
from typing import List, Optional
86

97
from taskgraph.transforms.base import TransformSequence
108
from taskgraph.util.schema import Schema
@@ -26,16 +24,13 @@ class ChunkConfig(Schema):
2624

2725

2826
#: Schema for chunking transforms
29-
class ChunkSchema(Schema):
27+
class ChunkSchema(Schema, forbid_unknown_fields=False):
3028
# Optional, so it can be used for a subset of tasks in a kind
3129
chunk: Optional[ChunkConfig] = None
32-
__extras__: Dict[str, Any] = msgspec.field(default_factory=dict)
33-
3430

35-
CHUNK_SCHEMA = ChunkSchema
3631

3732
transforms = TransformSequence()
38-
transforms.add_validate(CHUNK_SCHEMA)
33+
transforms.add_validate(ChunkSchema)
3934

4035

4136
@transforms.add

src/taskgraph/transforms/from_deps.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,12 +89,10 @@ def __post_init__(self):
8989

9090

9191
#: Schema for from_deps transforms
92-
class FromDepsSchema(Schema):
92+
class FromDepsSchema(Schema, forbid_unknown_fields=False):
9393
"""Schema for from_deps transforms."""
9494

9595
from_deps: FromDepsConfig
96-
# Allow extra fields
97-
_extra: Optional[Dict[str, Any]] = msgspec.field(default=None, name="")
9896

9997

10098
# Backward compatibility

src/taskgraph/transforms/matrix.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,14 @@
88
"""
99

1010
from copy import deepcopy
11-
from typing import Any, Dict, List, Optional
12-
13-
import msgspec
11+
from typing import Dict, List, Optional
1412

1513
from taskgraph.transforms.base import TransformSequence
1614
from taskgraph.util.schema import Schema
1715
from taskgraph.util.templates import substitute_task_fields
1816

1917

20-
class MatrixConfig(Schema):
18+
class MatrixConfig(Schema, forbid_unknown_fields=False):
2119
"""
2220
Matrix configuration for generating multiple tasks.
2321
"""
@@ -39,15 +37,17 @@ class MatrixConfig(Schema):
3937
# If not specified, all fields in the task definition will be
4038
# substituted.
4139
substitution_fields: Optional[List[str]] = None
42-
# Allow extra fields for matrix dimensions
43-
__extras__: Dict[str, List[str]] = msgspec.field(default_factory=dict)
4440

4541

4642
#: Schema for matrix transforms
47-
class MatrixSchema(Schema):
43+
class MatrixSchema(Schema, forbid_unknown_fields=False):
44+
"""Schema for matrix transforms.
45+
46+
This schema allows extra fields to be passed through to the task.
47+
"""
48+
4849
name: str
4950
matrix: Optional[MatrixConfig] = None
50-
__extras__: Dict[str, Any] = msgspec.field(default_factory=dict)
5151

5252

5353
MATRIX_SCHEMA = MatrixSchema

src/taskgraph/transforms/notify.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ class LegacyNotificationsConfig(Schema, rename="kebab"):
128128

129129

130130
#: Schema for notify transforms
131-
class NotifySchema(Schema, tag_field="notify_type"):
131+
class NotifySchema(Schema, tag_field="notify_type", forbid_unknown_fields=False):
132132
"""Schema for notify transforms.
133133
134134
Note: This schema allows either 'notify' or 'notifications' field,
@@ -137,8 +137,6 @@ class NotifySchema(Schema, tag_field="notify_type"):
137137

138138
notify: Optional[NotifyConfig] = None
139139
notifications: Optional[LegacyNotificationsConfig] = None
140-
# Allow extra fields
141-
_extra: Optional[Dict[str, Any]] = msgspec.field(default=None, name="")
142140

143141
def __post_init__(self):
144142
# Ensure only one of notify or notifications is present

src/taskgraph/transforms/run/__init__.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,14 @@ class WhenConfig(Schema):
4646

4747

4848
# Run configuration using msgspec
49-
class RunConfig(Schema, rename=None):
50-
"""Configuration for how to run a task."""
49+
class RunConfig(Schema, rename=None, forbid_unknown_fields=False):
50+
"""Configuration for how to run a task.
51+
52+
This schema allows extra fields for run implementation-specific configuration.
53+
"""
5154

5255
using: str
5356
workdir: TOptional[str] = None
54-
# Allow any extra fields for run implementation-specific config
55-
__extras__: Dict[str, Any] = msgspec.field(default_factory=dict)
5657

5758

5859
# Run description schema using msgspec

src/taskgraph/transforms/run/toolchain.py

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77

88
from typing import Any, Dict, List, Literal, Optional, Union
99

10-
import msgspec
11-
1210
import taskgraph
1311
from taskgraph.transforms.run import configure_taskdesc_for_run, run_task_using
1412
from taskgraph.transforms.run.common import (
@@ -25,7 +23,7 @@
2523

2624

2725
#: Schema for run.using toolchain
28-
class ToolchainRunSchema(Schema):
26+
class ToolchainRunSchema(Schema, forbid_unknown_fields=False):
2927
# Required fields first
3028

3129
# Specifies the run type. Must be "toolchain-script".
@@ -63,12 +61,6 @@ class ToolchainRunSchema(Schema):
6361
# toolchain.
6462
toolchain_env: Optional[Dict[str, Any]] = None
6563

66-
# Allow extra fields
67-
_extra: Optional[Dict[str, Any]] = msgspec.field(default=None, name="")
68-
69-
70-
toolchain_run_schema = ToolchainRunSchema
71-
7264

7365
def get_digest_data(config, run, taskdesc):
7466
files = list(run.pop("resources", []))

src/taskgraph/transforms/task.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,13 @@ class TaskDescriptionIndex(Schema, rename="kebab"):
7070
rank: Union[Literal["by-tier", "build_date"], int] = "by-tier"
7171

7272

73-
class TaskDescriptionWorker(Schema, rename=None):
74-
"""Worker configuration for a task."""
73+
class TaskDescriptionWorker(Schema, rename=None, forbid_unknown_fields=False):
74+
"""Worker configuration for a task.
75+
76+
This schema allows extra fields for worker-specific configuration.
77+
"""
7578

7679
implementation: str
77-
# Allow any extra fields for worker-specific configuration
78-
__extras__: Dict[str, TAny] = msgspec.field(default_factory=dict)
7980

8081

8182
class TaskDescriptionSchema(Schema):

src/taskgraph/transforms/task_context.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
from typing import Any, Dict, List, Optional, Union
22

3-
import msgspec
4-
53
from taskgraph.transforms.base import TransformSequence
64
from taskgraph.util.schema import Schema
75
from taskgraph.util.templates import deep_get, substitute_task_fields
@@ -53,13 +51,17 @@ class TaskContextConfig(Schema):
5351

5452

5553
#: Schema for the task_context transforms
56-
class TaskContextSchema(Schema):
54+
class TaskContextSchema(Schema, forbid_unknown_fields=False):
55+
"""Schema for task context transforms.
56+
57+
This schema allows extra fields to be passed through to the task.
58+
"""
59+
5760
# Required field first
5861
task_context: TaskContextConfig
5962

6063
# Optional fields
6164
name: Optional[str] = None
62-
__extras__: Dict[str, Any] = msgspec.field(default_factory=dict)
6365

6466

6567
SCHEMA = TaskContextSchema

src/taskgraph/util/schema.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,13 @@ def resolve_keyed_by(
190190
]
191191

192192

193-
class Schema(msgspec.Struct, kw_only=True, omit_defaults=True, rename="kebab"):
193+
class Schema(
194+
msgspec.Struct,
195+
kw_only=True,
196+
omit_defaults=True,
197+
rename="kebab",
198+
forbid_unknown_fields=True,
199+
):
194200
"""
195201
Base schema class that extends msgspec.Struct.
196202
@@ -202,6 +208,13 @@ class MySchema(Schema):
202208
203209
Instead of wrapping msgspec.Struct types.
204210
Most schemas use kebab-case renaming by default.
211+
212+
By default, forbid_unknown_fields is True, meaning extra fields
213+
will cause validation errors. Child classes can override this by
214+
setting forbid_unknown_fields=False in their class definition:
215+
216+
class MySchema(Schema, forbid_unknown_fields=False):
217+
foo: str
205218
"""
206219

207220
@classmethod

0 commit comments

Comments
 (0)