-
Notifications
You must be signed in to change notification settings - Fork 64
Conversation
@@ -78,10 +84,23 @@ def patterns_from_files(pattern_files): | |||
|
|||
def load_module(path): | |||
"""Loads a module from its path.""" | |||
if module_like(path): | |||
path = module_name_to_path(path) |
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 think this should be imp.find_module
? Otherwise you'll only be able to "find" modules in the current directory.
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 was reading the docs for find_module
, and it seems that if you pass in a series of paths, it will search through those for the module, and otherwise will look through sys.path
.
So, how do you ensure that it looks through the current directory first for the module, and then through sys.path
? I guess I could temporarily append '.' to sys.path
and then remove it after?
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.
@ajm188 Yup, that's generally the way it's done. Although you want to prepend it, and probably use os.getcwd()
instead of "."
.
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.
Cool, sounds good; thanks!
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.
Hmm, from the docs:
This function does not handle hierarchical module names (names containing dots). In order to find P.M, that is, submodule M of package P, use find_module() and load_module() to find and load package P, and then use find_module() with the path argument set to P.path. When P itself has a dotted name, apply this recipe recursively.
Seems like this could get potentially gross.
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.
@ajm188 Was just poking around--what you actually want to do instead is use importlib.import_module
combined with the sys.path
trick, which should do everything you want, including handling modules not in the current directory.
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 only I had looked up to check my email!! I'll switch over to importlib
, which presumably does pretty much what I just implemented :sigh:
@@ -31,7 +31,7 @@ Read it | |||
optional arguments: | |||
-h, --help show this help message and exit | |||
--pattern PATH, -p PATH | |||
paths to pattern definition files | |||
paths to pattern definition files/modules |
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 about "files or modules"?
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.
ack
Rebased to resolve conflicts with @paiweilai 's change. Pending travis, this should be good to ship. @asottile any final thoughts (since this was your request 😄)? |
You should really avoid |
def test_loading_pattern_with_module_name(): | ||
# Have to do some schenanigans here to get the module name to look like it | ||
# came from the project root | ||
module_name = 'undebt' + ( |
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 import foo.bar.baz
and use foo.bar.baz.__name__
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.
good call
Consequently, `_load_module` is no longer needed.
Begin by assuming that everything is a path, but we want to load it as a module. So, take the path and after ensuring it is not a ../ kind of path, convert it to a module name (dots as the separator), then import it with the builtin `__import__` This change means we don't need the `module_like` check any longer, so we don't need to import the `re` module, and since we are using `__import__` we also don't need to import the `imp` or `importlib` modules!
@asottile updated with (I think) all of your issues addressed |
def maybe_path_to_module_name(maybe_path): | ||
relpath = os.path.relpath(maybe_path) | ||
if relpath.startswith('..'): | ||
raise ValueError("Relative imports not allowed: {}", relpath) |
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.
2 things:
- "relative imports" means something else, I believe you mean relative file paths
- this isn't going to do the string formatting you expect:
>>> relpath = '../foo'
>>> raise ValueError("Relative imports not allowed: {}", relpath)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: ('Relative imports not allowed: {}', '../foo')
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.
- Yep. Definitely meant that.
- :facedesk: oops 😱
Ship? |
⛵ |
@@ -31,7 +31,7 @@ Read it | |||
optional arguments: | |||
-h, --help show this help message and exit | |||
--pattern PATH, -p PATH | |||
paths to pattern definition files | |||
paths to pattern definition files or modules |
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.
This should specify that it only supports importable modules.
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.
Isn't that kind of implied? "Your code failed to import my unimportable module" would get closed as wontfix
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.
@ajm188 No, because right now the documentation says you can give it any path, but actually, only modules that are reachable from sys.path
will work.
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.
Yeah you're right. How about:
modules or paths to importable pattern definition 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.
@ajm188 Honestly, if we're only allowing modules that are on sys.path
, I'm not sure why we're allowing path-like inputs in the first place. I would just enforce only something that can directly be passed to importlib.import_module
(or __import__
, which is functionally equivalent but stylistically discouraged).
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 guess I can only come up with:
- I don't have to change the examples?
- Supporting paths gives you tab completion, where module names really don't
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.
Moved to #46.
Refs #40. Based on #37.
Example use: