0

When I try running my Python module with the form py -m foldername, I get a ModuleNotFoundError referencing a different module that I am importing that I have also written. It runs perfectly fine if I just write py modulename.py, but not with the -m. Why is the module not found when called through -m but is found otherwise? Thanks!

Minimum reproducible example:

All files are in foldername

File __main__.py

import m
m.p()

File m.py

def p():
    print("hello")

Here is the full error

C:\Users\g\Documents>py -m hello
Traceback (most recent call last):
  File "C:\Users\g\AppData\Local\Programs\Python\Python39\lib\runpy.py", line 197, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "C:\Users\g\AppData\Local\Programs\Python\Python39\lib\runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "C:\Users\g\Documents\hello\__main__.py", line 1, in 
    import m
ModuleNotFoundError: No module named 'm'
Aaron
  • 10,133
  • 1
  • 24
  • 40
  • Can you provide `modulename.py`? – astrochun Mar 05 '21 at 01:58
  • I added an example of when I have an error @astrochun – SteelShredder Mar 05 '21 at 01:59
  • 1
    I believe the difference occurs with whether the code is properly packaged/index. the -m module tells python to use existing packages in PYTHONPATH. When you run `python module.py` you're telling it "run this specific file here" – astrochun Mar 05 '21 at 02:01
  • @astrochun How can I fix that exactly? Does it have to do with my __init__.py or some other file that I need to fix. – SteelShredder Mar 05 '21 at 02:04
  • 1
    It's not so much something to *fix*, as it is a case of understanding the difference between running a script from a file and running a script from a module (and by "module", I am making a distinction between a particular text file and the abstract Python entity *created* from that file.) – chepner Mar 05 '21 at 02:08
  • Indeed what @chepner says is correct. The question I would like to understand is why do you want to do `python -m module`? I use it mostly with standard python libraries like `os`, `sys`, and `crypt` (for encrypting a password), but usually for my own codebase, I don't do that. I have an `__init__ == "__main__"` script that is executable. – astrochun Mar 05 '21 at 02:13
  • But if I want to run the file as a script, how can I import another file? – SteelShredder Mar 05 '21 at 02:14
  • I want to upload it as a package such that later I can download it and run it rather than just cloning the GitHub repository. – SteelShredder Mar 05 '21 at 02:14
  • Then you should look at python packaging and publishing to PyPI. There are a number of resources out there. This might be of help: https://realpython.com/pypi-publish-python-package/ – astrochun Mar 05 '21 at 02:16
  • I went through the process on the Python documentation here: https://packaging.python.org/tutorials/installing-packages/ I did upload and download it as a package when I ran my actual code. – SteelShredder Mar 05 '21 at 02:17
  • I'm confused then, because you said: "... want to upload" but now you say you have it published? If so, what package is it then? Have you done `pip install PACKAGE`? – astrochun Mar 05 '21 at 02:19
  • I would prefer not to show my actual package, but the same error occurs when there is not a package so I do not seem the benefit in showing it. I have made a better example of what I am trying to do and I have shown the full error if that is any help. – SteelShredder Mar 05 '21 at 02:29
  • @Aaron You do not really need to be so aggressive about it. No one said relative import. I asked another question to your answer but I'll also copy it here Is there any way to have it both ways? You solved my general problem, but could I also have it so that I can run the file normally with py \_\_main__.py? – SteelShredder Mar 05 '21 at 02:54
  • @SteelShredder I didn't name the question... It's unfortunate it has an offensive title, but it was asked almost a decade ago, and it is regarding the same issue, so it is a duplicate. if you take a look at the accepted answer it has a very detailed discussion of exactly what you are asking: running as a module vs running as a script – Aaron Mar 05 '21 at 02:55
  • Sorry, I did not read the title of the post and I just went to the body. Does that imply that a script to run some code in the package cannot exist and that it must be outside of the package? – SteelShredder Mar 05 '21 at 03:18
  • As with programming in general **"cannot"** isn't necessarily the same as **"should not"**. Python was designed to have some amount of separation between what is a script and what is a module, and it is good organization practice to keep that separation. I will refer you to `python -m this`: *"There should be one-- and preferably only one --obvious way to do it."* – Aaron Mar 05 '21 at 03:41
  • that said, once you're inside `__main__.py`, `sys.path` is just a regular list which you can modify to your heart's content (modifications are not permeant so no risk of messing up your terminal env vars) *"Although that way may not be obvious at first unless you're Dutch."* ;) – Aaron Mar 05 '21 at 03:49
  • 1
    Thank you! The design of Python can be a bit strange at times but that is OK. I do not have enough interest in pursuing this to start to mess with the Python path so I will probably just stick to cloning and then running a script off of the repository. – SteelShredder Mar 05 '21 at 03:54

1 Answers1

0

NOTE: re-write due to new information:

tldr: You are trying to do an absolute import when you need a relative import.

when you call python -m hello, "__main__.py" is called as the script to run with "C:\Users\g\Documents" as the working directoy. when you import m python will search all the static paths defined by the site module as well as "C:\Users\g\Documents". It will not search "C:\Users\g\Documents\hello". If you want to search for a module relative to a file rather than relative to the working directory you need to use the relative import syntax: from . import m

Aaron
  • 10,133
  • 1
  • 24
  • 40
  • Given that the two files are in the same directory, I do not get how anything else could work. What should I change so that I can import the file? – SteelShredder Mar 05 '21 at 02:12
  • @SteelShredder is your terminal set to the same working dir as those two files? when you call `__main__.py`, it will set the working dir to the parent dir of the py file you execute, but if that's not the same as the working dir of the terminal, when you call `python -m` it won't be looking in the same folder. – Aaron Mar 05 '21 at 02:14
  • I would like to assume that I downloaded it as a package so that the working directory does not matter. How could I configure it so that I could run the package? – SteelShredder Mar 05 '21 at 02:16
  • @SteelShredder edited for better accuracy of language. I wasn't happy with how I worded it at first. also.. what is the name of the folder `__main__` and `m` are in, and where is it located. it seems to me that you may want to be calling `-m foldername.m` – Aaron Mar 05 '21 at 02:21
  • Oh sorry that is what I did. I will edit the original post. – SteelShredder Mar 05 '21 at 02:24
  • Is there any way to have it both ways? You solved my general problem, but could I also have it so that I can run the file normally with py __main__.py? – SteelShredder Mar 05 '21 at 02:51
  • @SteelShredder See the accepted answer on the duplicate I identified **Script vs. Module**. – Aaron Mar 05 '21 at 02:54