Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit635ce29

Browse files
gh-104803: Implement ntpath.isdevdrive for checking whether a path is on a Windows Dev Drive (GH-104805)
(cherry picked from commitbfd20d2)Co-authored-by: Steve Dower <steve.dower@python.org>
1 parent5dc6b18 commit635ce29

File tree

6 files changed

+216
-1
lines changed

6 files changed

+216
-1
lines changed

‎Doc/library/os.path.rst‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,24 @@ the :mod:`glob` module.)
304304
Accepts a:term:`path-like object`.
305305

306306

307+
..function::isdevdrive(path)
308+
309+
Return ``True`` if pathname *path* is located on a Windows Dev Drive.
310+
A Dev Drive is optimized for developer scenarios, and offers faster
311+
performance for reading and writing files. It is recommended for use for
312+
source code, temporary build directories, package caches, and other
313+
IO-intensive operations.
314+
315+
May raise an error for an invalid path, for example, one without a
316+
recognizable drive, but returns ``False`` on platforms that do not support
317+
Dev Drives. See `the Windows documentation<https://learn.microsoft.com/windows/dev-drive/>`_
318+
for information on enabling and creating Dev Drives.
319+
320+
..availability::Windows.
321+
322+
..versionadded::3.12
323+
324+
307325
..function::join(path, *paths)
308326

309327
Join one or more path segments intelligently. The return value is the

‎Lib/ntpath.py‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -867,3 +867,19 @@ def commonpath(paths):
867867
exceptImportError:
868868
# Use genericpath.* as imported above
869869
pass
870+
871+
872+
try:
873+
fromntimport_path_isdevdrive
874+
exceptImportError:
875+
defisdevdrive(path):
876+
"""Determines whether the specified path is on a Windows Dev Drive."""
877+
# Never a Dev Drive
878+
returnFalse
879+
else:
880+
defisdevdrive(path):
881+
"""Determines whether the specified path is on a Windows Dev Drive."""
882+
try:
883+
return_path_isdevdrive(abspath(path))
884+
exceptOSError:
885+
returnFalse

‎Lib/test/test_ntpath.py‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -992,6 +992,26 @@ def test_fast_paths_in_use(self):
992992
self.assertTrue(os.path.existsisnt._path_exists)
993993
self.assertFalse(inspect.isfunction(os.path.exists))
994994

995+
@unittest.skipIf(os.name!='nt',"Dev Drives only exist on Win32")
996+
deftest_isdevdrive(self):
997+
# Result may be True or False, but shouldn't raise
998+
self.assertIn(ntpath.isdevdrive(os_helper.TESTFN), (True,False))
999+
# ntpath.isdevdrive can handle relative paths
1000+
self.assertIn(ntpath.isdevdrive("."), (True,False))
1001+
self.assertIn(ntpath.isdevdrive(b"."), (True,False))
1002+
# Volume syntax is supported
1003+
self.assertIn(ntpath.isdevdrive(os.listvolumes()[0]), (True,False))
1004+
# Invalid volume returns False from os.path method
1005+
self.assertFalse(ntpath.isdevdrive(r"\\?\Volume{00000000-0000-0000-0000-000000000000}\\"))
1006+
# Invalid volume raises from underlying helper
1007+
withself.assertRaises(OSError):
1008+
nt._path_isdevdrive(r"\\?\Volume{00000000-0000-0000-0000-000000000000}\\")
1009+
1010+
@unittest.skipIf(os.name=='nt',"isdevdrive fallback only used off Win32")
1011+
deftest_isdevdrive_fallback(self):
1012+
# Fallback always returns False
1013+
self.assertFalse(ntpath.isdevdrive(os_helper.TESTFN))
1014+
9951015

9961016
classNtCommonTest(test_genericpath.CommonTest,unittest.TestCase):
9971017
pathmodule=ntpath
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Add:func:`os.path.isdevdrive` to detect whether a path is on a Windows Dev
2+
Drive. Returns ``False`` on platforms that do not support Dev Drive, and is
3+
absent on non-Windows platforms.

‎Modules/clinic/posixmodule.c.h‎

Lines changed: 69 additions & 1 deletion
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎Modules/posixmodule.c‎

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4530,6 +4530,95 @@ os_listmounts_impl(PyObject *module, path_t *volume)
45304530
}
45314531

45324532

