def setUp(self): self.settings = Settings() self.real_isdir = os.path.isdir self.tempdir = None self.old_home = os.environ.get('HOME') self.old_gtimelog_home = os.environ.get('GTIMELOG_HOME') self.old_xdg_config_home = os.environ.get('XDG_CONFIG_HOME') self.old_xdg_data_home = os.environ.get('XDG_DATA_HOME') os.environ['HOME'] = os.path.normpath('/tmp/home') os.environ.pop('GTIMELOG_HOME', None) os.environ.pop('XDG_CONFIG_HOME', None) os.environ.pop('XDG_DATA_HOME', None)
def __init__(self, config): self.settings = Settings() self.timelog = TimeLog(self.settings.get_timelog_file(), self.settings.virtual_midnight) self.aliases = config.get('aliases', {}) self.line_format = config.get('line_format', '') if self.line_format == 'categorized': self.line_format_str = "category: task description | comment" self.delimiter = " " else: self.line_format_str = "task: description | comment" self.delimiter = ":"
def do_handle_local_options(self, options): if options.contains('version'): print(gtimelog.__version__) return 0 if options.contains('sample-config'): settings = Settings() settings.save("gtimelogrc.sample") print("Sample configuration file written to gtimelogrc.sample") print("Edit it and save as %s" % settings.get_config_file()) return 0 self.debug = options.contains('debug') self.start_minimized = options.contains('tray') if options.contains('quit'): print('gtimelog: Telling the already-running instance to quit') return -1 # send the args to the remote instance for processing
def parse_two(): # slower than parse_one filename = Settings().get_timelog_file() for line in open(filename): try: time, entry = line.split(': ', 1) time = parse_datetime(time) except ValueError: continue
def parse_three(): # fastest filename = Settings().get_timelog_file() for line in open(filename): time, sep, entry = line.partition(': ') if not sep: continue try: time = parse_datetime(time) except ValueError: continue
def parse_one(): filename = Settings().get_timelog_file() for line in open(filename): if ': ' not in line: continue time, entry = line.split(': ', 1) try: time = parse_datetime(time) except ValueError: continue
def parse_and_strip(): filename = Settings().get_timelog_file() for line in open(filename): time, sep, entry = line.partition(': ') if not sep: continue try: time = parse_datetime(time) except ValueError: continue entry = entry.strip()
def parse_and_collect(): items = [] filename = Settings().get_timelog_file() for line in open(filename): time, sep, entry = line.partition(': ') if not sep: continue try: time = parse_datetime(time) except ValueError: continue entry = entry.strip() items.append((time, entry)) return items
class GtimelogParser(object): def __init__(self, config): self.settings = Settings() self.timelog = TimeLog(self.settings.get_timelog_file(), self.settings.virtual_midnight) self.aliases = config.get('aliases', {}) def skip_entry(self, entry): if '**' in entry: return True if entry.strip() in ('arrive', 'arrived', 'start'): return True return False def get_entries(self, date_window): window = self.timelog.window_for(date_window.start, date_window.stop) worklogs = [] attendances = [] for start, stop, duration, tags, entry in window.all_entries(): if self.skip_entry(entry): continue if attendances and attendances[-1][1] == start: attendances[-1] = (attendances[-1][0], stop) else: attendances += [(start, stop)] try: issue, description = [ x.strip() for x in entry.split(':', 1) if x.strip() ] except ValueError: print( 'Entry must be in the format `task: description`. ' 'Got ', entry) continue # no matter what we find as `issue`: # if we have an alias override it takes precedence if issue in self.aliases: issue = self.aliases[issue] worklogs.append( MultiLog(None, issue, int(duration.total_seconds()), start.date(), description)) # Dangling attendance for today if attendances and attendances[-1][1].date() == date.today(): attendances[-1] = (attendances[-1][0], None) return attendances, worklogs
def parse_and_sort_unicode(): items = [] filename = Settings().get_timelog_file() for line in open(filename, 'rb').read().decode('UTF-8').splitlines(): time, sep, entry = line.partition(': ') if not sep: continue try: time = parse_datetime(time) except ValueError: continue entry = entry.strip() items.append((time, entry)) items.sort(key=itemgetter(0)) return items
def parse_and_sort_incorrectly(): items = [] filename = Settings().get_timelog_file() for line in open(filename): time, sep, entry = line.partition(': ') if not sep: continue try: time = parse_datetime(time) except ValueError: continue entry = entry.strip() items.append((time, entry)) items.sort() # XXX: can reorder lines return items
def parse_and_sort_unicode_piecemeal(): items = [] filename = Settings().get_timelog_file() for line in open(filename, 'rb'): time, sep, entry = line.partition(b': ') if not sep: continue try: time = parse_datetime(time.decode('ASCII')) except (ValueError, UnicodeError): continue entry = entry.strip().decode('UTF-8') items.append((time, entry)) items.sort(key=itemgetter(0)) return items
class TestSettings(unittest.TestCase): def setUp(self): from gtimelog.settings import Settings self.settings = Settings() self.real_isdir = os.path.isdir self.tempdir = None self.old_home = os.environ.get('HOME') self.old_gtimelog_home = os.environ.get('GTIMELOG_HOME') self.old_xdg_config_home = os.environ.get('XDG_CONFIG_HOME') self.old_xdg_data_home = os.environ.get('XDG_DATA_HOME') os.environ['HOME'] = os.path.normpath('/tmp/home') os.environ.pop('GTIMELOG_HOME', None) os.environ.pop('XDG_CONFIG_HOME', None) os.environ.pop('XDG_DATA_HOME', None) def tearDown(self): os.path.isdir = self.real_isdir if self.tempdir: shutil.rmtree(self.tempdir) self.restore_env('HOME', self.old_home) self.restore_env('GTIMELOG_HOME', self.old_gtimelog_home) self.restore_env('XDG_CONFIG_HOME', self.old_xdg_config_home) self.restore_env('XDG_DATA_HOME', self.old_xdg_data_home) def restore_env(self, envvar, value): if value is not None: os.environ[envvar] = value else: os.environ.pop(envvar, None) def mkdtemp(self): if self.tempdir is None: self.tempdir = tempfile.mkdtemp(prefix='gtimelog-test-') return self.tempdir def test_get_config_dir_1(self): # Case 1: GTIMELOG_HOME is present in the environment os.environ['GTIMELOG_HOME'] = os.path.normpath('~/.gt') self.assertEqual(self.settings.get_config_dir(), os.path.normpath('/tmp/home/.gt')) def test_get_config_dir_2(self): # Case 2: ~/.gtimelog exists os.path.isdir = lambda dir: True self.assertEqual(self.settings.get_config_dir(), os.path.normpath('/tmp/home/.gtimelog')) def test_get_config_dir_3(self): # Case 3: ~/.gtimelog does not exist, so we use XDG os.path.isdir = lambda dir: False self.assertEqual(self.settings.get_config_dir(), os.path.normpath('/tmp/home/.config/gtimelog')) def test_get_config_dir_4(self): # Case 4: XDG_CONFIG_HOME is present in the environment os.environ['XDG_CONFIG_HOME'] = os.path.normpath('~/.conf') self.assertEqual(self.settings.get_config_dir(), os.path.normpath('/tmp/home/.conf/gtimelog')) def test_get_data_dir_1(self): # Case 1: GTIMELOG_HOME is present in the environment os.environ['GTIMELOG_HOME'] = os.path.normpath('~/.gt') self.assertEqual(self.settings.get_data_dir(), os.path.normpath('/tmp/home/.gt')) def test_get_data_dir_2(self): # Case 2: ~/.gtimelog exists os.path.isdir = lambda dir: True self.assertEqual(self.settings.get_data_dir(), os.path.normpath('/tmp/home/.gtimelog')) def test_get_data_dir_3(self): # Case 3: ~/.gtimelog does not exist, so we use XDG os.path.isdir = lambda dir: False self.assertEqual(self.settings.get_data_dir(), os.path.normpath('/tmp/home/.local/share/gtimelog')) def test_get_data_dir_4(self): # Case 4: XDG_CONFIG_HOME is present in the environment os.environ['XDG_DATA_HOME'] = os.path.normpath('~/.data') self.assertEqual(self.settings.get_data_dir(), os.path.normpath('/tmp/home/.data/gtimelog')) def test_get_config_file(self): self.settings.get_config_dir = lambda: os.path.normpath('~/.config/gtimelog') self.assertEqual(self.settings.get_config_file(), os.path.normpath('~/.config/gtimelog/gtimelogrc')) def test_get_timelog_file(self): self.settings.get_data_dir = lambda: os.path.normpath('~/.local/share/gtimelog') self.assertEqual(self.settings.get_timelog_file(), os.path.normpath('~/.local/share/gtimelog/timelog.txt')) def test_load(self): self.settings.load('/dev/null') def test_save(self): tempdir = self.mkdtemp() self.settings.save(os.path.join(tempdir, 'config'))
class TestSettings(unittest.TestCase): def setUp(self): self.settings = Settings() self.real_isdir = os.path.isdir self.tempdir = None self.old_home = os.environ.get('HOME') self.old_userprofile = os.environ.get('USERPROFILE') self.old_gtimelog_home = os.environ.get('GTIMELOG_HOME') self.old_xdg_config_home = os.environ.get('XDG_CONFIG_HOME') self.old_xdg_data_home = os.environ.get('XDG_DATA_HOME') os.environ['HOME'] = os.path.normpath('/tmp/home') os.environ['USERPROFILE'] = os.path.normpath('/tmp/home') os.environ.pop('GTIMELOG_HOME', None) os.environ.pop('XDG_CONFIG_HOME', None) os.environ.pop('XDG_DATA_HOME', None) def tearDown(self): os.path.isdir = self.real_isdir if self.tempdir: shutil.rmtree(self.tempdir) self.restore_env('HOME', self.old_home) self.restore_env('USERPROFILE', self.old_userprofile) self.restore_env('GTIMELOG_HOME', self.old_gtimelog_home) self.restore_env('XDG_CONFIG_HOME', self.old_xdg_config_home) self.restore_env('XDG_DATA_HOME', self.old_xdg_data_home) def restore_env(self, envvar, value): if value is not None: os.environ[envvar] = value else: os.environ.pop(envvar, None) def mkdtemp(self): if self.tempdir is None: self.tempdir = tempfile.mkdtemp(prefix='gtimelog-test-') return self.tempdir def test_get_config_dir_1(self): # Case 1: GTIMELOG_HOME is present in the environment os.environ['GTIMELOG_HOME'] = os.path.normpath('~/.gt') self.assertEqual(self.settings.get_config_dir(), os.path.normpath('/tmp/home/.gt')) def test_get_config_dir_2(self): # Case 2: ~/.gtimelog exists os.path.isdir = lambda dir: True self.assertEqual(self.settings.get_config_dir(), os.path.normpath('/tmp/home/.gtimelog')) def test_get_config_dir_3(self): # Case 3: ~/.gtimelog does not exist, so we use XDG os.path.isdir = lambda dir: False self.assertEqual(self.settings.get_config_dir(), os.path.normpath('/tmp/home/.config/gtimelog')) def test_get_config_dir_4(self): # Case 4: XDG_CONFIG_HOME is present in the environment os.environ['XDG_CONFIG_HOME'] = os.path.normpath('~/.conf') self.assertEqual(self.settings.get_config_dir(), os.path.normpath('/tmp/home/.conf/gtimelog')) def test_get_data_dir_1(self): # Case 1: GTIMELOG_HOME is present in the environment os.environ['GTIMELOG_HOME'] = os.path.normpath('~/.gt') self.assertEqual(self.settings.get_data_dir(), os.path.normpath('/tmp/home/.gt')) def test_get_data_dir_2(self): # Case 2: ~/.gtimelog exists os.path.isdir = lambda dir: True self.assertEqual(self.settings.get_data_dir(), os.path.normpath('/tmp/home/.gtimelog')) def test_get_data_dir_3(self): # Case 3: ~/.gtimelog does not exist, so we use XDG os.path.isdir = lambda dir: False self.assertEqual(self.settings.get_data_dir(), os.path.normpath('/tmp/home/.local/share/gtimelog')) def test_get_data_dir_4(self): # Case 4: XDG_CONFIG_HOME is present in the environment os.environ['XDG_DATA_HOME'] = os.path.normpath('~/.data') self.assertEqual(self.settings.get_data_dir(), os.path.normpath('/tmp/home/.data/gtimelog')) def test_get_config_file(self): self.settings.get_config_dir = lambda: os.path.normpath( '~/.config/gtimelog') self.assertEqual(self.settings.get_config_file(), os.path.normpath('~/.config/gtimelog/gtimelogrc')) def test_get_timelog_file(self): self.settings.get_data_dir = lambda: os.path.normpath( '~/.local/share/gtimelog') self.assertEqual( self.settings.get_timelog_file(), os.path.normpath('~/.local/share/gtimelog/timelog.txt')) def test_get_report_log_file(self): self.settings.get_data_dir = lambda: os.path.normpath( '~/.local/share/gtimelog') self.assertEqual( self.settings.get_report_log_file(), os.path.normpath('~/.local/share/gtimelog/sentreports.log')) def test_get_task_list_file(self): self.settings.get_data_dir = lambda: os.path.normpath( '~/.local/share/gtimelog') self.assertEqual(self.settings.get_task_list_file(), os.path.normpath('~/.local/share/gtimelog/tasks.txt')) def test_get_task_list_cache_file(self): self.settings.get_data_dir = lambda: os.path.normpath( '~/.local/share/gtimelog') self.assertEqual( self.settings.get_task_list_cache_file(), os.path.normpath('~/.local/share/gtimelog/remote-tasks.txt')) def test_load(self): self.settings.load('/dev/null') self.assertEqual(self.settings.name, 'Anonymous') def test_load_default_file(self): self.settings.load() def test_save(self): tempdir = self.mkdtemp() self.settings.save(os.path.join(tempdir, 'config'))
def full(): return Settings().get_time_log().items
def do_activate(self): if self.main_window is not None: self.main_window.main_window.present() return debug = self.debug start_minimized = self.start_minimized log.addHandler(logging.StreamHandler(sys.stdout)) if debug: log.setLevel(logging.DEBUG) else: log.setLevel(logging.INFO) if debug: print('GTimeLog version: %s' % gtimelog.__version__) print('Python version: %s' % sys.version) print('Gtk+ version: %s.%s.%s' % (Gtk.MAJOR_VERSION, Gtk.MINOR_VERSION, Gtk.MICRO_VERSION)) print('Config directory: %s' % Settings().get_config_dir()) print('Data directory: %s' % Settings().get_data_dir()) settings = Settings() configdir = settings.get_config_dir() datadir = settings.get_data_dir() try: # Create configdir if it doesn't exist. os.makedirs(configdir) except OSError as error: if error.errno != errno.EEXIST: # XXX: not the most friendly way of error reporting for a GUI app raise try: # Create datadir if it doesn't exist. os.makedirs(datadir) except OSError as error: if error.errno != errno.EEXIST: raise settings_file = settings.get_config_file() if not os.path.exists(settings_file): if debug: print('Saving settings to %s' % settings_file) settings.save(settings_file) else: if debug: print('Loading settings from %s' % settings_file) settings.load(settings_file) if debug: print('Assuming date changes at %s' % settings.virtual_midnight) print('Loading time log from %s' % settings.get_timelog_file()) timelog = TimeLog(settings.get_timelog_file(), settings.virtual_midnight) if settings.task_list_url: if debug: print('Loading cached remote tasks from %s' % os.path.join(datadir, 'remote-tasks.txt')) tasks = RemoteTaskList(settings.task_list_url, os.path.join(datadir, 'remote-tasks.txt')) else: if debug: print('Loading tasks from %s' % os.path.join(datadir, 'tasks.txt')) tasks = TaskList(os.path.join(datadir, 'tasks.txt')) self.main_window = MainWindow(timelog, settings, tasks) self.add_window(self.main_window.main_window) start_in_tray = False if settings.show_tray_icon: if debug: print('Tray icon preference: %s' % ('AppIndicator' if settings.prefer_app_indicator else 'SimpleStatusIcon')) if settings.prefer_app_indicator and have_app_indicator: tray_icon = AppIndicator(self.main_window) else: tray_icon = SimpleStatusIcon(self.main_window) if tray_icon: if debug: print('Using: %s' % tray_icon.__class__.__name__) start_in_tray = (settings.start_in_tray if settings.start_in_tray else start_minimized) if debug: print('GTK+ completion: %s' % ('enabled' if settings.enable_gtk_completion else 'disabled')) if not start_in_tray: self.main_window.on_show_activate() else: if debug: print('Starting minimized') # This is needed to make ^C terminate gtimelog when we're using # gobject-introspection. signal.signal(signal.SIGINT, signal.SIG_DFL)
def __init__(self, config): self.settings = Settings() self.timelog = TimeLog(self.settings.get_timelog_file(), self.settings.virtual_midnight) self.aliases = config.get('aliases', {})
def do_activate(self): if self.main_window is not None: self.main_window.main_window.present() return log.addHandler(logging.StreamHandler(sys.stdout)) if self.opts.debug: log.setLevel(logging.DEBUG) else: log.setLevel(logging.INFO) if self.opts.sample_config: settings = Settings() settings.save("gtimelogrc.sample") print("Sample configuration file written to gtimelogrc.sample") print("Edit it and save as %s" % settings.get_config_file()) return if self.opts.debug: print('GTimeLog version: %s' % gtimelog.__version__) print('Gtk+ version: %s.%s.%s' % (Gtk.MAJOR_VERSION, Gtk.MINOR_VERSION, Gtk.MICRO_VERSION)) print('Config directory: %s' % Settings().get_config_dir()) print('Data directory: %s' % Settings().get_data_dir()) settings = Settings() configdir = settings.get_config_dir() datadir = settings.get_data_dir() try: # Create configdir if it doesn't exist. os.makedirs(configdir) except OSError as error: if error.errno != errno.EEXIST: # XXX: not the most friendly way of error reporting for a GUI app raise try: # Create datadir if it doesn't exist. os.makedirs(datadir) except OSError as error: if error.errno != errno.EEXIST: raise settings_file = settings.get_config_file() if not os.path.exists(settings_file): if self.opts.debug: print('Saving settings to %s' % settings_file) settings.save(settings_file) else: if self.opts.debug: print('Loading settings from %s' % settings_file) settings.load(settings_file) if self.opts.debug: print('Assuming date changes at %s' % settings.virtual_midnight) print('Loading time log from %s' % settings.get_timelog_file()) timelog = TimeLog(settings.get_timelog_file(), settings.virtual_midnight) if settings.task_list_url: if self.opts.debug: print('Loading cached remote tasks from %s' % os.path.join(datadir, 'remote-tasks.txt')) tasks = RemoteTaskList(settings.task_list_url, os.path.join(datadir, 'remote-tasks.txt')) else: if self.opts.debug: print('Loading tasks from %s' % os.path.join(datadir, 'tasks.txt')) tasks = TaskList(os.path.join(datadir, 'tasks.txt')) self.main_window = MainWindow(timelog, settings, tasks) self.add_window(self.main_window.main_window) start_in_tray = False if settings.show_tray_icon: if self.opts.debug: print('Tray icon preference: %s' % ('AppIndicator' if settings.prefer_app_indicator else 'SimpleStatusIcon')) if settings.prefer_app_indicator and have_app_indicator: tray_icon = AppIndicator(self.main_window) else: tray_icon = SimpleStatusIcon(self.main_window) if tray_icon: if self.opts.debug: print('Using: %s' % tray_icon.__class__.__name__) start_in_tray = (settings.start_in_tray if settings.start_in_tray else self.opts.tray) if not start_in_tray: self.main_window.on_show_activate() else: if self.opts.debug: print('Starting minimized') # This is needed to make ^C terminate gtimelog when we're using # gobject-introspection. signal.signal(signal.SIGINT, signal.SIG_DFL)
def full(): return TimeLog(Settings().get_timelog_file(), Settings().virtual_midnight).items
def split(): filename = Settings().get_timelog_file() for line in open(filename): if ': ' not in line: continue time, entry = line.split(': ', 1)
def just_read(): filename = Settings().get_timelog_file() open(filename).readlines()