Skip to content

refactor: introduce AbstractResource base class for resource interface - #175

Open
phantomii wants to merge 1 commit into
masterfrom
improve-import-resource-class
Open

refactor: introduce AbstractResource base class for resource interface#175
phantomii wants to merge 1 commit into
masterfrom
improve-import-resource-class

Conversation

@phantomii

@phantomii phantomii commented Oct 22, 2025

Copy link
Copy Markdown
Member
  • Create AbstractResource class defining common resource interface
  • Update Resource class to inherit from AbstractResource
  • Refactor ImportedResource to implement AbstractResource interface
  • Remove __getattr__ delegation in favor of explicit method implementations
  • Improve code architecture and type safety for resource management

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @phantomii, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly refactors the resource management architecture by introducing a new AbstractResource base class. This change standardizes the interface for various resource types, ensuring consistent behavior and improving type safety across the system. The Resource and ImportedResource classes have been updated to conform to this new abstract interface, with ImportedResource specifically moving from dynamic attribute delegation to explicit method implementations for better maintainability and predictability.

Highlights

  • New Abstract Base Class: Introduced an AbstractResource class using Python's abc module to define a common interface for resource management.
  • Resource Class Update: The existing Resource class has been updated to inherit from the newly created AbstractResource.
  • ImportedResource Refactoring: The ImportedResource class now explicitly implements the AbstractResource interface, moving away from implicit delegation.
  • Removed getattr: The __getattr__ method has been removed from ImportedResource in favor of explicit method implementations, improving type safety and clarity.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces an AbstractResource base class to establish a common interface for resource objects, which is a positive step for the codebase's architecture. The refactoring of Resource and ImportedResource to use this new abstract class, and the removal of __getattr__ in favor of explicit delegation, are good changes for clarity and type safety. My review includes suggestions to further improve type safety by adding missing type hints, which aligns with the goals of this PR. I have also identified a critical bug in the implementation of ImportedResource.get_parameter_value that results from the refactoring, and I've provided a suggested fix.

Comment on lines 824 to 825
def get_parameter_value(self, parameter):
return type(self._resource).get_parameter_value(self, parameter)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

This implementation is broken after removing __getattr__. The call type(self._resource).get_parameter_value(self, parameter) will execute Resource.get_parameter_value on an ImportedResource instance (self). This will raise an AttributeError because ImportedResource does not have attributes like actual_resource or __allowed_methods_from_manifest__ which are accessed within that method.

A simple delegation to self._resource.get_parameter_value(parameter) is also incorrect because the resource name check inside it would use the original resource's name instead of the imported resource's name.

I suggest reconstructing the parameter string to use the original resource's name and then delegating the call. This correctly reuses the logic without code duplication and fixes the bug.

Suggested change
def get_parameter_value(self, parameter):
return type(self._resource).get_parameter_value(self, parameter)
def get_parameter_value(self, parameter):
parts = parameter.split(":")
resource_name = parts[0][1:]
if resource_name != self.name:
raise ValueError(
f"Resource name `{resource_name}` does not match the"
f" current resource name `{self.name}`"
)
new_parameter = f"${self._resource.name}:{':'.join(parts[1:])}"
return self._resource.get_parameter_value(new_parameter)

Comment on lines +414 to +465
class AbstractResource(metaclass=abc.ABCMeta):

@abc.abstractmethod
def get_uri(self):
raise NotImplementedError("Not implemented")

@abc.abstractmethod
def to_str(self, field: str) -> str:
raise NotImplementedError("Not implemented")

@abc.abstractmethod
def get_parameter_value(self, parameter):
raise NotImplementedError("Not implemented")

@abc.abstractmethod
def get_actual_state_safe(self):
raise NotImplementedError("Not implemented")

@abc.abstractmethod
def render_target_state(self, engine=None):
raise NotImplementedError("Not implemented")

@property
@abc.abstractmethod
def link(self):
raise NotImplementedError("Not implemented")

@abc.abstractmethod
def get_provider_element(self):
raise NotImplementedError("Not implemented")

@property
@abc.abstractmethod
def kind(self):
raise NotImplementedError("Not implemented")

@abc.abstractmethod
def calculate_full_hash(self):
raise NotImplementedError("Not implemented")

