Skip to content

Switch Python import machinery to focus primarily on Python modules #1176

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

Merged
merged 5 commits into from
Dec 23, 2024

Conversation

chrisrink10
Copy link
Member

@chrisrink10 chrisrink10 commented Dec 13, 2024

Possible alternative solution to #1165 and #1155

This PR changes the Python importlib machinery for Basilisp to simply focus on importing modules, without getting itself too mixed up in the business of figuring out what a namespace is actually called from the module name. When importlib.import_module is called, Basilisp just figures out the location of the module on disk and starts loading it up as if it were a Basilisp module. It sets the newly introduced basilisp.core/*import-module* dynamic Var to the value of the importing module and lets the Basilisp runtime fetch that value down and attach it to a new namespace if and when it is appropriate to do so.

There may be some unintended side effects here for strange cases, so noting those here for now:

  • If multiple namespaces are created within a single invocation of import.import_lib (excluding recursive calls for other imports or requires), a module could be attached to multiple namespaces. I'm not sure if that's actually an issue, but it's certainly bizarre and could lead to some unintended consequences. That being said, I don't really think it is a priority for the project to support this style of bizarre metaprogramming, so that may be fine.
  • Namespace names and module names aren't necessarily "linked" anymore, although they never were linked directly before due to the required munging of module names for Python code.
  • Others?

Copy link
Member Author

Choose a reason for hiding this comment

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

I lifted these tests from #1172 with some minor modifications (cc @ikappaki).

In particular, every test removes the namespace before the test runs to avoid other tests clashing with these.

Copy link
Contributor

Choose a reason for hiding this comment

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

Tests looks good.

Out of interest, would it be better to clean up the namespace after the test has run?

assert result.ret != 0
result.stdout.fnmatch_lines(
[
"*basilisp.lang.compiler.exception.CompilerException: unable to resolve symbol 'require'*"
Copy link
Member Author

Choose a reason for hiding this comment

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

Tweaked this check which now matches both how things work both in Basilisp at the REPL as well as in Clojure (I believe).

Comment on lines 190 to 199
if not paths:
top = None
for p in file.parents:
if _is_package(p):
top = p
else:
break

if top is None or top == file.parent:
return [file.stem]
Copy link
Member Author

Choose a reason for hiding this comment

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

I'm not convinced this branch is still necessary.

@chrisrink10 chrisrink10 marked this pull request as ready for review December 20, 2024 17:01
@chrisrink10
Copy link
Member Author

I'm hoping this can fix the issues documented in #1155 and #1165 in an alternative way to PR #1172. The idea being that we just let the namespace control its own name rather than trying to the name out from a filesystem location. @ikappaki take a look when you have a minute and let me know what you think.

@ikappaki
Copy link
Contributor

I'm hoping this can fix the issues documented in #1155 and #1165 in an alternative way to PR #1172. The idea being that we just let the namespace control its own name rather than trying to the name out from a filesystem location. @ikappaki take a look when you have a minute and let me know what you think.

Hi @chrisrink10, I'm not able to follow up on the particulars in detail of what the updated code does, but your description makes sense. My only concern is whether a __init__.py file is still needed at the root of the subtree. The tests might not cover this, as I believe pytester.runpytest automatically creates one at the top of the temporary directory.

Could you also consider updating the docs with the section I provided in the other patch? Feel free to make any extensive adjustments you find necessary.

I'll test this PR with various project configurations and report my findings here later today.

Thanks

@ikappaki
Copy link
Contributor

I'll test this PR with various project configurations and report my findings here later today.

Tested with

  1. hiccup port (clojure test setup), required -p test. Verified functionality with both basilisp test and basilisp nrepl-server
  2. basilisp-kernel (Basilisp tests setup).

Thus, everything appears to be working fie.

Thanks

@chrisrink10
Copy link
Member Author

Could you also consider updating the docs with the section I provided in the other patch? Feel free to make any extensive adjustments you find necessary.

Yes and thank you for the reminder. I have incorporated your suggestions as written.

@chrisrink10 chrisrink10 merged commit 54b340a into main Dec 23, 2024
12 checks passed
@chrisrink10 chrisrink10 deleted the feature/use-module branch December 23, 2024 15:10
chrisrink10 pushed a commit that referenced this pull request Feb 10, 2025
Hi,

could you please review patch to fix a likely regression issue where the
testrunner couldn't handle relative paths in `sys.path`. It fixes #1204.

This is likely a regression from #1176, where the update to the new
module loading system caused relative paths to never match a fully
qualified module name. The patch now expands relative paths to their
absolute form before comparing them to the module path.

This issue was breaking the vanilla `basilisp test` command, as it adds
an empty string (`""`) entry to `sys.path`, which is interpreted as
`"."`. Since this is a relative path, it wasn’t handled by the logic,
causing the project directory not to be recognized as the root of the
Basilisp test modules.

I’ve added a test that invokes `basilisp test` directly as a subprocess.
Unfortunately, I couldn’t find a way to control the pytester `sys.path`
entries with the precise control required for this test. Any counter
suggestions are most welcome.

Thanks

---------

Co-authored-by: ikappaki <[email protected]>
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.

2 participants