-
-
Notifications
You must be signed in to change notification settings - Fork 32k
Add follow_symlinks
to os.path.exists()
#117705
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
See previous discussion: |
OK, thanks for the information. I won't be pushing for that then. |
It is useful to search the tracker, Discourse, and the old python-ideas/python-dev mailing list archives before submitting feature requests. BTW, I would encourage you to take a good look at the devguide; it is a good read. Suggesting to start with the lifecycle of a pull request, and especially the subsection about making good PRs. |
It's indeed useful, it looks like this functionality was rejected for |
The place for such a discussion would be Discourse. Iff there is consensus, follow up with an issue on the tracker. |
I have printed the latter, but I have 2 questions:
|
You'll find instructions both for building and running tests in the devguide.
I have no idea; I don't use VS Code :) I think you are better off asking that question in a VS Code forum. |
On Windows, the In the context of stat queries, a name-surrogate reparse point is considered a 'symlink'. The |
Is this something you would be willing to make a pull request for? |
Alternatively, we could make |
That works, if you're averse to programming in C, assuming the wrapper doesn't significantly hurt the performance of |
There's around 1% hit on performance. We have better things to do than optimise that using C code. |
FWIW, here's code to extend the implementation of /*[clinic input]
os._path_exists
path: 'O'
Path to be tested; can be a string, bytes object, a path-like object,
or an integer that references an open file descriptor.
follow_symlinks: bool = True
If False, and the last element of the path is a symbolic link, do not
test the target of the symbolic link.
Test whether a path exists. Returns False for broken symbolic links
[clinic start generated code]*/
static PyObject *
os__path_exists_impl(PyObject *module, PyObject *path, int follow_symlinks)
/*[clinic end generated code: output=f31130f636d45dcc input=26779f82ae9d4f5a]*/
{
path_t _path = PATH_T_INITIALIZE("exists", "path", 0, 1);
HANDLE hfile;
int result = 0;
if (!path_converter(path, &_path)) {
path_cleanup(&_path);
if (PyErr_ExceptionMatches(PyExc_ValueError)) {
PyErr_Clear();
Py_RETURN_FALSE;
}
return NULL;
}
Py_BEGIN_ALLOW_THREADS
if (_path.fd != -1) {
hfile = _Py_get_osfhandle_noraise(_path.fd);
if (hfile != INVALID_HANDLE_VALUE) {
result = 1;
}
}
else if (_path.wide) {
BOOL slow_path = TRUE;
FILE_STAT_BASIC_INFORMATION statInfo;
if (_Py_GetFileInformationByName(_path.wide, FileStatBasicByNameInfo,
&statInfo, sizeof(statInfo)))
{
if (!(statInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) ||
!follow_symlinks &&
IsReparseTagNameSurrogate(statInfo.ReparseTag))
{
slow_path = FALSE;
result = 1;
}
} else if (_Py_GetFileInformationByName_ErrorIsTrustworthy(
GetLastError()))
{
slow_path = FALSE;
}
if (slow_path) {
STRUCT_STAT st;
if (!follow_symlinks) {
if (!LSTAT(_path.wide, &st)) {
result = 1;
}
}
else {
hfile = CreateFileW(_path.wide, FILE_READ_ATTRIBUTES, 0, NULL,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS,
NULL);
if (hfile != INVALID_HANDLE_VALUE) {
CloseHandle(hfile);
result = 1;
}
else {
switch (GetLastError()) {
case ERROR_ACCESS_DENIED:
case ERROR_SHARING_VIOLATION:
case ERROR_CANT_ACCESS_FILE:
case ERROR_INVALID_PARAMETER:
if (!STAT(_path.wide, &st)) {
result = 1;
}
}
}
}
}
}
Py_END_ALLOW_THREADS
path_cleanup(&_path);
if (result) {
Py_RETURN_TRUE;
}
Py_RETURN_FALSE;
}
/*[clinic input]
os._path_lexists
path: 'O'
Path to be tested; can be a string, bytes object, a path-like object,
or an integer that references an open file descriptor.
Test whether a path exists. Returns True for broken symbolic links
[clinic start generated code]*/
static PyObject *
os__path_lexists_impl(PyObject *module, PyObject *path)
/*[clinic end generated code: output=b9a42a50b1df6651 input=96bc06e253ad0cd7]*/
{
return os__path_exists_impl(module, path, 0);
} |
Thanks, that seems to work. Is there a reason you don't make pull requests? |
There is an old design rule -- rather than adding a boolean parameter to a function, it is better to add a new function. It does not always work, especially if there are several boolean parameters, but Python usually follows it. |
Then what about |
|
And |
The I do not see the need for this change. Nobody asked for it. It seems that the only reason for this change is that you can implement it. |
Actually, the correct answer is that this was used for refactoring (otherwise just having |
I'm happy to help if you want to use the code that I posted to make a pull request to implement |
Uh oh!
There was an error while loading. Please reload this page.
Feature or enhancement
Proposal:
Because we have
os.path.exists()
&os.path.lexists()
, it might make sense to add afollow_symlinks
argument to the former:This matches
pathlib.Path.exists()
(as well asos.stat()
&os.chmod()
).Also, it looks like(but that's less explicit and so unnecessary, see #21157 (comment))pathlib.Path
doesn't have anlexists()
function.Note: this argument also needs to be added toDone.nt._path_exists()
.Has this already been discussed elsewhere?
This is a minor feature, which does not need previous discussion elsewhere
Links to previous discussion of this feature:
No response
Linked PRs
follow_symlinks
toos.path.exists()
#117729The text was updated successfully, but these errors were encountered: