Skip to content

Commit

Permalink
allow additional for manifest object
Browse files Browse the repository at this point in the history
  • Loading branch information
ChenyuLInx committed Dec 13, 2024
1 parent 7acd049 commit cd64b89
Show file tree
Hide file tree
Showing 8 changed files with 35 additions and 18 deletions.
2 changes: 1 addition & 1 deletion .changes/unreleased/Under the Hood-20241211-160216.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
kind: Under the Hood
body: Allow additional property on Model and SourceDefinition to avoid artifact read
body: Allow additional property on manifest when loading
problem
time: 2024-12-11T16:02:16.551106-08:00
custom:
Expand Down
9 changes: 1 addition & 8 deletions core/dbt/artifacts/resources/v1/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
)
from dbt.artifacts.resources.v1.config import NodeConfig
from dbt_common.contracts.config.base import MergeBehavior
from dbt_common.contracts.config.properties import AdditionalPropertiesAllowed
from dbt_common.contracts.constraints import ModelLevelConstraint
from dbt_common.dataclass_schema import dbtClassMixin

Expand All @@ -36,7 +35,7 @@ class TimeSpine(dbtClassMixin):


@dataclass
class Model(AdditionalPropertiesAllowed, CompiledResource):
class Model(CompiledResource):
resource_type: Literal[NodeType.Model]
access: AccessType = AccessType.Protected
config: ModelConfig = field(default_factory=ModelConfig)
Expand All @@ -52,10 +51,4 @@ def __post_serialize__(self, dct: Dict, context: Optional[Dict] = None):
dct = super().__post_serialize__(dct, context)
if context and context.get("artifact") and "defer_relation" in dct:
del dct["defer_relation"]

# delete extra keys that should't be serialized
if self.extra:
for key, _ in self.extra.items():
if key in dct:
del dct[key]
return dct
2 changes: 1 addition & 1 deletion core/dbt/artifacts/resources/v1/source_definition.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class ParsedSourceMandatory(GraphResource, HasRelationMetadata):


@dataclass
class SourceDefinition(AdditionalPropertiesAllowed, ParsedSourceMandatory):
class SourceDefinition(ParsedSourceMandatory):
quoting: Quoting = field(default_factory=Quoting)
loaded_at_field: Optional[str] = None
freshness: Optional[FreshnessThreshold] = None
Expand Down
27 changes: 27 additions & 0 deletions core/dbt/contracts/graph/manifest.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
Union,
)

import jsonschema
from jsonschema import ValidationError
from typing_extensions import Protocol

import dbt_common.exceptions
Expand Down Expand Up @@ -936,6 +938,31 @@ class Manifest(MacroMethods, dbtClassMixin):
metadata={"serialize": lambda x: None, "deserialize": lambda x: None},
)

# This and the following methods can be refacong into a mixin
# and we should do so next time we do it for another artifact.
@classmethod
def validate(cls, data: Any) -> None:
json_schema = cls.json_schema()
cls._allow_additional_recursive(cls, json_schema)
validator = jsonschema.Draft7Validator(json_schema)
error = next(iter(validator.iter_errors(data)), None)
if error is not None:
raise ValidationError.create_from(error) from error

@staticmethod
def _allow_additional_recursive(cls, dct: Dict[str, Any]):
if (
"proproties" in dct
and "additionalProperties" in dct
and dct["additionalProperties"] is False
):
dct["additionalProperties"] = True
for k, v in dct.items():
if isinstance(v, dict):
dct[k] = cls._allow_additional_recursive(dct.get(k, {}))
if isinstance(v, list):
dct[k] = [cls._allow_additional_recursive(i) for i in v]

def __pre_serialize__(self, context: Optional[Dict] = None):
# serialization won't work with anything except an empty source_patches because
# tuple keys are not supported, so ensure it's empty
Expand Down
6 changes: 0 additions & 6 deletions core/dbt/contracts/graph/nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -1371,12 +1371,6 @@ def search_name(self):
def group(self):
return None

def __post_serialize__(self, dct: Dict, context: Optional[Dict] = None):
dct = super().__post_serialize__(dct, context)
if "_event_status" in dct:
del dct["_event_status"]
return dct


# ====================================
# Exposure node
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/contracts/graph/test_nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ def test_extra_fields_model_okay(minimal_uncompiled_dict):
extra = minimal_uncompiled_dict
extra["notvalid"] = "nope"
# Model still load fine with extra fields
assert ModelNode.from_dict(extra)._extra == {"notvalid": "nope"}
ModelNode.from_dict(extra)


def test_invalid_bad_type_model(minimal_uncompiled_dict):
Expand Down
3 changes: 2 additions & 1 deletion tests/unit/contracts/graph/test_nodes_parsed.py
Original file line number Diff line number Diff line change
Expand Up @@ -1950,6 +1950,7 @@ def test_basic_source_definition(
node = basic_parsed_source_definition_object
node_dict = basic_parsed_source_definition_dict
minimum = minimum_parsed_source_definition_dict

assert_symmetric(node.to_resource(), node_dict, SourceDefinitionResource)

assert node.is_ephemeral is False
Expand All @@ -1964,7 +1965,7 @@ def test_extra_fields_source_definition_okay(minimum_parsed_source_definition_di
extra = minimum_parsed_source_definition_dict
extra["notvalid"] = "nope"
# Model still load fine with extra fields
assert SourceDefinition.from_dict(extra)._extra == {"notvalid": "nope"}
SourceDefinition.from_dict(extra)


def test_invalid_missing(minimum_parsed_source_definition_dict):
Expand Down
2 changes: 2 additions & 0 deletions tests/unit/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,9 +197,11 @@ def assert_from_dict(obj, dct, cls=None):
cls.validate(dct)

obj_from_dict = cls.from_dict(dct)

if hasattr(obj, "created_at"):
obj_from_dict.created_at = 1
obj.created_at = 1

assert obj_from_dict == obj


Expand Down

0 comments on commit cd64b89

Please sign in to comment.