#7336 make --log-file relative to inifile if it exists#7350
#7336 make --log-file relative to inifile if it exists#7350symonk wants to merge 5 commits intopytest-dev:mainfrom
Conversation
|
While this is technically beyond the scope of the linked issue can we allow for the user to provide an absolute path for a log file, in which case we do not make the log file relative to anything? |
src/_pytest/logging.py
Outdated
| log_file = get_option_ini(config, "log_file") or os.devnull | ||
|
|
||
| # Keep the log file relative to the inidir file (if it exists) (#7336) | ||
| inidir = getattr(getattr(config, "inifile", None), "dirname", None) |
There was a problem hiding this comment.
At this point config.inifile should always be defined (unless I'm mistaken), so getattr(config, "inifile", None) can be replaced with just config.inifile.
inifile can be None, but instead of using getattr on it, I think it is better do use an explicit is None check. getattr() is using a dynamic feature of Python which is not analyzed and type checked, so I for one prefer to avoid it unless the dynamicism is really needed (e.g. when the name is not a constant).
Finally, I think currently there may be some cases where inifile may be an str rather than a py.path.local, but that is more of a bug (I'm just working on that as a follow up for the recent TOML PR).
There was a problem hiding this comment.
Hmm I seem to be mistaken, I thought i was getting a type:str in some cases; and no 'dirname' attr, but it seems if config.inifile is not None, it is always path.local (as far as our current test suite goes)
There was a problem hiding this comment.
mypy hates:
src\_pytest\logging.py:533: error: "str" has no attribute "dirname" [attr-defined]
Found 1 error in 1 file (checked 2 source files)
I assume some type hinting on the config obj - will check
You usually get this "for free" from the way path-joining works: >>> import os.path
>>> os.path.join('/the/log/dir', '/an/absolute/path')
'/an/absolute/path' |
nicoddemus
left a comment
There was a problem hiding this comment.
Thanks @symonk,
Looks good, just left a few comments. 👍
| def test_log_file_is_in_pytest_ini_rootdir(testdir): | ||
| # as per https://docs.pytest.org/en/5.4.3/reference.html log_file | ||
| # the file should be relative to the pytest inifile | ||
| testdir.makefile( |
There was a problem hiding this comment.
No need to change, but you can also use makeinifile. 😉
There was a problem hiding this comment.
ah i got confused as it made a 'tox' file :)
There was a problem hiding this comment.
Probably for historical reasons.
testing/logging/test_reporting.py
Outdated
| result.assert_outcomes(passed=1) | ||
|
|
||
|
|
||
| def test_log_file_is_in_pytest_ini_rootdir(testdir): |
There was a problem hiding this comment.
Please add docstrings to each test referencing #7350, so it is easier to find the issue that lead to the creation of the test later. 👍
src/_pytest/logging.py
Outdated
| log_file = get_option_ini(config, "log_file") or os.devnull | ||
|
|
||
| # Keep the log file relative to the inidir file (if it exists) (#7336) | ||
| inidir = getattr(getattr(config, "inifile", None), "dirname", None) |
There was a problem hiding this comment.
I realize this is a matter of opinion, but this seems a bit contrived, I would instead use this:
if log_file != os.devnull and config.inifile:
log_file = os.path.join(config.inifile.dirname, log_file)(No need for the getattr chain)
There was a problem hiding this comment.
Thanks, any advice on fixing:
src\_pytest\logging.py:533: error: "str" has no attribute "dirname" [attr-defined]
Found 1 error in 1 file (checked 2 source files)
As a result?
I see:
def determine_setup(
inifile: Optional[str],
args: List[str],
rootdir_cmd_arg: Optional[str] = None,
config: Optional["Config"] = None,
) -> Tuple[py.path.local, Optional[str], Dict[str, Union[str, List[str]]]]:
should this be a path local?
if im not mistaken, dont we want to remove references to 'py' ?
There was a problem hiding this comment.
That's weird, locate_config returns:
Tuple[
Optional[py.path.local], Optional[py.path.local], Dict[str, Union[str, List[str]]],
](Note that the 2nd item is Optional[py.path.local])
Here's a snippet from determine_setup, which calls locate_config:
def determine_setup(
inifile: Optional[str],
args: List[str],
rootdir_cmd_arg: Optional[str] = None,
config: Optional["Config"] = None,
) -> Tuple[py.path.local, Optional[str], Dict[str, Union[str, List[str]]]]:
rootdir = None
dirs = get_dirs_from_args(args)
if inifile: # (1)
inicfg = load_config_dict_from_file(py.path.local(inifile)) or {}
if rootdir_cmd_arg is None:
rootdir = get_common_ancestor(dirs)
else: # (2)
ancestor = get_common_ancestor(dirs)
rootdir, inifile, inicfg = locate_config([ancestor])
if rootdir is None and rootdir_cmd_arg is None:
...
return rootdir, inifile, inicfg or {}In 1, indeed inifile ends up as a string by the time of return, but not when we get into 2, where inifile is a py.path.local (because of the locate_config call).
Shouldn't mypy catch that?
Regardless, I think we should change the return value from determine_setup to always return a py.path.local.
testing/logging/test_reporting.py
Outdated
| """ | ||
| ) | ||
| p.move(sub.join(p.basename)) | ||
| os.chdir(sub.strpath) |
There was a problem hiding this comment.
Use monkeypatch.chdir as it is safer. 👍
There was a problem hiding this comment.
ah yes, auto revert post-test execution i assume? thanks for the tip
testing/logging/test_reporting.py
Outdated
| """ | ||
| ) | ||
| p.move(sub.join(p.basename)) | ||
| os.chdir(sub.strpath) |
There was a problem hiding this comment.
Use monkeypatch.chdir as it is safer. 👍
testing/logging/test_reporting.py
Outdated
| """ | ||
| ) | ||
| p.move(sub.join(p.basename)) | ||
| os.chdir(sub.strpath) |
There was a problem hiding this comment.
Use monkeypatch.chdir as it is safer. 👍
changelog/7336.bugfix.rst
Outdated
| @@ -0,0 +1 @@ | |||
| The pytest ``--log-file`` cli or ``log_file`` ini marker is now relative to the configs ``inifile`` directory. | |||
There was a problem hiding this comment.
this is a breaking change, the filename shoudld reflect that
There was a problem hiding this comment.
Hmm good point, although the docs say otherwise, indeed this might break users.
changelog/7336.bugfix.rst
Outdated
| @@ -0,0 +1 @@ | |||
| The pytest ``--log-file`` cli or ``log_file`` ini marker is now relative to the configs ``inifile`` directory. | |||
There was a problem hiding this comment.
| The pytest ``--log-file`` cli or ``log_file`` ini marker is now relative to the configs ``inifile`` directory. | |
| The pytest ``--log-file`` cli or ``log_file`` ini marker is now relative to the ``inifile`` directory, as it was always the intention. It was originally introduced as relative to the current working directory unintentionally. |
dd98247 to
45d6a10
Compare
| rootdir_cmd_arg: Optional[str] = None, | ||
| config: Optional["Config"] = None, | ||
| ) -> Tuple[py.path.local, Optional[str], Dict[str, Union[str, List[str]]]]: | ||
| ) -> Tuple[py.path.local, Optional[py.path.local], Dict[str, Union[str, List[str]]]]: |
There was a problem hiding this comment.
Please make sure to convert inifile to a py.path.local inside if inifile: below to honor this type annotation.
There was a problem hiding this comment.
I have a PR locally which addresses these issues (by fixing errors after running mypy with pytest-dev/py#232). I'll post it in a bit.
There was a problem hiding this comment.
test_inifilename hates such change(s) - investigating; maybe the test should be just updated:
'../../foo/bar.ini' # becomes:
C:\Users\sy\AppData\Local\Temp\pytest-of-sy\pytest-972\test_inifilename0\foo\bar.ini
bluetech
left a comment
There was a problem hiding this comment.
Formally registering two issues I mentioned above:
-
This makes
log_filerelative to inidir, however it also affects the--log-filecommand line argument, where it is expected to be relative to the invocation dir, IMO. -
The
set_log_pathis usingrootdiras the base path for relative input, this seems inconsistent (maybe it's OK though).
|
Thanks @bluetech I will revisit based on your insights |
|
Sorry been busy, going to look at this again; I will assume --log-file should remain untouched and only the ini marker for log_file should be relative to inifile |
As per #7336, I think the correct behaviour is to keep the --log-file relative to the inifile? From what I gather the inifile can be None; so this PR makes the --log-file relative to that directory in the event that it exists; not sure how to proceed if it is None in a good manner. (assume the current behaviour of putting the log file in the execution directory?)
Close #7336