Commit 12687a3c authored by Adam Plumb's avatar Adam Plumb

Add support for building with python 3

parent bb5eace2
......@@ -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
......@@ -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>
......
......@@ -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>
......
......@@ -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 &lt; 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 &gt;= 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"/>
......
......@@ -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",
......
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))
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",
......
......@@ -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,
......
......@@ -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 = []
......@@ -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)
......
......@@ -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,
......
......@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment