[pitivi/ges: 159/287] utils: Add logging functions/classes in pitivi/utils



commit 28fa6240f9be8838bf79363bc2df6bef26730caf
Author: Thibault Saunier <thibault saunier collabora com>
Date:   Mon Jan 9 13:22:20 2012 -0300

    utils: Add logging functions/classes in pitivi/utils
    
    No reason to have a special folder for it.

 configure.ac                             |    1 -
 pitivi/Makefile.am                       |    3 +-
 pitivi/application.py                    |    4 +-
 pitivi/encode.py                         |    2 +-
 pitivi/log/Makefile.am                   |   11 --
 pitivi/log/loggable.py                   |   43 -----
 pitivi/log/termcolor.py                  |  213 ----------------------
 pitivi/log/test_log.py                   |  284 -----------------------------
 pitivi/project.py                        |    2 +-
 pitivi/projectmanager.py                 |    2 +-
 pitivi/settings.py                       |    2 +-
 pitivi/sourcelist.py                     |    2 +-
 pitivi/system.py                         |    2 +-
 pitivi/threads.py                        |    2 +-
 pitivi/ui/clipproperties.py              |    2 +-
 pitivi/ui/common.py                      |    2 +-
 pitivi/ui/controller.py                  |    2 +-
 pitivi/ui/effectlist.py                  |    2 +-
 pitivi/ui/encodingdialog.py              |    2 +-
 pitivi/ui/filechooserpreview.py          |    2 +-
 pitivi/ui/filelisterrordialog.py         |    2 +-
 pitivi/ui/gstwidget.py                   |    2 +-
 pitivi/ui/mainwindow.py                  |    2 +-
 pitivi/ui/previewer.py                   |    2 +-
 pitivi/ui/ruler.py                       |    2 +-
 pitivi/ui/sourcelist.py                  |    2 +-
 pitivi/ui/timeline.py                    |    2 +-
 pitivi/ui/timelinecanvas.py              |    2 +-
 pitivi/ui/timelinecontrols.py            |    2 +-
 pitivi/ui/track.py                       |    2 +-
 pitivi/ui/trackobject.py                 |    2 +-
 pitivi/ui/viewer.py                      |    2 +-
 pitivi/undo/undo.py                      |    2 +-
 pitivi/utils/Makefile.am                 |    1 +
 pitivi/utils/align.py                    |    2 +-
 pitivi/utils/extract.py                  |    2 +-
 pitivi/{log/log.py => utils/loggable.py} |  264 +++++++++++++++++++++++++--
 pitivi/utils/misc.py                     |    2 +-
 pitivi/utils/timeline.py                 |    2 +-
 tests/Makefile.am                        |    1 +
 tests/runtests.py                        |    2 +-
 tests/test_log.py                        |  288 ++++++++++++++++++++++++++++++
 42 files changed, 569 insertions(+), 606 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 09a1e42..81fa597 100644
--- a/configure.ac
+++ b/configure.ac
@@ -87,7 +87,6 @@ help/Makefile
 pitivi/Makefile
 pitivi/configure.py
 pitivi/ui/Makefile
-pitivi/log/Makefile
 pitivi/undo/Makefile
 pitivi/utils/Makefile
 pitivi.spec
diff --git a/pitivi/Makefile.am b/pitivi/Makefile.am
index a4b93a1..1f144b5 100644
--- a/pitivi/Makefile.am
+++ b/pitivi/Makefile.am
@@ -1,8 +1,7 @@
 SUBDIRS = \
 	ui 		\
 	utils	\
-	undo	\
-	log
+	undo
 
 pitividir = $(libdir)/pitivi/python/pitivi
 
diff --git a/pitivi/application.py b/pitivi/application.py
index 34cc562..270c47c 100644
--- a/pitivi/application.py
+++ b/pitivi/application.py
@@ -43,8 +43,8 @@ from pitivi.settings import GlobalSettings
 from pitivi.threads import ThreadMaster
 from pitivi.signalinterface import Signallable
 from pitivi.system import getSystem
-from pitivi.log.loggable import Loggable
-from pitivi.log import log
+from pitivi.utils.loggable import Loggable
+import pitivi.utils.loggable as log
 from pitivi.ui.mainwindow import PitiviMainWindow
 from pitivi.projectmanager import ProjectManager, ProjectLogObserver
 from pitivi.undo.undo import UndoableActionLog, DebugActionLogObserver
diff --git a/pitivi/encode.py b/pitivi/encode.py
index 06f7eec..a008817 100644
--- a/pitivi/encode.py
+++ b/pitivi/encode.py
@@ -25,7 +25,7 @@ Encoding-related utilities and classes
 
 import gst
 
-import pitivi.log.log as log
+import pitivi.utils.loggable as log
 
 
 def get_compatible_sink_pad(factoryname, caps):
diff --git a/pitivi/project.py b/pitivi/project.py
index 22bd4d3..ad8d0ab 100644
--- a/pitivi/project.py
+++ b/pitivi/project.py
@@ -27,7 +27,7 @@ import ges
 import gst
 
 from pitivi.utils.misc import Seeker
-from pitivi.log.loggable import Loggable
+from pitivi.utils.loggable import Loggable
 from pitivi.sourcelist import SourceList
 from pitivi.settings import MultimediaSettings
 from pitivi.signalinterface import Signallable
diff --git a/pitivi/projectmanager.py b/pitivi/projectmanager.py
index c7bfb3d..21a50f2 100644
--- a/pitivi/projectmanager.py
+++ b/pitivi/projectmanager.py
@@ -30,7 +30,7 @@ from pwd import getpwuid
 
 from pitivi.project import Project
 from pitivi.signalinterface import Signallable
-from pitivi.log.loggable import Loggable
+from pitivi.utils.loggable import Loggable
 from pitivi.undo.undo import UndoableAction
 
 
diff --git a/pitivi/settings.py b/pitivi/settings.py
index 3c6488c..f0bdf7b 100644
--- a/pitivi/settings.py
+++ b/pitivi/settings.py
@@ -33,7 +33,7 @@ from gettext import gettext as _
 from pitivi.signalinterface import Signallable
 from pitivi.encode import available_combinations, \
      get_compatible_sink_caps
-from pitivi.log.loggable import Loggable
+from pitivi.utils.loggable import Loggable
 
 
 def get_bool_env(var):
diff --git a/pitivi/sourcelist.py b/pitivi/sourcelist.py
index b484627..5108a63 100644
--- a/pitivi/sourcelist.py
+++ b/pitivi/sourcelist.py
@@ -28,7 +28,7 @@ import urllib
 import gst
 
 from pitivi.signalinterface import Signallable
-from pitivi.log.loggable import Loggable
+from pitivi.utils.loggable import Loggable
 
 
 class SourceListError(Exception):
diff --git a/pitivi/system.py b/pitivi/system.py
index 3f002a5..881182a 100644
--- a/pitivi/system.py
+++ b/pitivi/system.py
@@ -23,7 +23,7 @@
 import os
 
 from pitivi.configure import APPNAME
-from pitivi.log.loggable import Loggable
+from pitivi.utils.loggable import Loggable
 from pitivi.signalinterface import Signallable
 
 
diff --git a/pitivi/threads.py b/pitivi/threads.py
index f274faa..e4724a0 100644
--- a/pitivi/threads.py
+++ b/pitivi/threads.py
@@ -24,7 +24,7 @@ Threading support
 
 import threading
 from pitivi.signalinterface import Signallable
-from pitivi.log.loggable import Loggable
+from pitivi.utils.loggable import Loggable
 
 #
 # Following code was freely adapted by code from:
diff --git a/pitivi/ui/clipproperties.py b/pitivi/ui/clipproperties.py
index 04a2872..038e7b3 100644
--- a/pitivi/ui/clipproperties.py
+++ b/pitivi/ui/clipproperties.py
@@ -33,7 +33,7 @@ from gettext import gettext as _
 from pitivi.utils.misc import Seeker
 from pitivi.check import soft_deps
 from pitivi.configure import get_ui_dir
-from pitivi.log.loggable import Loggable
+from pitivi.utils.loggable import Loggable
 from pitivi.effects import AUDIO_EFFECT, VIDEO_EFFECT
 
 
diff --git a/pitivi/ui/common.py b/pitivi/ui/common.py
index 40628f2..d3a314c 100644
--- a/pitivi/ui/common.py
+++ b/pitivi/ui/common.py
@@ -11,7 +11,7 @@ from gettext import ngettext
 from gettext import gettext as _
 
 from pitivi.settings import GlobalSettings
-from pitivi.log.log import doLog, ERROR
+from pitivi.utils.loggable import doLog, ERROR
 
 GlobalSettings.addConfigSection("user-interface")
 LAYER_HEIGHT_EXPANDED = 50
diff --git a/pitivi/ui/controller.py b/pitivi/ui/controller.py
index e6b4b15..e28a09d 100644
--- a/pitivi/ui/controller.py
+++ b/pitivi/ui/controller.py
@@ -22,7 +22,7 @@
 import gtk.gdk
 
 from pitivi.ui.point import Point
-from pitivi.log.loggable import Loggable
+from pitivi.utils.loggable import Loggable
 from pitivi.receiver import receiver, handler
 
 # Controllers are reusable and implement specific behaviors. Currently this
diff --git a/pitivi/ui/effectlist.py b/pitivi/ui/effectlist.py
index cfa3f71..338064c 100644
--- a/pitivi/ui/effectlist.py
+++ b/pitivi/ui/effectlist.py
@@ -32,7 +32,7 @@ import pitivi.ui.dnd as dnd
 
 from pitivi.configure import get_pixmap_dir
 
-from pitivi.log.loggable import Loggable
+from pitivi.utils.loggable import Loggable
 from pitivi.effects import AUDIO_EFFECT, VIDEO_EFFECT
 from pitivi.ui.common import SPACING
 from pitivi.settings import GlobalSettings
diff --git a/pitivi/ui/encodingdialog.py b/pitivi/ui/encodingdialog.py
index ef42c59..a4edcb5 100644
--- a/pitivi/ui/encodingdialog.py
+++ b/pitivi/ui/encodingdialog.py
@@ -37,7 +37,7 @@ from pitivi.utils.misc import togglePlayback, Seeker, beautify_ETA
 from pitivi.settings import MultimediaSettings
 from pitivi.signalinterface import Signallable
 
-from pitivi.log.loggable import Loggable
+from pitivi.utils.loggable import Loggable
 from pitivi.ui.gstwidget import GstElementSettingsDialog
 from pitivi.ui.ripple_update_group import RippleUpdateGroup
 from pitivi.ui.common import model, frame_rates, audio_rates, audio_depths, \
diff --git a/pitivi/ui/filechooserpreview.py b/pitivi/ui/filechooserpreview.py
index 7b1f69b..38e9b3c 100644
--- a/pitivi/ui/filechooserpreview.py
+++ b/pitivi/ui/filechooserpreview.py
@@ -5,7 +5,7 @@ import gtk
 import pango
 import os
 
-from pitivi.log.loggable import Loggable
+from pitivi.utils.loggable import Loggable
 from pitivi.ui.common import beautify_stream
 from pitivi.utils.misc import beautify_length, uri_is_valid
 from pitivi.configure import get_pixmap_dir
diff --git a/pitivi/ui/filelisterrordialog.py b/pitivi/ui/filelisterrordialog.py
index 14d90f4..ff7e8ce 100644
--- a/pitivi/ui/filelisterrordialog.py
+++ b/pitivi/ui/filelisterrordialog.py
@@ -32,7 +32,7 @@ from gettext import gettext as _
 from urllib import unquote
 from pitivi.configure import get_ui_dir
 from pitivi.signalinterface import Signallable
-from pitivi.log.loggable import Loggable
+from pitivi.utils.loggable import Loggable
 
 
 class FileListErrorDialog(Signallable, Loggable):
diff --git a/pitivi/ui/gstwidget.py b/pitivi/ui/gstwidget.py
index 67fb3e5..6e241ff 100644
--- a/pitivi/ui/gstwidget.py
+++ b/pitivi/ui/gstwidget.py
@@ -30,7 +30,7 @@ import os
 import ges
 
 from gettext import gettext as _
-from pitivi.log.loggable import Loggable
+from pitivi.utils.loggable import Loggable
 from pitivi.configure import get_ui_dir
 import pitivi.ui.dynamic as dynamic
 from pitivi.ui.common import SPACING
diff --git a/pitivi/ui/mainwindow.py b/pitivi/ui/mainwindow.py
index 313a75a..527239f 100644
--- a/pitivi/ui/mainwindow.py
+++ b/pitivi/ui/mainwindow.py
@@ -35,7 +35,7 @@ from gettext import gettext as _
 from gtk import RecentManager
 
 
-from pitivi.log.loggable import Loggable
+from pitivi.utils.loggable import Loggable
 from pitivi.settings import GlobalSettings
 from pitivi.sourcelist import SourceListError
 
diff --git a/pitivi/ui/previewer.py b/pitivi/ui/previewer.py
index 1d7a9c1..40cf9ad 100644
--- a/pitivi/ui/previewer.py
+++ b/pitivi/ui/previewer.py
@@ -33,7 +33,7 @@ from pitivi.configure import get_pixmap_dir
 from pitivi.signalinterface import Signallable
 from pitivi.settings import GlobalSettings
 from pitivi.ui.zoominterface import Zoomable
-from pitivi.log.loggable import Loggable
+from pitivi.utils.loggable import Loggable
 from pitivi.thumbnailcache import ThumbnailCache
 from pitivi.ui.prefs import PreferencesDialog
 from pitivi.receiver import receiver, handler
diff --git a/pitivi/ui/ruler.py b/pitivi/ui/ruler.py
index 0f8145a..58f18c6 100644
--- a/pitivi/ui/ruler.py
+++ b/pitivi/ui/ruler.py
@@ -30,7 +30,7 @@ import gst
 from pitivi.utils.misc import Seeker
 
 from pitivi.ui.zoominterface import Zoomable
-from pitivi.log.loggable import Loggable
+from pitivi.utils.loggable import Loggable
 from pitivi.utils.misc import time_to_string
 
 
diff --git a/pitivi/ui/sourcelist.py b/pitivi/ui/sourcelist.py
index 7fd570c..74cb2eb 100644
--- a/pitivi/ui/sourcelist.py
+++ b/pitivi/ui/sourcelist.py
@@ -42,7 +42,7 @@ from pitivi.ui.pathwalker import PathWalker, quote_uri
 from pitivi.ui.filelisterrordialog import FileListErrorDialog
 from pitivi.ui.common import beautify_info, info_name, \
     SPACING, PADDING
-from pitivi.log.loggable import Loggable
+from pitivi.utils.loggable import Loggable
 from pitivi.ui.filechooserpreview import PreviewWidget
 
 SHOW_TREEVIEW = 1
diff --git a/pitivi/ui/timeline.py b/pitivi/ui/timeline.py
index 45ee0a4..47208f5 100644
--- a/pitivi/ui/timeline.py
+++ b/pitivi/ui/timeline.py
@@ -35,7 +35,7 @@ from gettext import gettext as _
 
 from zoominterface import Zoomable
 from pitivi.check import soft_deps
-from pitivi.log.loggable import Loggable
+from pitivi.utils.loggable import Loggable
 from timelinecanvas import TimelineCanvas
 from timelinecontrols import TimelineControls
 from pitivi.effects import AUDIO_EFFECT, VIDEO_EFFECT
diff --git a/pitivi/ui/timelinecanvas.py b/pitivi/ui/timelinecanvas.py
index 778d13a..01281ae 100644
--- a/pitivi/ui/timelinecanvas.py
+++ b/pitivi/ui/timelinecanvas.py
@@ -23,7 +23,7 @@ import gtk
 import goocanvas
 from gettext import gettext as _
 
-from pitivi.log.loggable import Loggable
+from pitivi.utils.loggable import Loggable
 from pitivi.receiver import receiver, handler
 from pitivi.ui.track import Track
 from pitivi.ui.trackobject import TrackObject
diff --git a/pitivi/ui/timelinecontrols.py b/pitivi/ui/timelinecontrols.py
index 37ebcdc..eadd6d3 100644
--- a/pitivi/ui/timelinecontrols.py
+++ b/pitivi/ui/timelinecontrols.py
@@ -2,7 +2,7 @@ import gtk
 from pitivi.receiver import receiver, handler
 from gettext import gettext as _
 from common import LAYER_HEIGHT_EXPANDED, LAYER_SPACING
-from pitivi.log.loggable import Loggable
+from pitivi.utils.loggable import Loggable
 
 TRACK_CONTROL_WIDTH = 75
 
diff --git a/pitivi/ui/track.py b/pitivi/ui/track.py
index c316e6f..0dc57c1 100644
--- a/pitivi/ui/track.py
+++ b/pitivi/ui/track.py
@@ -24,7 +24,7 @@ import goocanvas
 import ges
 import gobject
 
-from pitivi.log.loggable import Loggable
+from pitivi.utils.loggable import Loggable
 from pitivi.ui.zoominterface import Zoomable
 from pitivi.receiver import receiver, handler
 from pitivi.ui.trackobject import TrackObject
diff --git a/pitivi/ui/trackobject.py b/pitivi/ui/trackobject.py
index 4506d09..449e30c 100644
--- a/pitivi/ui/trackobject.py
+++ b/pitivi/ui/trackobject.py
@@ -14,7 +14,7 @@ from common import LAYER_HEIGHT_EXPANDED, LAYER_HEIGHT_COLLAPSED
 from common import LAYER_SPACING, unpack_cairo_pattern, unpack_cairo_gradient
 
 from pitivi.ui.point import Point
-from pitivi.log.loggable import Loggable
+from pitivi.utils.loggable import Loggable
 from pitivi.settings import GlobalSettings
 from pitivi.receiver import receiver, handler
 from pitivi.ui.prefs import PreferencesDialog
diff --git a/pitivi/ui/viewer.py b/pitivi/ui/viewer.py
index afb273d..a82d598 100644
--- a/pitivi/ui/viewer.py
+++ b/pitivi/ui/viewer.py
@@ -27,7 +27,7 @@ import cairo
 
 from gettext import gettext as _
 
-from pitivi.log.loggable import Loggable
+from pitivi.utils.loggable import Loggable
 from pitivi.settings import GlobalSettings
 from pitivi.utils.misc import togglePlayback
 from pitivi.ui.common import SPACING, hex_to_rgb
diff --git a/pitivi/undo/undo.py b/pitivi/undo/undo.py
index bcf6582..f6b14a3 100644
--- a/pitivi/undo/undo.py
+++ b/pitivi/undo/undo.py
@@ -20,7 +20,7 @@
 # Boston, MA 02110-1301, USA.
 
 from pitivi.signalinterface import Signallable
-from pitivi.log.loggable import Loggable
+from pitivi.utils.loggable import Loggable
 
 
 class UndoError(Exception):
diff --git a/pitivi/utils/Makefile.am b/pitivi/utils/Makefile.am
index 1d1f076..afc42b2 100644
--- a/pitivi/utils/Makefile.am
+++ b/pitivi/utils/Makefile.am
@@ -6,6 +6,7 @@ utils_PYTHON = 	\
 	alignalgs.py    \
 	extract.py      \
 	timeline.py     \
+	loggable.py     \
 	misc.py
 
 clean-local:
diff --git a/pitivi/utils/align.py b/pitivi/utils/align.py
index 9102b6a..55343bf 100644
--- a/pitivi/utils/align.py
+++ b/pitivi/utils/align.py
@@ -33,7 +33,7 @@ except ImportError:
 import gobject
 import gst
 from pitivi.utils.misc import beautify_ETA, call_false
-from pitivi.log.loggable import Loggable
+from pitivi.utils.loggable import Loggable
 from pitivi.utils.alignalgs import rigidalign
 
 
diff --git a/pitivi/utils/extract.py b/pitivi/utils/extract.py
index cd01b79..9467b54 100644
--- a/pitivi/utils/extract.py
+++ b/pitivi/utils/extract.py
@@ -30,7 +30,7 @@ import gst
 from collections import deque
 from pitivi.elements.singledecodebin import SingleDecodeBin
 from pitivi.elements.extractionsink import ExtractionSink
-from pitivi.log.loggable import Loggable
+from pitivi.utils.loggable import Loggable
 from pitivi.utils.misc import pipeline
 
 
diff --git a/pitivi/log/log.py b/pitivi/utils/loggable.py
similarity index 74%
rename from pitivi/log/log.py
rename to pitivi/utils/loggable.py
index 6cb6cfa..ad1f3a7 100644
--- a/pitivi/log/log.py
+++ b/pitivi/utils/loggable.py
@@ -1,20 +1,23 @@
-# -*- Mode: Python; test-case-name: test_log -*-
-# vi:si:et:sw=4:sts=4:ts=4
-
-# This file is released under the standard PSF license.
-
-"""
-Logging module.
-
-Five levels of log information are defined.
-These are, in order of decreasing verbosity: log, debug, info, warning, error.
-
-This module provides a Loggable class for objects, as well as various
-convenience methods for logging in general, and for logging with Twisted
-and failures in particular.
-
-Maintainer: U{Thomas Vander Stichele <thomas at apestaart dot org>}
-"""
+# PiTiVi , Non-linear video editor
+#
+#       pitivi/log/loggable.py
+#
+# Copyright (c) 2009, Alessandro Decina <alessandro decina collabora co uk>
+#
+# This program 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.
+#
+# This program 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 program; if not, write to the
+# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+# Boston, MA 02110-1301, USA.
 
 import errno
 import sys
@@ -25,6 +28,7 @@ import types
 import traceback
 import thread
 
+
 # environment variables controlling levels for each category
 _DEBUG = "*:1"
 # name of the environment variable controlling our logging
@@ -63,6 +67,208 @@ _FORMATTED_LEVELS = []
 _LEVEL_NAMES = ['ERROR', 'WARN', 'INFO', 'DEBUG', 'LOG']
 
 
+class TerminalController:
+    """
+    A class that can be used to portably generate formatted output to
+    a terminal.
+
+    `TerminalController` defines a set of instance variables whose
+    values are initialized to the control sequence necessary to
+    perform a given action.  These can be simply included in normal
+    output to the terminal:
+
+        >>> term = TerminalController()
+        >>> print 'This is '+term.GREEN+'green'+term.NORMAL
+
+    Alternatively, the `render()` method can used, which replaces
+    '${action}' with the string required to perform 'action':
+
+        >>> term = TerminalController()
+        >>> print term.render('This is ${GREEN}green${NORMAL}')
+
+    If the terminal doesn't support a given action, then the value of
+    the corresponding instance variable will be set to ''.  As a
+    result, the above code will still work on terminals that do not
+    support color, except that their output will not be colored.
+    Also, this means that you can test whether the terminal supports a
+    given action by simply testing the truth value of the
+    corresponding instance variable:
+
+        >>> term = TerminalController()
+        >>> if term.CLEAR_SCREEN:
+        ...     print 'This terminal supports clearning the screen.'
+
+    Finally, if the width and height of the terminal are known, then
+    they will be stored in the `COLS` and `LINES` attributes.
+    """
+    # Cursor movement:
+    BOL = ''             # : Move the cursor to the beginning of the line
+    UP = ''              # : Move the cursor up one line
+    DOWN = ''            # : Move the cursor down one line
+    LEFT = ''            # : Move the cursor left one char
+    RIGHT = ''           # : Move the cursor right one char
+
+    # Deletion:
+    CLEAR_SCREEN = ''    # : Clear the screen and move to home position
+    CLEAR_EOL = ''       # : Clear to the end of the line.
+    CLEAR_BOL = ''       # : Clear to the beginning of the line.
+    CLEAR_EOS = ''       # : Clear to the end of the screen
+
+    # Output modes:
+    BOLD = ''            # : Turn on bold mode
+    BLINK = ''           # : Turn on blink mode
+    DIM = ''             # : Turn on half-bright mode
+    REVERSE = ''         # : Turn on reverse-video mode
+    NORMAL = ''          # : Turn off all modes
+
+    # Cursor display:
+    HIDE_CURSOR = ''     # : Make the cursor invisible
+    SHOW_CURSOR = ''     # : Make the cursor visible
+
+    # Terminal size:
+    COLS = None          # : Width of the terminal (None for unknown)
+    LINES = None         # : Height of the terminal (None for unknown)
+
+    # Foreground colors:
+    BLACK = BLUE = GREEN = CYAN = RED = MAGENTA = YELLOW = WHITE = ''
+
+    # Background colors:
+    BG_BLACK = BG_BLUE = BG_GREEN = BG_CYAN = ''
+    BG_RED = BG_MAGENTA = BG_YELLOW = BG_WHITE = ''
+
+    _STRING_CAPABILITIES = """
+    BOL=cr UP=cuu1 DOWN=cud1 LEFT=cub1 RIGHT=cuf1
+    CLEAR_SCREEN=clear CLEAR_EOL=el CLEAR_BOL=el1 CLEAR_EOS=ed BOLD=bold
+    BLINK=blink DIM=dim REVERSE=rev UNDERLINE=smul NORMAL=sgr0
+    HIDE_CURSOR=cinvis SHOW_CURSOR=cnorm""".split()
+    _COLORS = """BLACK BLUE GREEN CYAN RED MAGENTA YELLOW WHITE""".split()
+    _ANSICOLORS = "BLACK RED GREEN YELLOW BLUE MAGENTA CYAN WHITE".split()
+
+    def __init__(self, term_stream=sys.stdout):
+        """
+        Create a `TerminalController` and initialize its attributes
+        with appropriate values for the current terminal.
+        `term_stream` is the stream that will be used for terminal
+        output; if this stream is not a tty, then the terminal is
+        assumed to be a dumb terminal (i.e., have no capabilities).
+        """
+        # Curses isn't available on all platforms
+        try:
+            import curses
+        except ImportError:
+            return
+
+        # If the stream isn't a tty, then assume it has no capabilities.
+        if not term_stream.isatty():
+            return
+
+        # Check the terminal type.  If we fail, then assume that the
+        # terminal has no capabilities.
+        try:
+            curses.setupterm()
+        except:
+            return
+
+        # Look up numeric capabilities.
+        self.COLS = curses.tigetnum('cols')
+        self.LINES = curses.tigetnum('lines')
+
+        # Look up string capabilities.
+        for capability in self._STRING_CAPABILITIES:
+            (attrib, cap_name) = capability.split('=')
+            setattr(self, attrib, self._tigetstr(cap_name) or '')
+
+        # Colors
+        set_fg = self._tigetstr('setf')
+        if set_fg:
+            for i, color in zip(range(len(self._COLORS)), self._COLORS):
+                setattr(self, color, curses.tparm(set_fg, i) or '')
+        set_fg_ansi = self._tigetstr('setaf')
+        if set_fg_ansi:
+            for i, color in zip(range(len(self._ANSICOLORS)),
+                                self._ANSICOLORS):
+                setattr(self, color, curses.tparm(set_fg_ansi, i) or '')
+        set_bg = self._tigetstr('setb')
+        if set_bg:
+            for i, color in zip(range(len(self._COLORS)), self._COLORS):
+                setattr(self, 'BG_' + color, curses.tparm(set_bg, i) or '')
+        set_bg_ansi = self._tigetstr('setab')
+        if set_bg_ansi:
+            for i, color in zip(range(len(self._ANSICOLORS)),
+                                self._ANSICOLORS):
+                setattr(self, 'BG_' + color, curses.tparm(set_bg_ansi, i) or '')
+
+    def _tigetstr(self, cap_name):
+        # String capabilities can include "delays" of the form "$<2>".
+        # For any modern terminal, we should be able to just ignore
+        # these, so strip them out.
+        import curses
+        cap = curses.tigetstr(cap_name) or ''
+        return re.sub(r'\$<\d+>[/*]?', '', cap)
+
+    def render(self, template):
+        """
+        Replace each $-substitutions in the given template string with
+        the corresponding terminal control string (if it's defined) or
+        '' (if it's not).
+        """
+        return re.sub(r'\$\$|\${\w+}', self._render_sub, template)
+
+    def _render_sub(self, match):
+        s = match.group()
+        if s == '$$':
+            return s
+        else:
+            return getattr(self, s[2:-1])
+
+#######################################################################
+# Example use case: progress bar
+#######################################################################
+
+
+class ProgressBar:
+    """
+    A 3-line progress bar, which looks like::
+
+                                Header
+        20% [===========----------------------------------]
+                           progress message
+
+    The progress bar is colored, if the terminal supports color
+    output; and adjusts to the width of the terminal.
+    """
+    BAR = '%3d%% ${GREEN}[${BOLD}%s%s${NORMAL}${GREEN}]${NORMAL}\n'
+    HEADER = '${BOLD}${CYAN}%s${NORMAL}\n\n'
+
+    def __init__(self, term, header):
+        self.term = term
+        if not (self.term.CLEAR_EOL and self.term.UP and self.term.BOL):
+            raise ValueError("Terminal isn't capable enough -- you "
+                             "should use a simpler progress dispaly.")
+        self.width = self.term.COLS or 75
+        self.bar = term.render(self.BAR)
+        self.header = self.term.render(self.HEADER % header.center(self.width))
+        self.cleared = 1  # : true if we haven't drawn the bar yet.
+        self.update(0, '')
+
+    def update(self, percent, message):
+        if self.cleared:
+            sys.stdout.write(self.header)
+            self.cleared = 0
+        n = int((self.width - 10) * percent)
+        sys.stdout.write(
+            self.term.BOL + self.term.UP + self.term.CLEAR_EOL +
+            (self.bar % (100 * percent, '=' * n, '-' * (self.width - 10 - n))) +
+            self.term.CLEAR_EOL + message.center(self.width))
+
+    def clear(self):
+        if not self.cleared:
+            sys.stdout.write(self.term.BOL + self.term.CLEAR_EOL +
+                             self.term.UP + self.term.CLEAR_EOL +
+                             self.term.UP + self.term.CLEAR_EOL)
+            self.cleared = 1
+
+
 def getLevelName(level):
     """
     Return the name of a log level.
@@ -710,7 +916,7 @@ def outputToFiles(stdout=None, stderr=None):
 # base class for loggable objects
 
 
-class Loggable(object):
+class BaseLoggable(object):
     """
     Base class for objects that want to be able to log messages with
     different level of severity.  The levels are, in order from least
@@ -917,7 +1123,7 @@ def logTwisted():
 # expects a bound method
 
 
-class TwistedLogObserver(Loggable):
+class TwistedLogObserver(BaseLoggable):
     """
     Twisted log observer that integrates with our logging.
     """
@@ -971,3 +1177,23 @@ class TwistedLogObserver(Loggable):
 
     def clearIgnores(self):
         self._ignoreErrors = []
+
+
+class Loggable(BaseLoggable):
+    def __init__(self, logCategory=None):
+        if logCategory:
+            self.logCategory = logCategory
+        elif not hasattr(self, 'logCategory'):
+            self.logCategory = self.__class__.__name__.lower()
+
+    def logObjectName(self):
+        res = BaseLoggable.logObjectName(self)
+        if not res:
+            return "<%s at 0x%x>" % (self.__class__.__name__, id(self))
+        return res
+
+    def error(self, format, *args):
+        if _canShortcutLogging(self.logCategory, ERROR):
+            return
+        doLog(ERROR, self.logObjectName(), self.logCategory,
+            format, self.logFunction(*args), where=-2)
diff --git a/pitivi/utils/misc.py b/pitivi/utils/misc.py
index 9de4a1c..76b81f7 100644
--- a/pitivi/utils/misc.py
+++ b/pitivi/utils/misc.py
@@ -33,7 +33,7 @@ import time
 
 from pitivi.configure import APPMANUALURL_OFFLINE, APPMANUALURL_ONLINE
 from pitivi.signalinterface import Signallable
-import pitivi.log.log as log
+import pitivi.utils.loggable as log
 from gettext import ngettext
 try:
     import cProfile
diff --git a/pitivi/utils/timeline.py b/pitivi/utils/timeline.py
index 981a698..b98f425 100644
--- a/pitivi/utils/timeline.py
+++ b/pitivi/utils/timeline.py
@@ -25,7 +25,7 @@ import ges
 from gst import SECOND
 
 from pitivi.utils.misc import infinity
-from pitivi.log.loggable import Loggable
+from pitivi.utils.loggable import Loggable
 from pitivi.signalinterface import Signallable
 
 #from pitivi.utils.align import AutoAligner
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 0ec97d3..45e3695 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -13,6 +13,7 @@ tests = \
 	test_undo.py \
 	test_utils.py \
 	test_system.py \
+	test_log.py \
 	test_system_gnome.py
 
 integration_tests = \
diff --git a/tests/runtests.py b/tests/runtests.py
index e3f7c2e..a94a794 100644
--- a/tests/runtests.py
+++ b/tests/runtests.py
@@ -21,7 +21,7 @@ verbosity = 1
 if 'VERBOSE' in os.environ:
     descriptions = 2
     verbosity = 2
-from pitivi.log import log
+from pitivi.utils import loggable as log
 log.init('PITIVI_DEBUG', 1)
 
 # Make available to configure.py the top level dir.
diff --git a/tests/test_log.py b/tests/test_log.py
new file mode 100644
index 0000000..103757c
--- /dev/null
+++ b/tests/test_log.py
@@ -0,0 +1,288 @@
+# -*- Mode: Python; test-case-name: test_log -*-
+# vi:si:et:sw=4:sts=4:ts=4
+#
+# Flumotion - a streaming media server
+# Copyright (C) 2004,2005,2006,2007 Fluendo, S.L. (www.fluendo.com).
+# All rights reserved.
+
+# This file may be distributed and/or modified under the terms of
+# the GNU General Public License version 2 as published by
+# the Free Software Foundation.
+# This file is distributed without any warranty; without even the implied
+# warranty of merchantability or fitness for a particular purpose.
+# See "LICENSE.GPL" in the source distribution for more information.
+
+# Licensees having purchased or holding a valid Flumotion Advanced
+# Streaming Server license may use this file in accordance with the
+# Flumotion Advanced Streaming Server Commercial License Agreement.
+# See "LICENSE.Flumotion" in the source distribution for more information.
+
+# Headers in this file shall remain intact.
+
+
+###
+# FIXME me all
+###
+#from twisted.trial import unittest
+
+#from pitivi.utils import loggable as log
+
+#__version__ = "$Rev: 7162 $"
+
+
+#class LogTester(log.Loggable):
+    #logCategory = 'testlog'
+
+
+#class LogFunctionTester(log.Loggable):
+
+    #def logFunction(self, format, *args):
+        #return (("override " + format), ) + args[1:]
+
+
+#class TestLog(unittest.TestCase):
+
+    #def setUp(self):
+        #self.category = self.level = self.message = None
+        #self.tester = LogTester()
+        ## we want to remove the default handler so it doesn't show up stuff
+        #log.reset()
+
+    ## just test for parsing semi- or non-valid FLU_DEBUG variables
+
+    #def testSetDebug(self):
+        #log.setDebug(":5")
+        #log.setDebug("*")
+        #log.setDebug("5")
+
+    ## test for adding a log handler
+
+    #def handler(self, level, object, category, file, line, message):
+        #self.level = level
+        #self.object = object
+        #self.category = category
+        #self.file = file
+        #self.line = line
+        #self.message = message
+
+    #def testLimitInvisible(self):
+        #log.setDebug("testlog:3")
+        #log.addLimitedLogHandler(self.handler)
+
+        ## log 2 we shouldn't get
+        #self.tester.log("not visible")
+        #assert not self.category
+        #assert not self.level
+        #assert not self.message
+
+        #self.tester.debug("not visible")
+        #assert not self.category
+        #assert not self.level
+        #assert not self.message
+
+    #def testLimitedVisible(self):
+        #log.setDebug("testlog:3")
+        #log.addLimitedLogHandler(self.handler)
+
+        ## log 3 we should get
+        #self.tester.info("visible")
+        #assert self.category == 'testlog'
+        #assert self.level == log.INFO
+        #assert self.message == 'visible'
+
+        #self.tester.warning("also visible")
+        #assert self.category == 'testlog'
+        #assert self.level == log.WARN
+        #assert self.message == 'also visible'
+
+    #def testFormatStrings(self):
+        #log.setDebug("testlog:3")
+        #log.addLimitedLogHandler(self.handler)
+
+        #self.tester.info("%d %s", 42, 'the answer')
+        #assert self.category == 'testlog'
+        #assert self.level == log.INFO
+        #assert self.message == '42 the answer'
+
+    #def testLimitedError(self):
+        #log.setDebug("testlog:3")
+        #log.addLimitedLogHandler(self.handler)
+
+        #self.assertRaises(SystemExit, self.tester.error, "error")
+        #assert self.category == 'testlog'
+        #assert self.level == log.ERROR
+        #assert self.message == 'error'
+
+    #def testLogHandlerLimitedLevels(self):
+        #log.setDebug("testlog:3")
+        #log.addLimitedLogHandler(self.handler)
+
+        ## now try debug and log again too
+        #log.setDebug("testlog:5")
+
+        #self.tester.debug("debug")
+        #assert self.category == 'testlog'
+        #assert self.level == log.DEBUG
+        #assert self.message == 'debug'
+
+        #self.tester.log("log")
+        #assert self.category == 'testlog'
+        #assert self.level == log.LOG
+        #assert self.message == 'log'
+
+    ## test that we get all log messages
+
+    #def testLogHandler(self):
+        #log.setDebug("testlog:3")
+        #log.addLogHandler(self.handler)
+
+        #self.tester.log("visible")
+        #assert self.message == 'visible'
+
+        #self.tester.warning("also visible")
+        #assert self.message == 'also visible'
+
+
+#class TestOwnLogHandler(unittest.TestCase):
+
+    #def setUp(self):
+        #self.category = self.level = self.message = None
+        #self.tester = LogFunctionTester()
+
+    #def handler(self, level, object, category, file, line, message):
+        #self.level = level
+        #self.object = object
+        #self.category = category
+        #self.file = file
+        #self.line = line
+        #self.message = message
+
+    ## test if our own log handler correctly mangles the message
+
+    #def testOwnLogHandlerLimited(self):
+        #log.setDebug("testlog:3")
+        #log.addLogHandler(self.handler)
+
+        #self.tester.log("visible")
+        #assert self.message == 'override visible'
+
+    #def testLogHandlerAssertion(self):
+        #self.assertRaises(TypeError, log.addLimitedLogHandler, None)
+
+
+#class TestGetExceptionMessage(unittest.TestCase):
+
+    #def func3(self):
+        #self.func2()
+
+    #def func2(self):
+        #self.func1()
+
+    #def func1(self):
+        #raise TypeError("I am in func1")
+
+    #def testLevel2(self):
+        #try:
+            #self.func2()
+            #self.fail()
+        #except TypeError, e:
+            #self.verifyException(e)
+
+    #def testLevel3(self):
+        #try:
+            #self.func3()
+            #self.fail()
+        #except TypeError, e:
+            #self.verifyException(e)
+
+    #def verifyException(self, e):
+        #message = log.getExceptionMessage(e)
+        #self.failUnless("func1()" in message)
+        #self.failUnless("test_log.py" in message)
+        #self.failUnless("TypeError" in message)
+
+
+#class TestLogSettings(unittest.TestCase):
+
+    #def testSet(self):
+        #old = log.getLogSettings()
+        #log.setDebug('*:5')
+        #self.assertNotEquals(old, log.getLogSettings())
+
+        #log.setLogSettings(old)
+        #self.assertEquals(old, log.getLogSettings())
+
+
+#class TestWriteMark(unittest.TestCase):
+
+    #def handler(self, level, object, category, file, line, message):
+        #self.level = level
+        #self.object = object
+        #self.category = category
+        #self.file = file
+        #self.line = line
+        #self.message = message
+
+    #def testWriteMarkInDebug(self):
+        #loggable = log.Loggable()
+        #log.setDebug("4")
+        #log.addLogHandler(self.handler)
+        #marker = 'test'
+        #loggable.writeMarker(marker, log.DEBUG)
+        #self.assertEquals(self.message, marker)
+
+    #def testWriteMarkInWarn(self):
+        #loggable = log.Loggable()
+        #log.setDebug("2")
+        #log.addLogHandler(self.handler)
+        #marker = 'test'
+        #loggable.writeMarker(marker, log.WARN)
+        #self.assertEquals(self.message, marker)
+
+    #def testWriteMarkInInfo(self):
+        #loggable = log.Loggable()
+        #log.setDebug("3")
+        #log.addLogHandler(self.handler)
+        #marker = 'test'
+        #loggable.writeMarker(marker, log.INFO)
+        #self.assertEquals(self.message, marker)
+
+    #def testWriteMarkInLog(self):
+        #loggable = log.Loggable()
+        #log.setDebug("5")
+        #log.addLogHandler(self.handler)
+        #marker = 'test'
+        #loggable.writeMarker(marker, log.LOG)
+        #self.assertEquals(self.message, marker)
+
+    #def testWriteMarkInError(self):
+        #loggable = log.Loggable()
+        #log.setDebug("4")
+        #log.addLogHandler(self.handler)
+        #marker = 'test'
+        #self.assertRaises(SystemExit, loggable.writeMarker, marker, log.ERROR)
+        #self.assertEquals(self.message, marker)
+
+
+#class TestLogNames(unittest.TestCase):
+
+    #def testGetLevelNames(self):
+        #self.assertEquals(['ERROR', 'WARN', 'INFO', 'DEBUG', 'LOG'],
+                          #log.getLevelNames())
+
+    #def testGetLevelCode(self):
+        #self.assertEquals(1, log.getLevelInt('ERROR'))
+        #self.assertEquals(2, log.getLevelInt('WARN'))
+        #self.assertEquals(3, log.getLevelInt('INFO'))
+        #self.assertEquals(4, log.getLevelInt('DEBUG'))
+        #self.assertEquals(5, log.getLevelInt('LOG'))
+
+    #def testGetLevelName(self):
+        #self.assertEquals('ERROR', log.getLevelName(1))
+        #self.assertEquals('WARN', log.getLevelName(2))
+        #self.assertEquals('INFO', log.getLevelName(3))
+        #self.assertEquals('DEBUG', log.getLevelName(4))
+        #self.assertEquals('LOG', log.getLevelName(5))
+
+#if __name__ == '__main__':
+    #unittest.main()



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]