[Tutor] Why does os.path.realpath('test_main.py') give different results for unittest than for testing statement in interpreter?
Steven D'Aprano
steve at pearwood.info
Tue Jan 9 03:47:33 EST 2018
On Sun, Jan 07, 2018 at 03:07:26AM -0600, boB Stepp wrote:
> After some searching I have yet to locate a definition of "canonical
> path" that makes sense to me. The dictionary definition of canonical
> does not seem to be very helpful in understanding this.
Probably the best definition would be "the simplest authoritative form
of the path".
> What is the methodology that os.path.realpath(path) is
> actually following to yield a particular path name?
Trust the Source, Luke :-)
The Python 3.5 source code for os.path.realpath under Windows looks like
this:
# realpath is a no-op on systems without islink support
realpath = abspath
The comment is misleading[1] for two reasons:
- it isn't a no-op, since abspath() actually does something;
what they mean is that on Windows realpath() doesn't do
anything beyond what abspath() does;
(on Linux and Mac, it also checks for symbolic links, and
converts them to their actual paths)
- and technically speaking, some Windows file systems *do*
support symbolic links, although few people know this or
use them.
https://en.wikipedia.org/wiki/NTFS_symbolic_link
Nevertheless, we can say that under Windows realpath() does nothing more
than abspath() (at least up to Python 3.5). So what does abspath() do?
The source for abspath() is a more little complicated, because it has
two different implementations depending on whether you are *actually*
running Windows or not. But basically, abspath() does this:
- if the path is a relative path (does not start with C:\ or similar)
then prepend the current directory to the path;
- then normalise the path.
What does it mean to normalise the path?
It converts it to the simplest form, eliminating redundant slashes and
dots. Because this is Windows, there are a bunch of special cases for
device names and literal paths (whatever they are!) that look like this:
\\.\ -> device names
\\?\ -> literal paths
but for the standard case of ordinary file names, normpath() on Windows
will convert forward slashes / to backslashes \ and eliminate duplicated
slashes and dots in the path. Remember that . means "this directory" and
.. means "one directory up", normpath() will normalise any of these:
A//B
A/./B
A/foo/../B
to A\B. Since the Windows version of realpath() doesn't care about
symbolic links, it doesn't need to care whether any of the directories
and files actually exist or not. All it needs to do is turn a relative
path into an absolute path, then normalise the path. And none of that
depends on the path actually existing.
> What I *really* want to do is locate and open a file "test_data.dat"
> that is in the same directory as the file with the tests,
> "tests/test_main.py".
If you can assume that tests/test_main.py is always in the current
directory, then you can just write:
PATH = 'tests/test_main.py'
and use that. open(PATH) will happily work on relative paths as well as
absolute.
Reminder: absolute paths start with a drive:
A:\foo\bar
relative paths don't, and so they implicitly start in the current
directory.
*But* that assumes that you have started running the tests from inside
the directory which includes tests/test_main.py. That might not be the
case. In order to solve this problem properly, I think we need to know
how your project is laid out, including the tests.
But my guess is that the solution is to extract the path of the running
module, and append tests/test_main.py to that path.
If this isn't clear, ask and I'll explain in more detail. (But later,
I'm about to move off the computer for a few hours.)
> Anyway, based on that
> earlier related question and your answer tonight I have modified my
> test class to the following:
[...]
I'll read it later.
[1] "At Resolver we've found it useful to short-circuit any doubt and
just refer to comments in code as 'lies'. "
--Michael Foord paraphrases Christian Muirhead on python-dev, 2009-03-22
--
Steve
More information about the Tutor
mailing list