mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-03 02:15:43 -04:00
Implement Python 3.6 fspath protocol; allow passing a pathlib.Path wherever Filename is expected
The Python 3.6 fspath protocol allows passing Filename objects into any Python standard library calls that take a path.
This commit is contained in:
parent
3fa5b6b4ee
commit
e778c529b2
@ -38,7 +38,6 @@ Filename(const char *filename) {
|
|||||||
(*this) = filename;
|
(*this) = filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@ -84,6 +83,20 @@ Filename(Filename &&from) NOEXCEPT :
|
|||||||
}
|
}
|
||||||
#endif // USE_MOVE_SEMANTICS
|
#endif // USE_MOVE_SEMANTICS
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an empty Filename.
|
||||||
|
*/
|
||||||
|
INLINE Filename::
|
||||||
|
Filename() :
|
||||||
|
_dirname_end(0),
|
||||||
|
_basename_start(0),
|
||||||
|
_basename_end(string::npos),
|
||||||
|
_extension_start(string::npos),
|
||||||
|
_hash_start(string::npos),
|
||||||
|
_hash_end(string::npos),
|
||||||
|
_flags(0) {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@ -155,14 +168,6 @@ pattern_filename(const string &filename) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
INLINE Filename::
|
|
||||||
~Filename() {
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@ -233,7 +238,7 @@ operator = (string &&filename) NOEXCEPT {
|
|||||||
*/
|
*/
|
||||||
INLINE Filename &Filename::
|
INLINE Filename &Filename::
|
||||||
operator = (Filename &&from) NOEXCEPT {
|
operator = (Filename &&from) NOEXCEPT {
|
||||||
_filename = MOVE(from._filename);
|
_filename = move(from._filename);
|
||||||
_dirname_end = from._dirname_end;
|
_dirname_end = from._dirname_end;
|
||||||
_basename_start = from._basename_start;
|
_basename_start = from._basename_start;
|
||||||
_basename_end = from._basename_end;
|
_basename_end = from._basename_end;
|
||||||
|
@ -55,20 +55,22 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
INLINE Filename(const char *filename);
|
INLINE Filename(const char *filename);
|
||||||
|
INLINE Filename(const string &filename);
|
||||||
PUBLISHED:
|
|
||||||
INLINE Filename(const string &filename = "");
|
|
||||||
INLINE Filename(const wstring &filename);
|
INLINE Filename(const wstring &filename);
|
||||||
INLINE Filename(const Filename ©);
|
INLINE Filename(const Filename ©);
|
||||||
Filename(const Filename &dirname, const Filename &basename);
|
|
||||||
INLINE ~Filename();
|
|
||||||
|
|
||||||
#ifdef USE_MOVE_SEMANTICS
|
#ifdef USE_MOVE_SEMANTICS
|
||||||
INLINE Filename(string &&filename) NOEXCEPT;
|
INLINE Filename(string &&filename) NOEXCEPT;
|
||||||
INLINE Filename(Filename &&from) NOEXCEPT;
|
INLINE Filename(Filename &&from) NOEXCEPT;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
PUBLISHED:
|
||||||
|
INLINE Filename();
|
||||||
|
Filename(const Filename &dirname, const Filename &basename);
|
||||||
|
|
||||||
#ifdef HAVE_PYTHON
|
#ifdef HAVE_PYTHON
|
||||||
|
EXTENSION(Filename(PyObject *path));
|
||||||
|
|
||||||
EXTENSION(PyObject *__reduce__(PyObject *self) const);
|
EXTENSION(PyObject *__reduce__(PyObject *self) const);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -118,6 +120,7 @@ PUBLISHED:
|
|||||||
INLINE char operator [] (size_t n) const;
|
INLINE char operator [] (size_t n) const;
|
||||||
|
|
||||||
EXTENSION(PyObject *__repr__() const);
|
EXTENSION(PyObject *__repr__() const);
|
||||||
|
EXTENSION(PyObject *__fspath__() const);
|
||||||
|
|
||||||
INLINE string substr(size_t begin) const;
|
INLINE string substr(size_t begin) const;
|
||||||
INLINE string substr(size_t begin, size_t end) const;
|
INLINE string substr(size_t begin, size_t end) const;
|
||||||
|
@ -14,6 +14,115 @@
|
|||||||
#include "filename_ext.h"
|
#include "filename_ext.h"
|
||||||
|
|
||||||
#ifdef HAVE_PYTHON
|
#ifdef HAVE_PYTHON
|
||||||
|
|
||||||
|
#ifndef CPPPARSER
|
||||||
|
extern Dtool_PyTypedObject Dtool_Filename;
|
||||||
|
#endif // CPPPARSER
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a Filename object from a str, bytes object, or os.PathLike.
|
||||||
|
*/
|
||||||
|
void Extension<Filename>::
|
||||||
|
__init__(PyObject *path) {
|
||||||
|
nassertv(path != NULL);
|
||||||
|
nassertv(_this != NULL);
|
||||||
|
|
||||||
|
Py_ssize_t length;
|
||||||
|
|
||||||
|
if (PyUnicode_CheckExact(path)) {
|
||||||
|
wchar_t *data;
|
||||||
|
#if PY_VERSION_HEX >= 0x03020000
|
||||||
|
data = PyUnicode_AsWideCharString(path, &length);
|
||||||
|
#else
|
||||||
|
length = PyUnicode_GET_SIZE(path);
|
||||||
|
data = (wchar_t *)alloca(sizeof(wchar_t) * (length + 1));
|
||||||
|
PyUnicode_AsWideChar((PyUnicodeObject *)path, data, length);
|
||||||
|
#endif
|
||||||
|
(*_this) = wstring(data, length);
|
||||||
|
|
||||||
|
#if PY_VERSION_HEX >= 0x03020000
|
||||||
|
PyMem_Free(data);
|
||||||
|
#endif
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PyBytes_CheckExact(path)) {
|
||||||
|
char *data;
|
||||||
|
PyBytes_AsStringAndSize(path, &data, &length);
|
||||||
|
(*_this) = string(data, length);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Py_TYPE(path) == &Dtool_Filename._PyType) {
|
||||||
|
// Copy constructor.
|
||||||
|
(*_this) = *((Filename *)((Dtool_PyInstDef *)path)->_ptr_to_object);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject *path_str;
|
||||||
|
|
||||||
|
#if PY_VERSION_HEX >= 0x03060000
|
||||||
|
// It must be an os.PathLike object. Check for an __fspath__ method.
|
||||||
|
PyObject *fspath = PyObject_GetAttrString((PyObject *)Py_TYPE(path), "__fspath__");
|
||||||
|
if (fspath == NULL) {
|
||||||
|
PyErr_Format(PyExc_TypeError, "expected str, bytes or os.PathLike object, not %s", Py_TYPE(path)->tp_name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
path_str = PyObject_CallFunctionObjArgs(fspath, path, NULL);
|
||||||
|
Py_DECREF(fspath);
|
||||||
|
#else
|
||||||
|
// There is no standard path protocol before Python 3.6, but let's try and
|
||||||
|
// support taking pathlib paths anyway. We don't version check this to
|
||||||
|
// allow people to use backports of the pathlib module.
|
||||||
|
if (PyObject_HasAttrString(path, "_format_parsed_parts")) {
|
||||||
|
path_str = PyObject_Str(path);
|
||||||
|
} else {
|
||||||
|
#if PY_VERSION_HEX >= 0x03040000
|
||||||
|
PyErr_Format(PyExc_TypeError, "expected str, bytes, Path or Filename object, not %s", Py_TYPE(path)->tp_name);
|
||||||
|
#elif PY_MAJOR_VERSION >= 3
|
||||||
|
PyErr_Format(PyExc_TypeError, "expected str, bytes or Filename object, not %s", Py_TYPE(path)->tp_name);
|
||||||
|
#else
|
||||||
|
PyErr_Format(PyExc_TypeError, "expected str or unicode object, not %s", Py_TYPE(path)->tp_name);
|
||||||
|
#endif
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (path_str == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PyUnicode_CheckExact(path_str)) {
|
||||||
|
wchar_t *data;
|
||||||
|
#if PY_VERSION_HEX >= 0x03020000
|
||||||
|
data = PyUnicode_AsWideCharString(path_str, &length);
|
||||||
|
#else
|
||||||
|
length = PyUnicode_GET_SIZE(path_str);
|
||||||
|
data = (wchar_t *)alloca(sizeof(wchar_t) * (length + 1));
|
||||||
|
PyUnicode_AsWideChar((PyUnicodeObject *)path_str, data, length);
|
||||||
|
#endif
|
||||||
|
(*_this) = Filename::from_os_specific_w(wstring(data, length));
|
||||||
|
|
||||||
|
#if PY_VERSION_HEX >= 0x03020000
|
||||||
|
PyMem_Free(data);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} else if (PyBytes_CheckExact(path_str)) {
|
||||||
|
char *data;
|
||||||
|
PyBytes_AsStringAndSize(path_str, &data, &length);
|
||||||
|
(*_this) = Filename::from_os_specific(string(data, length));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
#if PY_MAJOR_VERSION >= 3
|
||||||
|
PyErr_Format(PyExc_TypeError, "expected str or bytes object, not %s", Py_TYPE(path_str)->tp_name);
|
||||||
|
#else
|
||||||
|
PyErr_Format(PyExc_TypeError, "expected str or unicode object, not %s", Py_TYPE(path_str)->tp_name);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
Py_DECREF(path_str);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This special Python method is implement to provide support for the pickle
|
* This special Python method is implement to provide support for the pickle
|
||||||
* module.
|
* module.
|
||||||
@ -62,6 +171,16 @@ __repr__() const {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows a Filename object to be passed to any Python function that accepts
|
||||||
|
* an os.PathLike object.
|
||||||
|
*/
|
||||||
|
PyObject *Extension<Filename>::
|
||||||
|
__fspath__() const {
|
||||||
|
wstring filename = _this->to_os_specific_w();
|
||||||
|
return PyUnicode_FromWideChar(filename.data(), (Py_ssize_t)filename.size());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This variant on scan_directory returns a Python list of strings on success,
|
* This variant on scan_directory returns a Python list of strings on success,
|
||||||
* or None on failure.
|
* or None on failure.
|
||||||
|
@ -29,8 +29,11 @@
|
|||||||
template<>
|
template<>
|
||||||
class Extension<Filename> : public ExtensionBase<Filename> {
|
class Extension<Filename> : public ExtensionBase<Filename> {
|
||||||
public:
|
public:
|
||||||
|
void __init__(PyObject *path);
|
||||||
|
|
||||||
PyObject *__reduce__(PyObject *self) const;
|
PyObject *__reduce__(PyObject *self) const;
|
||||||
PyObject *__repr__() const;
|
PyObject *__repr__() const;
|
||||||
|
PyObject *__fspath__() const;
|
||||||
PyObject *scan_directory() const;
|
PyObject *scan_directory() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user