Home > Blockchain >  Why are certain file names not allowed for local Python source code files?
Why are certain file names not allowed for local Python source code files?

Time:05-17

There seem to be file names that are not allowed to exist in the same directory in which I'm running my Python source code because they probably conflict with a file of the same name within a module in which I've imported.

Is there a way to still keep the names the same but avoid the exception?

This seems bizarre being how long Python has been around and is not fixed or the default install of Python doesn't avoid this, despite what modules are imported (ie: openpyxl in the copy.py scenario & smtplib in the email.py scenario).

Below are two example exceptions. My source code is in the testing.py file. And files copy.py and email.py are in the same directory as testing.py. For now, I renamed them to copy2.py and email2.py, but this seems like a bad workaround.

copy.py

Traceback (most recent call last):
  File "C:\Python\Python37_64\lib\runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "C:\Python\Python37_64\lib\runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "C:\Python\Python37_64\lib\cProfile.py", line 185, in <module>
    main()
  File "C:\Python\Python37_64\lib\cProfile.py", line 178, in main
    runctx(code, globs, None, options.outfile, options.sort)
  File "C:\Python\Python37_64\lib\cProfile.py", line 20, in runctx
    filename, sort)
  File "C:\Python\Python37_64\lib\profile.py", line 62, in runctx
    prof.runctx(statement, globals, locals)
  File "C:\Python\Python37_64\lib\cProfile.py", line 100, in runctx
    exec(cmd, globals, locals)
  File "C:\GitLab\redcap-p01-etl\testing.py", line 7, in <module>
    import openpyxl # openpyxl 3.0.7
  File "C:\Python\venv\Python37_64\lib\site-packages\openpyxl\__init__.py", line 6, in <module>
    from openpyxl.workbook import Workbook
  File "C:\Python\venv\Python37_64\lib\site-packages\openpyxl\workbook\__init__.py", line 4, in <module>
    from .workbook import Workbook
  File "C:\Python\venv\Python37_64\lib\site-packages\openpyxl\workbook\workbook.py", line 4, in <module>
    from copy import copy
  File "C:\GitLab\p01\copy.py", line 2
    def parse_slash_copy(const char *args):
    ^
IndentationError: unexpected indent

email.py

Traceback (most recent call last):
  File "C:\Python\Python37_64\lib\runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "C:\Python\Python37_64\lib\runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "C:\Python\Python37_64\lib\cProfile.py", line 185, in <module>
    main()
  File "C:\Python\Python37_64\lib\cProfile.py", line 178, in main
    runctx(code, globs, None, options.outfile, options.sort)
  File "C:\Python\Python37_64\lib\cProfile.py", line 20, in runctx
    filename, sort)
  File "C:\Python\Python37_64\lib\profile.py", line 62, in runctx
    prof.runctx(statement, globals, locals)
  File "C:\Python\Python37_64\lib\cProfile.py", line 100, in runctx
    exec(cmd, globals, locals)
  File "C:\GitLab\p01\testing.py", line 13, in <module>
    import requests
  File "C:\Python\venv\Python37_64\lib\site-packages\requests\__init__.py", line 43, in <module>
    import urllib3
  File "C:\Python\venv\Python37_64\lib\site-packages\urllib3\__init__.py", line 11, in <module>
    from . import exceptions
  File "C:\Python\venv\Python37_64\lib\site-packages\urllib3\exceptions.py", line 3, in <module>
    from .packages.six.moves.http_client import IncompleteRead as httplib_IncompleteRead
  File "C:\Python\venv\Python37_64\lib\site-packages\urllib3\packages\six.py", line 199, in load_module
    mod = mod._resolve()
  File "C:\Python\venv\Python37_64\lib\site-packages\urllib3\packages\six.py", line 113, in _resolve
    return _import_module(self.mod)
  File "C:\Python\venv\Python37_64\lib\site-packages\urllib3\packages\six.py", line 82, in _import_module
    __import__(name)
  File "C:\Python\Python37_64\lib\http\client.py", line 71, in <module>
    import email.parser
  File "C:\GitLab\p01\email.py", line 1, in <module>
    import smtplib
  File "C:\Python\Python37_64\lib\smtplib.py", line 47, in <module>
    import email.utils
ModuleNotFoundError: No module named 'email.utils'; 'email' is not a package

CodePudding user response:

This seems bizarre being how long Python has been around and is not fixed or the default install of Python doesn't avoid this, despite what modules are imported

It is not fixed or avoided because it is considered to be working as intended. In the default configuration, any time Python loads modules, it looks for the module in various paths, defined in a list that is accessible as sys.path.

From the documentation:

As initialized upon program startup, the first item of this list, path[0], is the directory containing the script that was used to invoke the Python interpreter. If the script directory is not available (e.g. if the interpreter is invoked interactively or if the script is read from standard input), path[0] is the empty string, which directs Python to search modules in the current directory first. Notice that the script directory is inserted before the entries inserted as a result of PYTHONPATH.

In your case, then, path[0] is C:\GitLab\p01, which is definitely not a place to look for standard library modules.

Personally, I am not very happy with the design decision (I would prefer, in particular, that new programmers are forced to get their heads around relative imports ASAP), but it is a conscious design decision, and one that enables quite a bit of convenience.

Is there a way to still keep the names the same but avoid the exception?

If you insist - you can simply hack sys.path:

import sys
local = sys.path.pop(0)
import requests
sys.path.insert(0, local)

This will not necessarily be compatible with any other hacks you might attempt to sys.path anywhere else in the program (but at least you can ensure that the change is immediately reverted after the otherwise-problematic imports). You will be stuck with something like this for every import (optimistically, sequence of imports) that conflicts with the name you want. And, of course, if you want to use the name sys you are out of luck.

You can wrap this up in a variety of ways; and you can hook into the import system in a variety of ways. It is possible (but potentially very dangerous) to do dynamic imports (i.e., from a string that contains a URI), and it is possible to alter the mechanisms that import uses. This is a broad research topic, beyond the scope of a Stack Overflow answer.

CodePudding user response:

Python ships with a number of modules, such as json, collections, copy and email. A complete list can be found in the official documentation.

Since module/package names are globally unique per interpreter sessions, using custom modules/packages with the same name as a built in module makes the latter inaccessible by their given name. This means that any code trying to access the builtin modules – be it your own or third-party code – will likely fail.

There is no workaround for this. Do not re-use names of builtin modules/packages unless you purposely want to replace them. This includes removing leftover code with such naming conflicts. Either rename the conflicting files, or move them out of the searched paths.

  • Related