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

Quick fix for circular imports #325

Merged
merged 3 commits into from
Mar 23, 2021
Merged

Quick fix for circular imports #325

merged 3 commits into from
Mar 23, 2021

Conversation

max-veit
Copy link
Contributor

Fix #294

I can't guarantee that this fixes all our circular import problems, but I think this addresses the one triggered by trying to run

from rascal.models import <something>

I'm not sure how exactly to test this -- it pops up pretty randomly when changing something in the Python code, and depends on import ordering (which is a nightmare), so somehow it has not been caught by the Python binding tests until now. Suggestions welcome.

@max-veit
Copy link
Contributor Author

And a note for the future: This whole mess was mostly caused by creating "convenience imports" that just rename existing functions in librascal. Let's try to avoid those and try to keep our internal dependency graph as simple as possible to avoid running into such issues again.

@max-veit max-veit requested review from agoscinski and Luthaf March 22, 2021 18:29
@max-veit
Copy link
Contributor Author

Please note that I had to take the SparsePoints alias-import out of bindings/rascal/models/__init__.py in order to resolve the circular import, so you can no longer just do from rascal.models import SparsePoints. The correct way to import these is now from rascal.models.sparse_points import SparsePoints. The examples and tests have been updated accordingly.

Note that this style of "aliasing" (importing) objects into a higher package level's __init__.py file is generally discouraged for exactly this reason, so eventually we'll want to take the rest of those alias-imports out, especially if they cause problems in the future.

Copy link
Contributor

@Luthaf Luthaf left a comment

Choose a reason for hiding this comment

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

The fix looks good as far as fixing circular imports go.

Note that this style of "aliasing" (importing) objects into a higher package level's init.py file is generally discouraged for exactly this reason, so eventually we'll want to take the rest of those alias-imports out, especially if they cause problems in the future.

What makes you think this is discouraged?

I generally prefer to use it as much as possible because it is nicer from the user perspective, which in turns force me to structure my classes and modules as a cycle-free graph (usually a tree). If necessary, I then use late imports (directly inside class methods) to break up module cycles. At the same time, I've mostly worked with relatively small python packages, so I'd like to read more on this subject if you have links!

bindings/rascal/utils/__init__.py Outdated Show resolved Hide resolved
bindings/rascal/utils/__init__.py Outdated Show resolved Hide resolved
"""Miscellaneous useful utilities"""


def is_notebook():
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't really see why we have this function in librascal ... Is this used anywhere else in the code or is this just a convenience function for librascal users?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It was used to decide whether to import tqdm in the command-line version or the notebook version, in one of the tutorials (yet to be merged, I think). I know we wanted to make the dependency on tqdm optional, but if it is present, we will probably want to import the appropriate version.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It was one of the i-PI tutorials actually, see e.g.: af2c7bd

Copy link
Contributor

Choose a reason for hiding this comment

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

Ok, ideally I would move this function to the tutorial code itself, and not inside librascal. But this can happen as part of #307

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That PR is scheduled to be merged soon anyway (I split this fix off from that PR because I thought it was more urgent)

Copy link
Contributor

@Luthaf Luthaf left a comment

Choose a reason for hiding this comment

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

Looks good! Feel free to merge once CI is happy!

Also, please squash the commits before or during merge 😃

@max-veit
Copy link
Contributor Author

What makes you think this is discouraged?

I might be misremembering a blog post or StackOverflow answer I read once, which of course I can't find again. Although I think this one does a pretty good job of explaining the issue and various fixes.

I generally prefer to use it as much as possible because it is nicer from the user perspective, which in turns force me to structure my classes and modules as a cycle-free graph (usually a tree).

Agree, I was hoping this was one step towards making our dependency graph easier to understand.

If necessary, I then use late imports (directly inside class methods) to break up module cycles. At the same time, I've mostly worked with relatively small python packages, so I'd like to read more on this subject if you have links!

I don't like late imports because then you can no longer see the module's dependencies just by looking at the top of the file. Note that there were already several instances of SparsePoints being imported within a function, which might actually make things worse if the import error is only triggered on running a function... Anyway, I took those out, and since SparsePoints is a fairly low-level object anyway I don't think we really need to expose it in models.

max-veit and others added 3 commits March 23, 2021 19:25
fix #294

Still need to update some examples, since this required taking
some "convenience imports" out of the __init__ files
@max-veit max-veit force-pushed the bugfix/circular-imports branch from 251a322 to ac8002c Compare March 23, 2021 18:27
@max-veit max-veit merged commit 1ae879c into master Mar 23, 2021
@max-veit max-veit deleted the bugfix/circular-imports branch March 25, 2021 11:06
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.

Circular python import of SparsePoints
2 participants