[nautilus-python] Add support for building with python 3
- From: Adam Plumb <adamplumb src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [nautilus-python] Add support for building with python 3
- Date: Mon, 1 Jan 2018 19:44:06 +0000 (UTC)
commit 12687a3c107c7141eaf46da7752e6b82d669f23b
Author: Adam Plumb <adamplumb gmail com>
Date: Mon Jan 1 14:43:50 2018 -0500
Add support for building with python 3
configure.in | 5 +-
docs/reference/nautilus-python-column-provider.xml | 11 +++-
docs/reference/nautilus-python-info-provider.xml | 13 +++++-
docs/reference/nautilus-python-overview.xml | 16 ++++++-
.../nautilus-python-property-page-provider.xml | 22 +++++-----
examples/block-size-column.py | 9 +++-
examples/md5sum-property-page.py | 18 ++++----
examples/open-terminal.py | 4 +-
examples/update-file-info-async.py | 13 ++++-
src/Makefile.am | 1 +
src/nautilus-python-object.c | 48 +++++++++++++++++---
src/nautilus-python.c | 16 +++++--
12 files changed, 131 insertions(+), 45 deletions(-)
---
diff --git a/configure.in b/configure.in
index 4da69ee..6d094a2 100644
--- a/configure.in
+++ b/configure.in
@@ -35,8 +35,8 @@ AC_PREFIX_DEFAULT([$(pkg-config --variable=prefix libnautilus-extension || echo
dnl **************************************************
dnl * Check for Python
dnl **************************************************
-AM_CHECK_PYTHON_HEADERS(,[AC_MSG_ERROR(could not find Python headers)])
-AM_CHECK_PYTHON_LIBS(,[AC_MSG_ERROR(could not find Python lib)])
+PYG_CHECK_PYTHON_HEADERS(,[AC_MSG_ERROR(could not find Python headers)])
+PYG_CHECK_PYTHON_LIBS(,[AC_MSG_ERROR(could not find Python lib)])
if test "`pkg-config --variable=datadir pygobject-3.0`" != "" ; then
PYGOBJECT_VERSION=pygobject-3.0
@@ -98,5 +98,6 @@ echo " nautilus-python $VERSION"
echo
echo " Nautilus Prefix: ${prefix}"
echo " PyGObject Version: ${PYGOBJECT_VERSION}"
+echo " Python Library: ${PYTHON_LIB_LOC}/${PYTHON_LIB_NAME}"
echo " Documentation: ${enable_gtk_doc}"
echo
diff --git a/docs/reference/nautilus-python-column-provider.xml
b/docs/reference/nautilus-python-column-provider.xml
index edba0da..8adf2e3 100644
--- a/docs/reference/nautilus-python-column-provider.xml
+++ b/docs/reference/nautilus-python-column-provider.xml
@@ -46,9 +46,14 @@
<title>Nautilus.ColumnProvider Example</title>
<programlisting>
import os
-import urllib
-from gi.repository import Nautilus, GObject
+# A way to get unquote working with python 2 and 3
+try:
+ from urllib import unquote
+except ImportError:
+ from urllib.parse import unquote
+
+from gi.repository import GObject, Nautilus
class ColumnExtension(GObject.GObject, Nautilus.ColumnProvider, Nautilus.InfoProvider):
def __init__(self):
@@ -64,7 +69,7 @@ class ColumnExtension(GObject.GObject, Nautilus.ColumnProvider, Nautilus.InfoPro
if file.get_uri_scheme() != 'file':
return
- filename = urllib.unquote(file.get_uri()[7:])
+ filename = unquote(file.get_uri()[7:])
file.add_string_attribute('block_size', str(os.stat(filename).st_blksize))
</programlisting>
diff --git a/docs/reference/nautilus-python-info-provider.xml
b/docs/reference/nautilus-python-info-provider.xml
index ed156a0..74e1e42 100644
--- a/docs/reference/nautilus-python-info-provider.xml
+++ b/docs/reference/nautilus-python-info-provider.xml
@@ -65,16 +65,25 @@
<programlisting>
from gi.repository import Nautilus, GObject
-class ColumnExtension(GObject.GObject, Nautilus.InfoProvider):
+class UpdateFileInfoAsync(GObject.GObject, Nautilus.InfoProvider):
def __init__(self):
+ self.timers = []
pass
def update_file_info_full(self, provider, handle, closure, file):
- gobject.timeout_add_seconds(3, self.update_cb, provider, handle, closure)
+ print("update_file_info_full")
+ self.timers.append(GObject.timeout_add_seconds(3, self.update_cb, provider, handle, closure))
return Nautilus.OperationResult.IN_PROGRESS
def update_cb(self, provider, handle, closure):
+ print("update_cb")
Nautilus.info_provider_update_complete_invoke(closure, provider, handle,
Nautilus.OperationResult.FAILED)
+
+ def cancel_update(self, provider, handle):
+ print("cancel_update")
+ for t in self.timers:
+ GObject.source_remove(t)
+ self.timers = []
</programlisting>
</example>
diff --git a/docs/reference/nautilus-python-overview.xml b/docs/reference/nautilus-python-overview.xml
index 5f83fc4..9827d78 100644
--- a/docs/reference/nautilus-python-overview.xml
+++ b/docs/reference/nautilus-python-overview.xml
@@ -22,11 +22,20 @@
the main class from a Nautilus module class will be loaded</para>
<note>
-<title>A note about the standard python extensions install path</title>
+<title>Extension Install Path for < v1.2.0</title>
<para>As of nautilus-python 0.7.0 (and continued in 1.0+), nautilus-python looks in
~/.local/share/nautilus-python/extensions
for local extensions and $PREFIX/share/nautilus-python/extensions for global extensions.</para>
</note>
+
+ <note>
+<title>Extension Install Path for >= v1.2.0</title>
+<para>As of nautilus-python 1.2.0, python extensions are loaded in the following order:
+
+ 1. $XDG_DATA_HOME/nautilus-python/extensions
+ 2. nautilus_prefix/share/nautilus-python/extensions
+ 3. $XDG_DATA_DIRS/nautilus-python/extensions</para>
+ </note>
<note>
<title>A note about compatibility issues for nautilus-python 1.0</title>
@@ -36,6 +45,11 @@ for local extensions and $PREFIX/share/nautilus-python/extensions for global ext
<para>3. For now, some Nautilus class constructors require passing named arguments instead of a standard
argument list. This requirement may go away at some point.</para>
</note>
+ <note>
+ <title>Python3</title>
+ <para>As of nautilus-python v1.2.0, nautilus-python can be built to embed python3 instead of
python2. It uses the $PYTHON environment variable to determine which library to use.</para>
+ </note>
+
<xi:include href="nautilus-python-overview-example.xml"/>
<xi:include href="nautilus-python-overview-methods.xml"/>
diff --git a/docs/reference/nautilus-python-property-page-provider.xml
b/docs/reference/nautilus-python-property-page-provider.xml
index 84879c7..2afa2f9 100644
--- a/docs/reference/nautilus-python-property-page-provider.xml
+++ b/docs/reference/nautilus-python-property-page-provider.xml
@@ -41,11 +41,16 @@
<title>Nautilus.PropertyPageProvider Example</title>
<programlisting>
import hashlib
-import urllib
-from gi.repository import Nautilus, GObject, Gtk
+# A way to get unquote working with python 2 and 3
+try:
+ from urllib import unquote
+except ImportError:
+ from urllib.parse import unquote
-class ColumnExtension(GObject.GObject, Nautilus.PropertyPageProvider):
+from gi.repository import Nautilus, Gtk, GObject
+
+class MD5SumPropertyPage(GObject.GObject, Nautilus.PropertyPageProvider):
def __init__(self):
pass
@@ -60,7 +65,7 @@ class ColumnExtension(GObject.GObject, Nautilus.PropertyPageProvider):
if file.is_directory():
return
- filename = urllib.unquote(file.get_uri()[7:])
+ filename = unquote(file.get_uri()[7:])
self.property_label = Gtk.Label('MD5Sum')
self.property_label.show()
@@ -75,13 +80,8 @@ class ColumnExtension(GObject.GObject, Nautilus.PropertyPageProvider):
self.value_label = Gtk.Label()
self.hbox.pack_start(self.value_label, False, False, 0)
- md5sum = hashlib.md5()
- with open(filename,'rb') as f:
- for chunk in iter(lambda: f.read(8192), ''):
- md5sum.update(chunk)
- f.close()
-
- self.value_label.set_text(md5sum.hexdigest())
+ md5sum = hashlib.md5(filename.encode("utf-8")).hexdigest()
+ self.value_label.set_text(md5sum)
self.value_label.show()
return Nautilus.PropertyPage(name="NautilusPython::md5_sum",
diff --git a/examples/block-size-column.py b/examples/block-size-column.py
index fda87a9..e481dff 100644
--- a/examples/block-size-column.py
+++ b/examples/block-size-column.py
@@ -1,5 +1,10 @@
import os
-import urllib
+
+# A way to get unquote working with python 2 and 3
+try:
+ from urllib import unquote
+except ImportError:
+ from urllib.parse import unquote
from gi.repository import GObject, Nautilus
@@ -17,6 +22,6 @@ class ColumnExtension(GObject.GObject, Nautilus.ColumnProvider, Nautilus.InfoPro
if file.get_uri_scheme() != 'file':
return
- filename = urllib.unquote(file.get_uri()[7:])
+ filename = unquote(file.get_uri()[7:])
file.add_string_attribute('block_size', str(os.stat(filename).st_blksize))
diff --git a/examples/md5sum-property-page.py b/examples/md5sum-property-page.py
index c098738..42e1df7 100644
--- a/examples/md5sum-property-page.py
+++ b/examples/md5sum-property-page.py
@@ -1,5 +1,10 @@
import hashlib
-import urllib
+
+# A way to get unquote working with python 2 and 3
+try:
+ from urllib import unquote
+except ImportError:
+ from urllib.parse import unquote
from gi.repository import Nautilus, Gtk, GObject
@@ -18,7 +23,7 @@ class MD5SumPropertyPage(GObject.GObject, Nautilus.PropertyPageProvider):
if file.is_directory():
return
- filename = urllib.unquote(file.get_uri()[7:])
+ filename = unquote(file.get_uri()[7:])
self.property_label = Gtk.Label('MD5Sum')
self.property_label.show()
@@ -33,13 +38,8 @@ class MD5SumPropertyPage(GObject.GObject, Nautilus.PropertyPageProvider):
self.value_label = Gtk.Label()
self.hbox.pack_start(self.value_label, False, False, 0)
- md5sum = hashlib.md5()
- with open(filename,'rb') as f:
- for chunk in iter(lambda: f.read(8192), ''):
- md5sum.update(chunk)
- f.close()
-
- self.value_label.set_text(md5sum.hexdigest())
+ md5sum = hashlib.md5(filename.encode("utf-8")).hexdigest()
+ self.value_label.set_text(md5sum)
self.value_label.show()
return Nautilus.PropertyPage(name="NautilusPython::md5_sum",
diff --git a/examples/open-terminal.py b/examples/open-terminal.py
index 448bc94..60c761f 100644
--- a/examples/open-terminal.py
+++ b/examples/open-terminal.py
@@ -32,9 +32,9 @@ class OpenTerminalExtension(Nautilus.MenuProvider, GObject.GObject):
file = files[0]
if not file.is_directory() or file.get_uri_scheme() != 'file':
return
-
+
item = Nautilus.MenuItem(name='NautilusPython::openterminal_file_item',
- label='Open Terminal 2' ,
+ label='Open Terminal' ,
tip='Open Terminal In %s' % file.get_name())
item.connect('activate', self.menu_activate_cb, file)
return item,
diff --git a/examples/update-file-info-async.py b/examples/update-file-info-async.py
index a926a03..332a043 100644
--- a/examples/update-file-info-async.py
+++ b/examples/update-file-info-async.py
@@ -2,13 +2,20 @@ from gi.repository import Nautilus, GObject
class UpdateFileInfoAsync(GObject.GObject, Nautilus.InfoProvider):
def __init__(self):
+ self.timers = []
pass
def update_file_info_full(self, provider, handle, closure, file):
- print "update_file_info_full"
- gobject.timeout_add_seconds(3, self.update_cb, provider, handle, closure)
+ print("update_file_info_full")
+ self.timers.append(GObject.timeout_add_seconds(3, self.update_cb, provider, handle, closure))
return Nautilus.OperationResult.IN_PROGRESS
def update_cb(self, provider, handle, closure):
- print "update_cb"
+ print("update_cb")
Nautilus.info_provider_update_complete_invoke(closure, provider, handle,
Nautilus.OperationResult.FAILED)
+
+ def cancel_update(self, provider, handle):
+ print("cancel_update")
+ for t in self.timers:
+ GObject.source_remove(t)
+ self.timers = []
diff --git a/src/Makefile.am b/src/Makefile.am
index 285db08..b5030e1 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -8,6 +8,7 @@ INCLUDES = \
$(NAUTILUS_PYTHON_CFLAGS) \
-DPYTHON_VERSION=\"$(PYTHON_VERSION)\" \
-DPY_LIB_LOC="\"$(PYTHON_LIB_LOC)\"" \
+ -DPY_LIB_NAME="\"$(PYTHON_LIB_NAME)\"" \
$(PYTHON_INCLUDES)
nautilus_extensiondir=$(NAUTILUS_EXTENSION_DIR)
diff --git a/src/nautilus-python-object.c b/src/nautilus-python-object.c
index 8bc439c..b60088b 100644
--- a/src/nautilus-python-object.c
+++ b/src/nautilus-python-object.c
@@ -41,6 +41,38 @@
static GObjectClass *parent_class;
+int __PyString_Check(PyObject *obj) {
+#if PY_MAJOR_VERSION >= 3
+ return PyUnicode_Check(obj);
+#else
+ return PyString_Check(obj);
+#endif
+}
+
+char* __PyString_AsString(PyObject *obj) {
+#if PY_MAJOR_VERSION >= 3
+ return PyUnicode_AsUTF8(obj);
+#else
+ return PyString_AsString(obj);
+#endif
+}
+
+PyObject* __PyString_FromString(const char *c) {
+#if PY_MAJOR_VERSION >= 3
+ return PyUnicode_FromString(c);
+#else
+ return PyString_FromString(c);
+#endif
+}
+
+int __PyInt_Check(PyObject *obj) {
+#if PY_MAJOR_VERSION >= 3
+ return PyLong_Check(obj);
+#else
+ return PyInt_Check(obj);
+#endif
+}
+
/* These macros assumes the following things:
* a METHOD_NAME is defined with is a string
* a goto label called beach
@@ -82,7 +114,7 @@ static GObjectClass *parent_class;
#define HANDLE_LIST(py_ret, type, type_name) \
{ \
Py_ssize_t i = 0; \
- if (!PySequence_Check(py_ret) || PyString_Check(py_ret)) \
+ if (!PySequence_Check(py_ret) || __PyString_Check(py_ret)) \
{ \
PyErr_SetString(PyExc_TypeError, \
METHOD_NAME " must return a sequence"); \
@@ -184,7 +216,7 @@ nautilus_python_object_get_widget (NautilusLocationWidgetProvider *provider,
CHECK_OBJECT(object);
CHECK_METHOD_NAME(object->instance);
- py_uri = PyString_FromString(uri);
+ py_uri = __PyString_FromString(uri);
py_ret = PyObject_CallMethod(object->instance, METHOD_PREFIX METHOD_NAME,
"(NN)", py_uri,
@@ -398,14 +430,18 @@ nautilus_python_object_update_file_info (NautilusInfoProvider *provider,
HANDLE_RETVAL(py_ret);
- if (!PyInt_Check(py_ret)) {
+ if (!__PyInt_Check(py_ret)) {
PyErr_SetString(PyExc_TypeError,
METHOD_NAME " must return None or a int");
goto beach;
}
+#if PY_MAJOR_VERSION >= 3
+ ret = PyLong_AsLong(py_ret);
+#else
ret = PyInt_AsLong(py_ret);
-
+#endif
+
beach:
free_pygobject_data(file, NULL);
Py_XDECREF(py_ret);
@@ -489,7 +525,7 @@ nautilus_python_object_get_type (GTypeModule *module,
NULL
};
- debug_enter_args("type=%s", PyString_AsString(PyObject_GetAttrString(type, "__name__")));
+ debug_enter_args("type=%s", __PyString_AsString(PyObject_GetAttrString(type, "__name__")));
info = g_new0 (GTypeInfo, 1);
info->class_size = sizeof (NautilusPythonObjectClass);
@@ -501,7 +537,7 @@ nautilus_python_object_get_type (GTypeModule *module,
Py_INCREF(type);
type_name = g_strdup_printf("%s+NautilusPython",
- PyString_AsString(PyObject_GetAttrString(type, "__name__")));
+ __PyString_AsString(PyObject_GetAttrString(type, "__name__")));
gtype = g_type_module_register_type (module,
G_TYPE_OBJECT,
diff --git a/src/nautilus-python.c b/src/nautilus-python.c
index 6bac4fc..694d555 100644
--- a/src/nautilus-python.c
+++ b/src/nautilus-python.c
@@ -131,7 +131,11 @@ nautilus_python_load_dir (GTypeModule *module,
/* sys.path.insert(0, dirname) */
sys_path = PySys_GetObject("path");
+#if PY_MAJOR_VERSION >= 3
+ py_path = PyUnicode_FromString(dirname);
+#else
py_path = PyString_FromString(dirname);
+#endif
PyList_Insert(sys_path, 0, py_path);
Py_DECREF(py_path);
}
@@ -145,13 +149,12 @@ static gboolean
nautilus_python_init_python (void) {
PyObject *nautilus;
GModule *libpython;
- char *argv[] = { "nautilus", NULL };
if (Py_IsInitialized())
return TRUE;
- debug("g_module_open " PY_LIB_LOC "/libpython" PYTHON_VERSION "." G_MODULE_SUFFIX ".1.0");
- libpython = g_module_open(PY_LIB_LOC "/libpython" PYTHON_VERSION "." G_MODULE_SUFFIX ".1.0", 0);
+ debug("g_module_open " PY_LIB_LOC "/lib" PY_LIB_NAME "." G_MODULE_SUFFIX ".1.0");
+ libpython = g_module_open (PY_LIB_LOC "/lib" PY_LIB_NAME "." G_MODULE_SUFFIX ".1.0", 0);
if (!libpython)
g_warning("g_module_open libpython failed: %s", g_module_error());
@@ -163,6 +166,11 @@ nautilus_python_init_python (void) {
}
debug("PySys_SetArgv");
+#if PY_MAJOR_VERSION >= 3
+ wchar_t *argv[] = { L"thunar", NULL };
+#else
+ char *argv[] = { "thunar", NULL };
+#endif
PySys_SetArgv(1, argv);
if (PyErr_Occurred()) {
PyErr_Print();
@@ -170,7 +178,7 @@ nautilus_python_init_python (void) {
}
debug("Sanitize the python search path");
- PyRun_SimpleString("import sys; sys.path = filter(None, sys.path)");
+ PyRun_SimpleString("import sys; sys.path = [path for path in sys.path if path]");
if (PyErr_Occurred()) {
PyErr_Print();
return FALSE;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]