Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix(eos_designs): Invalid class returned from snmp_settings.vrfs #5035

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
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
Loading