diff --git a/README.rst b/README.rst index d9ac03d..d35460f 100644 --- a/README.rst +++ b/README.rst @@ -11,7 +11,10 @@ Requirements * Python 2.4 or later * Works on Python 2.4 -> 2.7 - * Python 3 not yet supported (coming soon) + * Works on Python 3.5 + * Python 3.6 not yet supported + * Python package six is required + * New `XRootD `_ client + development headers * `xrootd-client, xrootd-client-devel` packages * Version 3.3.3 or above required diff --git a/libs/client/__init__.py b/libs/client/__init__.py index 8567684..1833698 100644 --- a/libs/client/__init__.py +++ b/libs/client/__init__.py @@ -1,4 +1,4 @@ -from filesystem import FileSystem as FileSystem -from file import File as File -from url import URL as URL -from copyprocess import CopyProcess as CopyProcess +from .filesystem import FileSystem as FileSystem +from .file import File as File +from .url import URL as URL +from .copyprocess import CopyProcess as CopyProcess diff --git a/libs/client/flags.py b/libs/client/flags.py index d485295..444722e 100644 --- a/libs/client/flags.py +++ b/libs/client/flags.py @@ -15,10 +15,11 @@ # You should have received a copy of the GNU Lesser General Public License # along with XRootD. If not, see . #------------------------------------------------------------------------------- +import six def enum(**enums): """Build the equivalent of a C++ enum""" - reverse = dict((value, key) for key, value in enums.iteritems()) + reverse = dict((value, key) for key, value in six.iteritems(enums)) enums['reverse_mapping'] = reverse return type('Enum', (), enums) diff --git a/libs/client/responses.py b/libs/client/responses.py index 0da3928..6283dc4 100644 --- a/libs/client/responses.py +++ b/libs/client/responses.py @@ -16,6 +16,7 @@ # along with XRootD. If not, see . #------------------------------------------------------------------------------- from XRootD.client.url import URL +import six class Struct(object): """Convert a dict into an object by adding each dict entry to __dict__""" @@ -23,7 +24,7 @@ def __init__(self, entries): self.__dict__.update(**entries) def __repr__(self): return '<%s>' % str(', '.join('%s: %s' % (k, repr(v)) - for (k, v) in self.__dict__.iteritems())) + for (k, v) in six.iteritems(self.__dict__))) class LocationInfo(Struct): """Path location information (a list of discovered file locations). diff --git a/setup.py b/setup.py index d8bb200..3f08fef 100644 --- a/setup.py +++ b/setup.py @@ -2,17 +2,18 @@ from distutils import sysconfig from os import getenv, walk, path import subprocess +import six # Remove the "-Wstrict-prototypes" compiler option, which isn't valid for C++. cfg_vars = sysconfig.get_config_vars() opt = cfg_vars["OPT"] cfg_vars["OPT"] = " ".join( flag for flag in opt.split() if flag != '-Wstrict-prototypes' ) -xrdlibdir = getenv( 'XRD_LIBDIR' ) or '/usr/lib' -xrdincdir = getenv( 'XRD_INCDIR' ) or '/usr/include/xrootd' +xrdlibdir = getenv( 'XRD_LIBDIR' ) or '/opt/xrootd/lib' +xrdincdir = getenv( 'XRD_INCDIR' ) or '/opt/xrootd/include/xrootd' -print 'XRootD library dir:', xrdlibdir -print 'XRootD include dir:', xrdincdir +print ('XRootD library dir:', xrdlibdir) +print ('XRootD include dir:', xrdincdir) sources = list() depends = list() @@ -26,10 +27,10 @@ p = subprocess.Popen(["./genversion.sh"], stdout=subprocess.PIPE) version, err = p.communicate() -print version +print (version) setup( name = 'pyxrootd', - version = version, + version = str(version), author = 'XRootD Developers', author_email = 'xrootd-dev@slac.stanford.edu', url = 'http://xrootd.org', diff --git a/src/ChunkIterator.hh b/src/ChunkIterator.hh index fec3f7c..90b0c0e 100644 --- a/src/ChunkIterator.hh +++ b/src/ChunkIterator.hh @@ -97,8 +97,12 @@ namespace PyXRootD //! ChunkIterator type structure //---------------------------------------------------------------------------- static PyTypeObject ChunkIteratorType = { +#if PY_MAJOR_VERSION >= 3 + PyVarObject_HEAD_INIT(NULL, 0) +#else PyObject_HEAD_INIT(NULL) 0, /* ob_size */ +#endif "client.File.ChunkIterator", /* tp_name */ sizeof(ChunkIterator), /* tp_basicsize */ 0, /* tp_itemsize */ diff --git a/src/PyXRootD.hh b/src/PyXRootD.hh index 886185b..66f2deb 100644 --- a/src/PyXRootD.hh +++ b/src/PyXRootD.hh @@ -33,9 +33,24 @@ #include #include "structmember.h" +#if PY_MAJOR_VERSION >= 3 +#define IS_PY3K +#define PyString_AsString PyUnicode_AsUTF8 +#define PyString_Check PyUnicode_Check +#define PyInt_FromLong PyLong_FromLong +#define PyString_FromStringAndSize PyUnicode_FromStringAndSize +#define METH_KEYWORDS METH_VARARGS +#define PyString_Size PyUnicode_GET_SIZE +#define PyInt_FromLong PyLong_FromLong +#define PyInt_Check PyLong_Check +#define PyInt_AsLong PyLong_AsLong +#define initclient PyInit_client +#define PyString_FromString PyUnicode_FromString +#else #if PY_MINOR_VERSION <= 5 #define PyUnicode_FromString PyString_FromString #endif +#endif #define async( func ) \ Py_BEGIN_ALLOW_THREADS \ diff --git a/src/PyXRootDCopyProcess.hh b/src/PyXRootDCopyProcess.hh index 01b195c..a74daff 100644 --- a/src/PyXRootDCopyProcess.hh +++ b/src/PyXRootDCopyProcess.hh @@ -67,7 +67,11 @@ namespace PyXRootD { delete self->process; delete self->results; +#if PY_MAJOR_VERSION >= 3 + Py_TYPE(self)->tp_free( (PyObject*) self ); +#else self->ob_type->tp_free( (PyObject*) self ); +#endif } //---------------------------------------------------------------------------- @@ -97,8 +101,12 @@ namespace PyXRootD //! CopyProcess binding type object //---------------------------------------------------------------------------- static PyTypeObject CopyProcessType = { - PyObject_HEAD_INIT(NULL) - 0, /* ob_size */ +#if PY_MAJOR_VERSION >= 3 + PyVarObject_HEAD_INIT(NULL, 0) +#else + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ +#endif "pyxrootd.CopyProcess", /* tp_name */ sizeof(CopyProcess), /* tp_basicsize */ 0, /* tp_itemsize */ diff --git a/src/PyXRootDFile.hh b/src/PyXRootDFile.hh index 79691e7..740bd9d 100644 --- a/src/PyXRootDFile.hh +++ b/src/PyXRootDFile.hh @@ -32,6 +32,10 @@ #include +#if PY_MAJOR_VERSION >=3 +# define Py_TPFLAGS_HAVE_ITER 0 +#endif + namespace PyXRootD { //---------------------------------------------------------------------------- @@ -98,7 +102,11 @@ namespace PyXRootD delete self->file; delete self->partial; delete self->surplus; +#if PY_MAJOR_VERSION >= 3 + Py_TYPE(self)->tp_free( (PyObject*) self ); +#else self->ob_type->tp_free( (PyObject*) self ); +#endif } //---------------------------------------------------------------------------- @@ -214,8 +222,13 @@ namespace PyXRootD //! File binding type object //---------------------------------------------------------------------------- static PyTypeObject FileType = { - PyObject_HEAD_INIT(NULL) - 0, /* ob_size */ + +#if PY_MAJOR_VERSION >= 3 + PyVarObject_HEAD_INIT(NULL, 0) +#else + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ +#endif "pyxrootd.File", /* tp_name */ sizeof(File), /* tp_basicsize */ 0, /* tp_itemsize */ diff --git a/src/PyXRootDFileSystem.hh b/src/PyXRootDFileSystem.hh index caee834..62f7841 100644 --- a/src/PyXRootDFileSystem.hh +++ b/src/PyXRootDFileSystem.hh @@ -134,7 +134,11 @@ namespace PyXRootD { delete self->filesystem; Py_XDECREF( self->url ); +#if PY_MAJOR_VERSION >= 3 + Py_TYPE(self)->tp_free( (PyObject*) self ); +#else self->ob_type->tp_free( (PyObject*) self ); +#endif } //---------------------------------------------------------------------------- @@ -150,8 +154,13 @@ namespace PyXRootD //---------------------------------------------------------------------------- //! FileSystem binding type object //---------------------------------------------------------------------------- - static PyTypeObject FileSystemType = - { PyObject_HEAD_INIT(NULL) 0, /* ob_size */ + static PyTypeObject FileSystemType = { +#if PY_MAJOR_VERSION >= 3 + PyVarObject_HEAD_INIT(NULL, 0) +#else + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ +#endif "pyxrootd.FileSystem", /* tp_name */ sizeof(FileSystem), /* tp_basicsize */ 0, /* tp_itemsize */ diff --git a/src/PyXRootDModule.cc b/src/PyXRootDModule.cc index 4497b7b..4af3a85 100644 --- a/src/PyXRootDModule.cc +++ b/src/PyXRootDModule.cc @@ -46,7 +46,11 @@ namespace PyXRootD //---------------------------------------------------------------------------- //! Module initialization function //---------------------------------------------------------------------------- +#if PY_MAJOR_VERSION >= 3 + PyMODINIT_FUNC PyInit_client( void ) +#else PyMODINIT_FUNC initclient( void ) +#endif { // Ensure GIL state is initialized Py_Initialize(); @@ -55,30 +59,73 @@ namespace PyXRootD } FileSystemType.tp_new = PyType_GenericNew; - if ( PyType_Ready( &FileSystemType ) < 0 ) return; - Py_INCREF( &FileSystemType ); + if ( PyType_Ready( &FileSystemType ) < 0 ) +#if PY_MAJOR_VERSION >= 3 + return 0; +#else + return; +#endif + Py_INCREF( &FileSystemType ); FileType.tp_new = PyType_GenericNew; - if ( PyType_Ready( &FileType ) < 0 ) return; + if ( PyType_Ready( &FileType ) < 0 ) +#if PY_MAJOR_VERSION >= 3 + return 0; +#else + return; +#endif Py_INCREF( &FileType ); URLType.tp_new = PyType_GenericNew; - if ( PyType_Ready( &URLType ) < 0 ) return; + if ( PyType_Ready( &URLType ) < 0 ) +#if PY_MAJOR_VERSION >= 3 + return 0; +#else + return; +#endif Py_INCREF( &URLType ); CopyProcessType.tp_new = PyType_GenericNew; - if ( PyType_Ready( &CopyProcessType ) < 0 ) return; + if ( PyType_Ready( &CopyProcessType ) < 0 ) +#if PY_MAJOR_VERSION >= 3 + return 0; +#else + return; +#endif Py_INCREF( &CopyProcessType ); +#if PY_MAJOR_VERSION >= 3 + static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "client", //m_name + client_module_doc, //m_doc + -1, //m_name + module_methods, //m_functions + NULL, //m_reload + NULL, //m_traverse + NULL, //m_clear + NULL, //m_free + }; + ClientModule = PyModule_Create(&moduledef); +#else ClientModule = Py_InitModule3("client", module_methods, client_module_doc); +#endif + if (ClientModule == NULL) { - return; +#if PY_MAJOR_VERSION >= 3 + return 0; +#else + return; +#endif } PyModule_AddObject( ClientModule, "FileSystem", (PyObject *) &FileSystemType ); PyModule_AddObject( ClientModule, "File", (PyObject *) &FileType ); PyModule_AddObject( ClientModule, "URL", (PyObject *) &URLType ); PyModule_AddObject( ClientModule, "CopyProcess", (PyObject *) &CopyProcessType ); +#if PY_MAJOR_VERSION >= 3 + return ClientModule; +#endif } } diff --git a/src/PyXRootDURL.hh b/src/PyXRootDURL.hh index bf4383f..4a597d1 100644 --- a/src/PyXRootDURL.hh +++ b/src/PyXRootDURL.hh @@ -81,7 +81,11 @@ namespace PyXRootD static void URL_dealloc( URL *self ) { delete self->url; +#if PY_MAJOR_VERSION >= 3 + Py_TYPE(self)->tp_free( (PyObject*) self ); +#else self->ob_type->tp_free( (PyObject*) self ); +#endif } //---------------------------------------------------------------------------- @@ -134,8 +138,12 @@ namespace PyXRootD //! URL binding type object //---------------------------------------------------------------------------- static PyTypeObject URLType = { - PyObject_HEAD_INIT(NULL) - 0, /* ob_size */ +#if PY_MAJOR_VERSION >= 3 + PyVarObject_HEAD_INIT(NULL, 0) +#else + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ +#endif "pyxrootd.URL", /* tp_name */ sizeof(URL), /* tp_basicsize */ 0, /* tp_itemsize */