davemds pushed a commit to branch master.

commit 39e16242a046e238f84e6b35955bdb2bd6573b8e
Author: davemds <[email protected]>
Date:   Sun May 12 19:15:09 2013 +0200

    Python-EFL: implemented ecore.FileMonitor class
---
 INSTALL                              |  2 +-
 TODO                                 |  1 -
 efl/ecore/efl.ecore.pyx              | 12 ++++-
 efl/ecore/efl.ecore_file_monitor.pxi | 81 ++++++++++++++++++++++++++++++++++
 include/efl.ecore.enums.pxd          | 12 +++++
 include/efl.ecore.pxd                | 18 +++++++-
 tests/ecore/test_09_file_monitor.py  | 85 ++++++++++++++++++++++++++++++++++++
 7 files changed, 207 insertions(+), 4 deletions(-)

diff --git a/INSTALL b/INSTALL
index d8c749b..ce5b226 100644
--- a/INSTALL
+++ b/INSTALL
@@ -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
diff --git a/TODO b/TODO
index 486b027..80dddd1 100644
--- a/TODO
+++ b/TODO
@@ -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
diff --git a/efl/ecore/efl.ecore.pyx b/efl/ecore/efl.ecore.pyx
index a554bac..67b9e40 100644
--- a/efl/ecore/efl.ecore.pyx
+++ b/efl/ecore/efl.ecore.pyx
@@ -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()
diff --git a/efl/ecore/efl.ecore_file_monitor.pxi 
b/efl/ecore/efl.ecore_file_monitor.pxi
new file mode 100644
index 0000000..3d9436d
--- /dev/null
+++ b/efl/ecore/efl.ecore_file_monitor.pxi
@@ -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))
diff --git a/include/efl.ecore.enums.pxd b/include/efl.ecore.enums.pxd
index 86268d9..fe72acb 100644
--- a/include/efl.ecore.enums.pxd
+++ b/include/efl.ecore.enums.pxd
@@ -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
diff --git a/include/efl.ecore.pxd b/include/efl.ecore.pxd
index 3d92871..5b7bd26 100644
--- a/include/efl.ecore.pxd
+++ b/include/efl.ecore.pxd
@@ -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)
diff --git a/tests/ecore/test_09_file_monitor.py 
b/tests/ecore/test_09_file_monitor.py
new file mode 100644
index 0000000..9d3519e
--- /dev/null
+++ b/tests/ecore/test_09_file_monitor.py
@@ -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()

-- 

------------------------------------------------------------------------------
Learn Graph Databases - Download FREE O'Reilly Book
"Graph Databases" is the definitive new guide to graph databases and 
their applications. This 200-page book is written by three acclaimed 
leaders in the field. The early access version is available now. 
Download your free book today! http://p.sf.net/sfu/neotech_d2d_may

Reply via email to