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

Resolve Cyclic Imports #1500

Closed
wants to merge 78 commits into from
Closed

Resolve Cyclic Imports #1500

wants to merge 78 commits into from

Conversation

Yuyuutsu
Copy link
Contributor

@Yuyuutsu Yuyuutsu commented Sep 6, 2024

What is the context of this PR?

This PR refactors VSR and RuleEvaluator to resolve most of the Cyclic imports found after upgrading Pylint to version v3.2.5.

How to review

Read through the changes and check if runner works as expected.
Check if tests pass locally

Checklist

  • New static content marked up for translation
  • Newly defined schema content included in eq-translations repo

Yuyuutsu and others added 30 commits September 6, 2024 05:43
…r to have use_default_answer=True

Signed-off-by: Yuyutsu Rai <[email protected]>
@@ -310,20 +310,25 @@ def _get_period_range_for_single_date(
date_to: Mapping[str, dict],
) -> timedelta:
list_item_id = self.location.list_item_id if self.location else None
value_source_resolver = ValueSourceResolver(
rule_evaluator = RuleEvaluator(
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not sure this makes sense at the moment, the rule evaluator now has a value source resolver but you're still passing both to the field handler?

Copy link
Contributor Author

@Yuyuutsu Yuyuutsu Nov 18, 2024

Choose a reason for hiding this comment

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

I was not sure if it was okay to remove but now removed VSR from FieldHandler.



@dataclass
class Resolver(ABC):
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need this abstract class? I don't think this makes sense since there is only one instance of a "Resolver" class? So all of the stuff from ValueSourceResolver would be in here if we did this/nothing would be overridden since they are be the same?

Copy link
Contributor Author

@Yuyuutsu Yuyuutsu Nov 18, 2024

Choose a reason for hiding this comment

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

I implemented it as a pre measure and was not sure how we wanted to approach the type hinting. I have updated VSR and RuleEvaluator, where RuleEvaluator uses type annotations for the type hinting.

@@ -480,32 +480,47 @@ def get_answer_fields(
if block_ids_by_section:
block_ids = get_flattened_mapping_values(block_ids_by_section)

def _get_value_source_resolver(list_item: str | None = None) -> ValueSourceResolver:
def _get_value_source_resolver(
Copy link
Contributor

Choose a reason for hiding this comment

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

There are still some inconsistencies taking this approach, as we seem to mix where we call rule evaluator and where we are calling value source resolver directly. For example here, if we were to do this we'd be better of getting the rule_evaluator as it already has a value source resolver.

Copy link
Contributor

Choose a reason for hiding this comment

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

Probably worth having a chat about this approach with the team anyway.

@@ -480,32 +480,47 @@ def get_answer_fields(
if block_ids_by_section:
block_ids = get_flattened_mapping_values(block_ids_by_section)

def _get_value_source_resolver(list_item: str | None = None) -> ValueSourceResolver:
def _get_value_source_resolver(
Copy link
Contributor

@petechd petechd Nov 21, 2024

Choose a reason for hiding this comment

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

If this private method does not use vars from the higher scope of the class implicitly (is only passing parameters explicitly), there is no reason why to nest it inside and in the middle of another method of this class. Should be separated out from the parent method.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think it still uses the higher scope of the function. If not I think the function would not be needed

@@ -50,6 +45,7 @@ def __post_init__(self) -> None:
self.operations = Operations(
language=self.language, schema=self.schema, renderer=renderer
)
self.value_source_resolver = self.value_source_resolver
Copy link
Contributor

Choose a reason for hiding this comment

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

Does this statement make sense?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Technically, yes 😂 . Removed 👍

@@ -272,6 +272,14 @@ def _resolve_summary_with_calculation(
data_stores=self.data_stores,
location=self.location,
routing_path_block_ids=self.routing_path_block_ids,
value_source_resolver=ValueSourceResolver(
Copy link
Contributor

Choose a reason for hiding this comment

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

We definitely don't want to instantiate another ValueSourceResolver inside the ValueSourceResolver class instance.

Copy link
Contributor

Choose a reason for hiding this comment

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

I agree with @berroar this probably needs some more thought and some kind of structured approach/plan/proposal.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah this felt akward to do when refactoring, Will have a look

location=this_location,
routing_path_block_ids=block_ids_for_dependencies,
value_source_resolver=ValueSourceResolver(
Copy link
Contributor

@petechd petechd Nov 21, 2024

Choose a reason for hiding this comment

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

We could probably call the same instance of VSR here and on line 245, if we initialised VSR when the PathFinder class instance is first created, but that requires some more thought as we would need to refactor how we initialise PathFinder class.

Copy link
Contributor Author

@Yuyuutsu Yuyuutsu Nov 25, 2024

Choose a reason for hiding this comment

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

Will bring this up in Tech Session once everyone has had a look

Copy link
Contributor

@liamtoozer liamtoozer left a comment

Choose a reason for hiding this comment

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

Great work 👍 I agree though that we might want to take a bit more time and look at some of the alternatives like breaking down some of the bigger classes into smaller ones to get around the cyclic imports. Appreciate this is a lot more complex though and might not be as straightforward as that. Maybe a spike ticket to look at some possible solutions, with this being one of them?

@Yuyuutsu
Copy link
Contributor Author

Yuyuutsu commented Dec 2, 2024

Yeah I agree, as this approach still has its issues and would be better if we can find another approach. - Closing PR

@Yuyuutsu Yuyuutsu closed this Dec 2, 2024
@Yuyuutsu
Copy link
Contributor Author

Yuyuutsu commented Dec 2, 2024

NEW Investigation card: https://jira.ons.gov.uk/browse/ECI-1498

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.

4 participants