47
47
from _pytest .compat import TYPE_CHECKING
48
48
from _pytest .outcomes import fail
49
49
from _pytest .outcomes import Skipped
50
+ from _pytest .pathlib import bestrelpath
50
51
from _pytest .pathlib import import_path
51
52
from _pytest .pathlib import ImportMode
52
53
from _pytest .pathlib import Path
@@ -520,7 +521,7 @@ def _getconftestmodules(
520
521
else :
521
522
directory = path
522
523
523
- # XXX these days we may rather want to use config.rootdir
524
+ # XXX these days we may rather want to use config.rootpath
524
525
# and allow users to opt into looking into the rootdir parent
525
526
# directories instead of requiring to specify confcutdir.
526
527
clist = []
@@ -820,13 +821,13 @@ class Config:
820
821
:param PytestPluginManager pluginmanager:
821
822
822
823
:param InvocationParams invocation_params:
823
- Object containing the parameters regarding the `` pytest.main` `
824
+ Object containing parameters regarding the :func:` pytest.main`
824
825
invocation.
825
826
"""
826
827
827
828
@attr .s (frozen = True )
828
829
class InvocationParams :
829
- """Holds parameters passed during `` pytest.main()``
830
+ """Holds parameters passed during :func:` pytest.main`.
830
831
831
832
The object attributes are read-only.
832
833
@@ -841,11 +842,20 @@ class InvocationParams:
841
842
"""
842
843
843
844
args = attr .ib (type = Tuple [str , ...], converter = _args_converter )
844
- """Tuple of command-line arguments as passed to ``pytest.main()``."""
845
+ """The command-line arguments as passed to :func:`pytest.main`.
846
+
847
+ :type: Tuple[str, ...]
848
+ """
845
849
plugins = attr .ib (type = Optional [Sequence [Union [str , _PluggyPlugin ]]])
846
- """List of extra plugins, might be `None`."""
850
+ """Extra plugins, might be `None`.
851
+
852
+ :type: Optional[Sequence[Union[str, plugin]]]
853
+ """
847
854
dir = attr .ib (type = Path )
848
- """Directory from which ``pytest.main()`` was invoked."""
855
+ """The directory from which :func:`pytest.main` was invoked.
856
+
857
+ :type: pathlib.Path
858
+ """
849
859
850
860
def __init__ (
851
861
self ,
@@ -867,6 +877,10 @@ def __init__(
867
877
"""
868
878
869
879
self .invocation_params = invocation_params
880
+ """The parameters with which pytest was invoked.
881
+
882
+ :type: InvocationParams
883
+ """
870
884
871
885
_a = FILE_OR_DIR
872
886
self ._parser = Parser (
@@ -876,7 +890,7 @@ def __init__(
876
890
self .pluginmanager = pluginmanager
877
891
"""The plugin manager handles plugin registration and hook invocation.
878
892
879
- :type: PytestPluginManager.
893
+ :type: PytestPluginManager
880
894
"""
881
895
882
896
self .trace = self .pluginmanager .trace .root .get ("config" )
@@ -901,9 +915,55 @@ def __init__(
901
915
902
916
@property
903
917
def invocation_dir (self ) -> py .path .local :
904
- """Backward compatibility."""
918
+ """The directory from which pytest was invoked.
919
+
920
+ Prefer to use :attr:`invocation_params.dir <InvocationParams.dir>`,
921
+ which is a :class:`pathlib.Path`.
922
+
923
+ :type: py.path.local
924
+ """
905
925
return py .path .local (str (self .invocation_params .dir ))
906
926
927
+ @property
928
+ def rootpath (self ) -> Path :
929
+ """The path to the :ref:`rootdir <rootdir>`.
930
+
931
+ :type: pathlib.Path
932
+
933
+ .. versionadded:: 6.1
934
+ """
935
+ return self ._rootpath
936
+
937
+ @property
938
+ def rootdir (self ) -> py .path .local :
939
+ """The path to the :ref:`rootdir <rootdir>`.
940
+
941
+ Prefer to use :attr:`rootpath`, which is a :class:`pathlib.Path`.
942
+
943
+ :type: py.path.local
944
+ """
945
+ return py .path .local (str (self .rootpath ))
946
+
947
+ @property
948
+ def inipath (self ) -> Optional [Path ]:
949
+ """The path to the :ref:`configfile <configfiles>`.
950
+
951
+ :type: Optional[pathlib.Path]
952
+
953
+ .. versionadded:: 6.1
954
+ """
955
+ return self ._inipath
956
+
957
+ @property
958
+ def inifile (self ) -> Optional [py .path .local ]:
959
+ """The path to the :ref:`configfile <configfiles>`.
960
+
961
+ Prefer to use :attr:`inipath`, which is a :class:`pathlib.Path`.
962
+
963
+ :type: Optional[py.path.local]
964
+ """
965
+ return py .path .local (str (self .inipath )) if self .inipath else None
966
+
907
967
def add_cleanup (self , func : Callable [[], None ]) -> None :
908
968
"""Add a function to be called when the config object gets out of
909
969
use (usually coninciding with pytest_unconfigure)."""
@@ -977,9 +1037,9 @@ def notify_exception(
977
1037
978
1038
def cwd_relative_nodeid (self , nodeid : str ) -> str :
979
1039
# nodeid's are relative to the rootpath, compute relative to cwd.
980
- if self .invocation_dir != self .rootdir :
981
- fullpath = self .rootdir . join ( nodeid )
982
- nodeid = self .invocation_dir . bestrelpath ( fullpath )
1040
+ if self .invocation_params . dir != self .rootpath :
1041
+ fullpath = self .rootpath / nodeid
1042
+ nodeid = bestrelpath ( self .invocation_params . dir , fullpath )
983
1043
return nodeid
984
1044
985
1045
@classmethod
@@ -1014,11 +1074,11 @@ def _initini(self, args: Sequence[str]) -> None:
1014
1074
rootdir_cmd_arg = ns .rootdir or None ,
1015
1075
config = self ,
1016
1076
)
1017
- self .rootdir = py . path . local ( str ( rootpath ))
1018
- self .inifile = py . path . local ( str ( inipath )) if inipath else None
1077
+ self ._rootpath = rootpath
1078
+ self ._inipath = inipath
1019
1079
self .inicfg = inicfg
1020
- self ._parser .extra_info ["rootdir" ] = self .rootdir
1021
- self ._parser .extra_info ["inifile" ] = self .inifile
1080
+ self ._parser .extra_info ["rootdir" ] = str ( self .rootpath )
1081
+ self ._parser .extra_info ["inifile" ] = str ( self .inipath )
1022
1082
self ._parser .addini ("addopts" , "extra command line options" , "args" )
1023
1083
self ._parser .addini ("minversion" , "minimally required pytest version" )
1024
1084
self ._parser .addini (
@@ -1110,8 +1170,8 @@ def _preparse(self, args: List[str], addopts: bool = True) -> None:
1110
1170
self ._validate_plugins ()
1111
1171
self ._warn_about_skipped_plugins ()
1112
1172
1113
- if self .known_args_namespace .confcutdir is None and self .inifile :
1114
- confcutdir = py . path . local (self .inifile ). dirname
1173
+ if self .known_args_namespace .confcutdir is None and self .inipath is not None :
1174
+ confcutdir = str (self .inipath . parent )
1115
1175
self .known_args_namespace .confcutdir = confcutdir
1116
1176
try :
1117
1177
self .hook .pytest_load_initial_conftests (
@@ -1147,13 +1207,13 @@ def _checkversion(self) -> None:
1147
1207
1148
1208
if not isinstance (minver , str ):
1149
1209
raise pytest .UsageError (
1150
- "%s: 'minversion' must be a single value" % self .inifile
1210
+ "%s: 'minversion' must be a single value" % self .inipath
1151
1211
)
1152
1212
1153
1213
if Version (minver ) > Version (pytest .__version__ ):
1154
1214
raise pytest .UsageError (
1155
1215
"%s: 'minversion' requires pytest-%s, actual pytest-%s'"
1156
- % (self .inifile , minver , pytest .__version__ ,)
1216
+ % (self .inipath , minver , pytest .__version__ ,)
1157
1217
)
1158
1218
1159
1219
def _validate_config_options (self ) -> None :
@@ -1218,10 +1278,10 @@ def parse(self, args: List[str], addopts: bool = True) -> None:
1218
1278
args , self .option , namespace = self .option
1219
1279
)
1220
1280
if not args :
1221
- if self .invocation_dir == self .rootdir :
1281
+ if self .invocation_params . dir == self .rootpath :
1222
1282
args = self .getini ("testpaths" )
1223
1283
if not args :
1224
- args = [str (self .invocation_dir )]
1284
+ args = [str (self .invocation_params . dir )]
1225
1285
self .args = args
1226
1286
except PrintHelp :
1227
1287
pass
@@ -1324,10 +1384,10 @@ def _getini(self, name: str):
1324
1384
#
1325
1385
if type == "pathlist" :
1326
1386
# TODO: This assert is probably not valid in all cases.
1327
- assert self .inifile is not None
1328
- dp = py . path . local ( self .inifile ). dirpath ()
1387
+ assert self .inipath is not None
1388
+ dp = self .inipath . parent
1329
1389
input_values = shlex .split (value ) if isinstance (value , str ) else value
1330
- return [dp . join ( x , abs = True ) for x in input_values ]
1390
+ return [py . path . local ( str ( dp / x ) ) for x in input_values ]
1331
1391
elif type == "args" :
1332
1392
return shlex .split (value ) if isinstance (value , str ) else value
1333
1393
elif type == "linelist" :
0 commit comments