Skip to content

Commit

Permalink
Fix(eos_designs): Invalid class returned from snmp_settings.vrfs (#5035
Browse files Browse the repository at this point in the history
…) (#5042)
  • Loading branch information
carlbuchmann authored Feb 14, 2025
1 parent 293c927 commit 8857431
Show file tree
Hide file tree
Showing 7 changed files with 535 additions and 1,466 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ ip name-server vrf MGMT 192.168.42.40
ip name-server vrf VRF2 192.168.42.40
ip name-server vrf MGMT 192.168.42.50
!
snmp-server vrf foo
snmp-server vrf bar
!
vrf instance MGMT
!
management api http-commands
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@ management_api_http:
metadata:
fabric_name: EOS_DESIGNS_UNIT_TESTS
service_routing_protocols_model: multi-agent
snmp_server:
vrfs:
- name: foo
enable: true
- name: bar
enable: true
transceiver_qsfp_default_mode_4x10: true
vlan_internal_order:
allocation: ascending
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,3 +107,14 @@ csc_1_domain_list:
- foo.foo
- bar.bar
csc_2_domain_list: null

# Testing a model where we are using a $ref for the entire schema, so the classes will be cli_gen classes.
snmp_settings:
vrfs:
- name: foo
enable: true

csc_1_snmp_server:
vrfs:
- name: bar
enable: true
1,924 changes: 486 additions & 1,438 deletions python-avd/pyavd/_eos_designs/schema/__init__.py

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ def _snmp_local_interfaces(self: AvdStructuredConfigBaseProtocol, source_interfa
for local_interface in local_interfaces:
self.structured_config.snmp_server.local_interfaces.append(EosCliConfigGen.SnmpServer.LocalInterfacesItem(**local_interface))

def _snmp_vrfs(self: AvdStructuredConfigBaseProtocol, snmp_settings: EosDesigns.SnmpSettings) -> EosDesigns.SnmpSettings.Vrfs:
def _snmp_vrfs(self: AvdStructuredConfigBaseProtocol, snmp_settings: EosDesigns.SnmpSettings) -> None:
"""
Set list of dicts for enabling/disabling SNMP for VRFs.
Expand Down
52 changes: 25 additions & 27 deletions python-avd/schema_tools/generate_classes/class_src_gen.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,8 @@ class SrcGenList(SrcGenBase):
schema: AvdSchemaList

def get_type(self) -> str:
if self.schema.field_ref:
return generate_class_name_from_ref(self.schema.field_ref)
return self.get_class_name()

def generate_class_src(self, schema: AvdSchemaList, class_name: str | None = None) -> SrcData:
Expand All @@ -176,14 +178,11 @@ def generate_class_src(self, schema: AvdSchemaList, class_name: str | None = Non
return SrcData(field=self.field_src, cls=self.class_src, item_classes=self.get_item_classes())

@cached_property
def class_src(self) -> ListSrc:
def class_src(self) -> ListSrc | None:
"""Returns ListSrc for the given schema to be used for the class definition in the parent object."""
if self.schema.field_ref:
# TODO: Currently we only skip resolving ref for indexedlists. Improve this.
return ListSrc(
name=self.get_class_name(),
base_class=generate_class_name_from_ref(self.schema.field_ref),
)
return None

class_name = self.get_class_name()
if self.schema.items is None:
Expand Down Expand Up @@ -237,7 +236,9 @@ def get_item_classes(self) -> list[ModelSrc | ListSrc] | None:
@cached_property
def type_hints_src(self) -> list[FieldTypeHintSrc]:
"""Returns a list of FieldTypeHintSrc representing the type hints for this schema."""
return [FieldTypeHintSrc(field_type=self.class_src.name)]
if self.schema.field_ref:
return [FieldTypeHintSrc(field_type=generate_class_name_from_ref(self.schema.field_ref))]
return super().type_hints_src

def get_default(self) -> str | None:
"""Returns the default value from the schema as a source code string."""
Expand All @@ -261,11 +262,11 @@ def get_primary_key_field_name(self) -> str | None:
return primary_key

def get_description(self) -> str:
descriptions = [super().get_description(), self.class_src.description]
descriptions = [super().get_description(), cls_src.description if (cls_src := self.class_src) is not None else None]
return "\n\n".join(description for description in descriptions if description is not None)

def get_imports(self) -> set[str]:
"""Return a set of strings with Python imports that are needed for this class."""
"""Return a set of strings with Python imports that are needed for this class or field."""
imports = set()
if self.schema.items is None:
imports.add("from typing import Any")
Expand All @@ -279,21 +280,26 @@ class SrcGenDict(SrcGenBase):
schema: AvdSchemaDict

def get_type(self) -> str:
if self.schema.field_ref:
return generate_class_name_from_ref(self.schema.field_ref)
if self.class_src is not None:
return self.get_class_name()
return "dict"

@cached_property
def type_hints_src(self) -> list[FieldTypeHintSrc]:
"""Returns a list of FieldTypeHintSrc representing the type hints for this schema."""
if self.schema.field_ref:
return [FieldTypeHintSrc(field_type=generate_class_name_from_ref(self.schema.field_ref))]
return super().type_hints_src

@cached_property
def class_src(self) -> ModelSrc | None:
"""Returns ModelSrc for the given schema to be used for the class definition in the parent object."""
if not self.schema.keys:
if not self.schema.field_ref:
return None

classes, fields = [], []
if self.schema.field_ref or not self.schema.keys:
return None

else:
classes, fields = self.get_children_classes_and_fields()
classes, fields = self.get_children_classes_and_fields()
return ModelSrc(
name=self.get_class_name(),
base_classes=self.get_base_classes(),
Expand All @@ -305,20 +311,12 @@ def class_src(self) -> ModelSrc | None:
)

def get_base_classes(self) -> list[str]:
"""Return a list of base classes. Only used if there is an unresolved $ref in the schema."""
if not self.schema.field_ref:
return []

return [generate_class_name_from_ref(self.schema.field_ref)]
"""Return a list of base classes. Only used by the root dict class."""
return []

def get_imports(self) -> set[str]:
"""Return a set of strings with Python imports that are needed for this class."""
imports = set()
if self.schema.field_ref:
schema_name = self.schema.field_ref.split("#", maxsplit=1)[0]
imports.add(f"from pyavd._{schema_name}.schema import {generate_class_name(schema_name)}")

return imports
"""Return a set of strings with Python imports that are needed for this class or field. Only used for rootdict."""
return set()

def get_children_classes_and_fields(self) -> tuple[list[ModelSrc | ListSrc], list[FieldSrc]]:
"""Return lists of ModelSrc and FieldSrc for any nested fields."""
Expand Down
3 changes: 3 additions & 0 deletions python-avd/schema_tools/generate_classes/src_generators.py
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,9 @@ def get_imports(self) -> set:
if "Literal[" in self.field_type:
imports.add("from typing import Literal")

if self.field_type.startswith("EosCliConfigGen."):
imports.add("from pyavd._eos_cli_config_gen.schema import EosCliConfigGen")

if not self.annotations:
return imports

Expand Down

0 comments on commit 8857431

Please sign in to comment.