4533+
/*[clinic input]
4534+
os._path_isdevdrive
4535+
4536+
path: path_t
4537+
4538+
Determines whether the specified path is on a Windows Dev Drive.
4539+
4540+
[clinic start generated code]*/
4541+
4542+
staticPyObject*
4543+
os__path_isdevdrive_impl(PyObject*module,path_t*path)
4544+
/*[clinic end generated code: output=1f437ea6677433a2 input=ee83e4996a48e23d]*/
4545+
{
4546+
#ifndefPERSISTENT_VOLUME_STATE_DEV_VOLUME
4547+
/* This flag will be documented at
4548+
https://learn.microsoft.com/windows-hardware/drivers/ddi/ntifs/ns-ntifs-_file_fs_persistent_volume_information
4549+
after release, and will be available in the latest WinSDK.
4550+
We include the flag to avoid a specific version dependency
4551+
on the latest WinSDK. */
4552+
constintPERSISTENT_VOLUME_STATE_DEV_VOLUME=0x00002000;
4553+
#endif
4554+
interr=0;
4555+
PyObject*r=NULL;
4556+
wchar_tvolume[MAX_PATH];
4557+
4558+
Py_BEGIN_ALLOW_THREADS
4559+
if (!GetVolumePathNameW(path->wide,volume,MAX_PATH)) {
4560+
/* invalid path of some kind */
4561+
/* Note that this also includes the case where a volume is mounted
4562+
in a path longer than 260 characters. This is likely to be rare
4563+
and problematic for other reasons, so a (soft) failure in this
4564+
check seems okay. */
4565+
err=GetLastError();
4566+
}elseif (GetDriveTypeW(volume)!=DRIVE_FIXED) {
4567+
/* only care about local dev drives */
4568+
r=Py_False;
4569+
}else {
4570+
HANDLEhVolume=CreateFileW(
4571+
volume,
4572+
FILE_READ_ATTRIBUTES,
4573+
FILE_SHARE_READ |FILE_SHARE_WRITE,
4574+
NULL,
4575+
OPEN_EXISTING,
4576+
FILE_FLAG_BACKUP_SEMANTICS,
4577+
NULL
4578+
);
4579+
if (hVolume==INVALID_HANDLE_VALUE) {
4580+
err=GetLastError();
4581+
}else {
4582+
FILE_FS_PERSISTENT_VOLUME_INFORMATIONvolumeState= {0};
4583+
volumeState.Version=1;
4584+
volumeState.FlagMask=PERSISTENT_VOLUME_STATE_DEV_VOLUME;
4585+
if (!DeviceIoControl(
4586+
hVolume,
4587+
FSCTL_QUERY_PERSISTENT_VOLUME_STATE,
4588+
&volumeState,
4589+
sizeof(volumeState),
4590+
&volumeState,
4591+
sizeof(volumeState),
4592+
NULL,
4593+
NULL
4594+
)) {
4595+
err=GetLastError();
4596+
}
4597+
CloseHandle(hVolume);
4598+
if (err==ERROR_INVALID_PARAMETER) {
4599+
/* not supported on this platform */
4600+
r=Py_False;
4601+
}elseif (!err) {
4602+
r= (volumeState.VolumeFlags&PERSISTENT_VOLUME_STATE_DEV_VOLUME)
4603+
?Py_True :Py_False;
4604+
}
4605+
}
4606+
}
4607+
Py_END_ALLOW_THREADS
4608+
4609+
if (err) {
4610+
PyErr_SetFromWindowsErr(err);
4611+
returnNULL;
4612+
}
4613+
4614+
if (r) {
4615+
returnPy_NewRef(r);
4616+
}
4617+
4618+
returnNULL;
4619+
}
4620+
4621+
45334622
int
45344623
_PyOS_getfullpathname(constwchar_t*path,wchar_t**abspath_p)
45354624
{
@@ -15797,6 +15886,7 @@ static PyMethodDef posix_methods[] = {
1579715886
OS_SETNS_METHODDEF
1579815887
OS_UNSHARE_METHODDEF
1579915888

15889+
OS__PATH_ISDEVDRIVE_METHODDEF
1580015890
OS__PATH_ISDIR_METHODDEF
1580115891
OS__PATH_ISFILE_METHODDEF
1580215892
OS__PATH_ISLINK_METHODDEF

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp