Python-EFL: implemented ecore.FileMonitor class

This commit is contained in:
Davide Andreoli 2013-05-12 19:15:09 +02:00
parent 6e221b54c5
commit 39e16242a0
7 changed files with 207 additions and 4 deletions

View File

@ -9,7 +9,7 @@
- Tested with Cython 0.17.1
* EFL core library
- eo, evas, ecore, edje, elementary, edbus and emotion
- eo, evas, ecore, edje, emotion and elementary
* pkg-config (http://www.freedesktop.org/wiki/Software/pkg-config)
- Windows executable (and GLib dependency) can be downloaded from

1
TODO
View File

@ -20,7 +20,6 @@ TODO
====
* ecore.Poller
* ecore.FileMonitor
* alert on signal and subprocess module usage (was in python-ecore/ecore/__init__.py)
* evas.SmartObject
* edje: complete the unit tests

View File

@ -190,11 +190,20 @@ ECORE_EXE_TERM_WITH_PARENT = enums.ECORE_EXE_TERM_WITH_PARENT
ECORE_EXE_PRIORITY_INHERIT = 9999
# Ecore_File_Progress_Return:
ECORE_FILE_PROGRESS_CONTINUE = 0
ECORE_FILE_PROGRESS_ABORT = 1
# Ecore_File_Event
ECORE_FILE_EVENT_NONE = enums.ECORE_FILE_EVENT_NONE
ECORE_FILE_EVENT_CREATED_FILE = enums.ECORE_FILE_EVENT_CREATED_FILE
ECORE_FILE_EVENT_CREATED_DIRECTORY = enums.ECORE_FILE_EVENT_CREATED_DIRECTORY
ECORE_FILE_EVENT_DELETED_FILE = enums.ECORE_FILE_EVENT_DELETED_FILE
ECORE_FILE_EVENT_DELETED_DIRECTORY = enums.ECORE_FILE_EVENT_DELETED_DIRECTORY
ECORE_FILE_EVENT_DELETED_SELF = enums.ECORE_FILE_EVENT_DELETED_SELF
ECORE_FILE_EVENT_MODIFIED = enums.ECORE_FILE_EVENT_MODIFIED
ECORE_FILE_EVENT_CLOSED = enums.ECORE_FILE_EVENT_CLOSED
cdef Eina_Bool _ecore_task_cb(void *data) with gil:
cdef Eo obj = <Eo>data
@ -281,5 +290,6 @@ include "efl.ecore_fd_handler.pxi"
include "efl.ecore_events.pxi"
include "efl.ecore_exe.pxi"
include "efl.ecore_file_download.pxi"
include "efl.ecore_file_monitor.pxi"
init()

View File

@ -0,0 +1,81 @@
# Copyright (C) 2007-2013 various contributors (see AUTHORS)
#
# This file is part of Python-EFL.
#
# Python-EFL is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# Python-EFL is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this Python-EFL. If not, see <http://www.gnu.org/licenses/>.
from cpython cimport PyUnicode_AsUTF8String
cdef void _file_monitor_cb(void *data, Ecore_File_Monitor *em, Ecore_File_Event event, const_char *path) with gil:
obj = <FileMonitor>data
try:
obj._exec_monitor(event, path)
except Exception, e:
traceback.print_exc()
cdef class FileMonitor(object):
""" TODOC """
def __init__(self, path, monitor_cb, *args, **kargs):
if not callable(monitor_cb):
raise TypeError("Parameter 'monitor_cb' must be callable")
self.monitor_cb = monitor_cb
self.args = args
self.kargs = kargs
if isinstance(path, unicode): path = PyUnicode_AsUTF8String(path)
self.mon = ecore_file_monitor_add(
<const_char *>path if path is not None else NULL,
_file_monitor_cb, <void *>self)
if not self.mon:
raise SystemError("could not monitor '%s'" % (path))
Py_INCREF(self)
def __dealloc__(self):
if self.mon != NULL:
ecore_file_monitor_del(self.mon)
self.mon = NULL
self.monitor_cb = None
self.args = None
self.kargs = None
def __str__(self):
return "%s(monitor_cb=%s, args=%s, kargs=%s)" % \
(self.__class__.__name__, self.monitor_cb, self.args, self.kargs)
def __repr__(self):
return ("%s(%#x, monitor_cb=%s, args=%s, kargs=%s, refcount=%d)") % \
(self.__class__.__name__, <unsigned long><void *>self,
self.monitor_cb, self.args, self.kargs, PY_REFCOUNT(self))
cdef object _exec_monitor(self, Ecore_File_Event event, const_char *path):
if self.monitor_cb:
return self.monitor_cb(event, _ctouni(path), *self.args, **self.kargs)
return 0
def delete(self):
""" TODOC """
if self.mon != NULL:
ecore_file_monitor_del(self.mon)
self.mon = NULL
Py_DECREF(self)
property path:
""" TODOC """
def __get__(self):
return _ctouni(ecore_file_monitor_path_get(self.mon))

View File

@ -52,3 +52,15 @@ cdef extern from "Ecore.h":
ctypedef enum Ecore_Animator_Source:
ECORE_ANIMATOR_SOURCE_TIMER
ECORE_ANIMATOR_SOURCE_CUSTOM
cdef extern from "Ecore_File.h":
ctypedef enum Ecore_File_Event:
ECORE_FILE_EVENT_NONE
ECORE_FILE_EVENT_CREATED_FILE
ECORE_FILE_EVENT_CREATED_DIRECTORY
ECORE_FILE_EVENT_DELETED_FILE
ECORE_FILE_EVENT_DELETED_DIRECTORY
ECORE_FILE_EVENT_DELETED_SELF
ECORE_FILE_EVENT_MODIFIED
ECORE_FILE_EVENT_CLOSED

View File

@ -18,7 +18,8 @@
from efl cimport *
from efl.c_eo cimport Eo as cEo
from efl.eo cimport Eo
from efl.ecore.enums cimport Ecore_Fd_Handler_Flags, Ecore_Exe_Flags
from efl.ecore.enums cimport Ecore_Fd_Handler_Flags, Ecore_Exe_Flags, \
Ecore_File_Event
cdef extern from "Ecore.h":
@ -165,9 +166,12 @@ cdef extern from "Ecore.h":
cdef extern from "Ecore_File.h":
ctypedef struct Ecore_File_Download_Job
ctypedef struct Ecore_File_Monitor
ctypedef void (*Ecore_File_Download_Completion_Cb)(void *data, const_char *file, int status)
ctypedef int (*Ecore_File_Download_Progress_Cb)(void *data, const_char *file, long int dltotal, long int dlnow, long int ultotal, long int ulnow)
ctypedef void (*Ecore_File_Monitor_Cb)(void *data, Ecore_File_Monitor *em, Ecore_File_Event event, const_char *path)
int ecore_file_init()
int ecore_file_shutdown()
@ -180,6 +184,10 @@ cdef extern from "Ecore_File.h":
void *data,
Ecore_File_Download_Job **job_ret)
Ecore_File_Monitor *ecore_file_monitor_add(const_char *path, Ecore_File_Monitor_Cb func, void *data)
void ecore_file_monitor_del(Ecore_File_Monitor *ecore_file_monitor)
const_char *ecore_file_monitor_path_get(Ecore_File_Monitor *ecore_file_monitor)
####################################################################
# Python classes
@ -316,3 +324,11 @@ cdef class FileDownload:
long int dltotal, long int dlnow,
long int ultotal, long int ulnow)
cdef class FileMonitor:
cdef Ecore_File_Monitor *mon
cdef readonly object monitor_cb
cdef readonly object args
cdef readonly object kargs
cdef object _exec_monitor(self, Ecore_File_Event event, const_char *path)

View File

@ -0,0 +1,85 @@
#!/usr/bin/env python
from efl import ecore
import unittest
import os
import tempfile
counters = [0, 0, 0, 0, 0, 0 , 0, 0]
def monitor_cb(event, path, tmp_path):
""" for reference:
if event == ecore.ECORE_FILE_EVENT_MODIFIED:
print("EVENT_MODIFIED: '%s'" % path)
elif event == ecore.ECORE_FILE_EVENT_CLOSED:
print("EVENT_CLOSED: '%s'" % path)
elif event == ecore.ECORE_FILE_EVENT_CREATED_FILE:
print("ECORE_FILE_EVENT_CREATED_FILE: '%s'" % path)
elif event == ecore.ECORE_FILE_EVENT_CREATED_DIRECTORY:
print("ECORE_FILE_EVENT_CREATED_DIRECTORY: '%s'" % path)
elif event == ecore.ECORE_FILE_EVENT_DELETED_FILE:
print("ECORE_FILE_EVENT_DELETED_FILE: '%s'" % path)
elif event == ecore.ECORE_FILE_EVENT_DELETED_DIRECTORY:
print("ECORE_FILE_EVENT_DELETED_DIRECTORY: '%s'" % path)
elif event == ecore.ECORE_FILE_EVENT_DELETED_SELF:
print("ECORE_FILE_EVENT_DELETED_SELF: '%s'" % path)
"""
counters[event] += 1
def do_stuff(tmp_path, fm):
folder1 = os.path.join(tmp_path, "folder1")
folder2 = os.path.join(tmp_path, "folder2")
file1 = os.path.join(tmp_path, "file1")
file2 = os.path.join(tmp_path, "file2")
# this should trigger two ECORE_FILE_EVENT_CREATED_DIRECTORY
os.mkdir(folder1)
os.mkdir(folder2)
# this should trigger two ECORE_FILE_EVENT_DELETED_DIRECTORY
os.rmdir(folder1)
os.rmdir(folder2)
# this should trigger two ECORE_FILE_EVENT_CREATED_FILE
fp1 = open(file1, 'a')
fp2 = open(file2, 'a')
# this should trigger two ECORE_FILE_EVENT_MODIFIED
fp1.write("nothing to say")
fp2.write("nothing to say")
# this should trigger two ECORE_FILE_EVENT_CLOSED
fp1.close()
fp2.close()
# this should trigger two ECORE_FILE_EVENT_DELETED_FILE
os.remove(file1)
os.remove(file2)
# this should trigger one ECORE_FILE_EVENT_DELETED_SELF !!! we get two
os.rmdir(tmp_path)
class TestFileMonitor(unittest.TestCase):
def testInit(self):
path = tempfile.mkdtemp()
fm = ecore.FileMonitor(path, monitor_cb, path)
self.assertIsInstance(fm, ecore.FileMonitor)
self.assertEqual(fm.path, path)
ecore.Timer(0.1, do_stuff, path, fm)
ecore.Timer(1.0, lambda: ecore.main_loop_quit())
ecore.main_loop_begin()
self.assertEqual(fm.path, path)
fm.delete()
# FIXME: we receive two ECORE_FILE_EVENT_DELETED_SELF, it's wrong
# should be [0, 2, 2, 2, 2, 1, 2, 2]
self.assertEqual(counters, [0, 2, 2, 2, 2, 2, 2, 2])
if __name__ == '__main__':
unittest.main(verbosity=2)
ecore.shutdown()