@abc.abstractmethod
def actualize(self):
raise NotImplementedError("Not implemented")

@abc.abstractmethod
def delete(self, session=None):
raise NotImplementedError("Not implemented")

@property
@abc.abstractmethod
def original(self):
raise NotImplementedError("Not implemented")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To improve type safety and align with the PR's goal, it would be beneficial to add type hints to the abstract methods. This will make the interface clearer for implementers. You may need to import typing as tp and use forward references (string quotes) for types defined later in the file or for circular dependencies.

class AbstractResource(metaclass=abc.ABCMeta):

    @abc.abstractmethod
    def get_uri(self) -> str:
        raise NotImplementedError("Not implemented")

    @abc.abstractmethod
    def to_str(self, field: str) -> str:
        raise NotImplementedError("Not implemented")

    @abc.abstractmethod
    def get_parameter_value(self, parameter: str) -> 'tp.Any':
        raise NotImplementedError("Not implemented")

    @abc.abstractmethod
    def get_actual_state_safe(self) -> dict:
        raise NotImplementedError("Not implemented")

    @abc.abstractmethod
    def render_target_state(self, engine: 'ElementEngine' | None = None) -> dict:
        raise NotImplementedError("Not implemented")

    @property
    @abc.abstractmethod
    def link(self) -> str:
        raise NotImplementedError("Not implemented")

    @abc.abstractmethod
    def get_provider_element(self) -> 'Element':
        raise NotImplementedError("Not implemented")

    @property
    @abc.abstractmethod
    def kind(self) -> str:
        raise NotImplementedError("Not implemented")

    @abc.abstractmethod
    def calculate_full_hash(self) -> str:
        raise NotImplementedError("Not implemented")

    @abc.abstractmethod
    def actualize(self) -> None:
        raise NotImplementedError("Not implemented")

    @abc.abstractmethod
    def delete(self, session: 'tp.Any' | None = None) -> None:
        raise NotImplementedError("Not implemented")

    @property
    @abc.abstractmethod
    def original(self) -> 'AbstractResource':
        raise NotImplementedError("Not implemented")

Comment on lines +839 to +869
def get_uri(self):
return self._resource.get_uri()

def to_str(self, field: str) -> str:
return self._resource.to_str(field)

def get_actual_state_safe(self):
return self._resource.get_actual_state_safe()

def render_target_state(self, engine=None):
return self._resource.render_target_state(engine)

def get_provider_element(self):
return self._resource.get_provider_element()

@property
def kind(self):
return self._resource.kind

def calculate_full_hash(self):
return self._resource.calculate_full_hash()

def actualize(self):
return self._resource.actualize()

def delete(self, session=None):
return self._resource.delete(session)

@property
def original(self):
return self._resource

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

For consistency and improved type safety, consider adding type hints to these delegated methods, similar to how to_str is typed. This will make the ImportedResource class more robust and easier to use correctly. You may need to import typing as tp.

    def get_uri(self) -> str:
        return self._resource.get_uri()

    def to_str(self, field: str) -> str:
        return self._resource.to_str(field)

    def get_actual_state_safe(self) -> dict:
        return self._resource.get_actual_state_safe()

    def render_target_state(self, engine: 'ElementEngine' | None = None) -> dict:
        return self._resource.render_target_state(engine)

    def get_provider_element(self) -> 'Element':
        return self._resource.get_provider_element()

    @property
    def kind(self) -> str:
        return self._resource.kind

    def calculate_full_hash(self) -> str:
        return self._resource.calculate_full_hash()

    def actualize(self) -> None:
        return self._resource.actualize()

    def delete(self, session: 'tp.Any' | None = None) -> None:
        return self._resource.delete(session)

    @property
    def original(self) -> 'Resource':
        return self._resource

- Create AbstractResource class defining common resource interface
- Update Resource class to inherit from AbstractResource
- Refactor ImportedResource to implement AbstractResource interface
- Remove __getattr__ delegation in favor of explicit method implementations
- Improve code architecture and type safety for resource management
@phantomii
phantomii force-pushed the improve-import-resource-class branch from 5dc1238 to 97bffa2 Compare March 20, 2026 10:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant