-
Notifications
You must be signed in to change notification settings - Fork 9
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
Refactors recipe conversion work #22
Conversation
- Recipe conversion tooling is now broken-out into a subclass of the original `RecipeParser` - This keeps the `RecipeParser file from getting any bigger and will allow some future flexibility in maintaining the conversion process - Test files are broken up accordingly - Adds `conftest.py` to share testing utilities across multiple unit test files
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a small change in how you define these helpers, they would work well as fixtures with indirect parameters, or as utility functions living outside of the magic conftest module.
@schuylermartin45 I think the file is missing 🤗 |
This is what I get for quickly doing |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The tests seem to have trouble importing the new module, not sure why it wouldn't, maybe the indirection via make?
I'm not sure if I follow, it looks like the only test failing is the rattler-build test that's probably a rattler issue. |
it is not really a problem with rattler, that is due the name path being too long if you can try simply reduce the name of the file, that should do it |
return RecipeParser(recipe) | ||
|
||
|
||
def load_recipe_convert(file_name: str) -> RecipeParserConvert: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
to load files for tests you can use pytest-datadir
if you wish, that would simplify a few things
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TIL, I'll have to look into that. I was not aware of that plugin.
return f.read() | ||
|
||
|
||
def load_recipe(file_name: str) -> RecipeParser: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if you prefer you can use factories as fixtures here and remove the __init__.py
and this bit here, and put everything in the conftest.py
example:
https://docs.pytest.org/en/7.1.x/how-to/fixtures.html#factories-as-fixtures
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I appreciate and am aware, but I wanted to keep this PR smaller and focus refactoring one thing.
I've been pinning it on rattler as I think it is a change between versions. That path is not new and has worked in previous CI builds. |
Well good news, I finally found time to look into :). From what I can tell, my initial gut feeling looks correct and I've filed an issue with rattler-build. Version |
class RecipeParserConvert(RecipeParser): | ||
""" | ||
Extension of the base RecipeParser class to enables upgrading recipes from the old to new format. | ||
This was originally part of the RecipeParser class but was broken-out for easier maintenance. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How does breaking this out like this offer easier maintenance?
As far as I can tell the maintenance issue here is caused by the high cyclomatic complexity of the render_to_new_recipe_format
method. A good rule of thumb is to aim for a complexity of 15 or lower but, as currently written, this method has a complexity of 49, much too high.
Furthermore if it is this easy to break this into a new class (and since self
is only referenced once in the method) it would seem to me that this deserves to live as a function and not nested within a larger object:
def convert_to_new_recipe_format(old_recipe: RecipeParser) -> tuple[str, MessageTable]:
new_recipe = RecipeParser(self.render())
...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The subclass is mostly there to make the static analyzer happy with accessing underscore functions. I also have future plans to break this up into more functions under this new "namespace".
As for maintenance, the original parser class is huge. It used to be an even larger class file and was split-up into a few supporting files and classes.
Out of curiosity, how did you calculate that? Do you have a plugin? I also think some of this logic is unavoidable with the nature of the conversion work. There is a lot of "if this, then that" to perform.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let me go and clean up a bit more here. I think I can have the message tracking and a few other pieces of state tracked as part of the class member that will simplify some of the ick.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have McCabe linters enabled in my IDE. Since you're using pylint
you can use https://pypi.org/project/pylint-mccabe/.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just posted a few commits that clean-up the inner-function and state usage. If you're okay with it, I'd like to look into this mccabe
integration after this PR and #29 get merged in. I think that might cause a bigger refactor
Co-authored-by: Ken Odegard <[email protected]>
Co-authored-by: Ken Odegard <[email protected]>
- Moves state stored in `render_to_new_recipe_format()` to simplify logic - Moves inner-functions of `render_to_new_recipe_format()` to private members of the `RecipeParserConvert` subclass
@@ -2,6 +2,7 @@ | |||
File: convert.py | |||
Description: CLI for converting an old recipe file to the "new" format. | |||
""" | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
black
got an update in pre-commit
the other day, hence the change here and in other files.
RecipeParser
There are no net logic changes, only code has been moved.