Source code for moments.log

# ----------------------------------------------------------------------------
# moments
# Copyright (c) 2009-2010, Charles Brandt
# 
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
# 
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
# ----------------------------------------------------------------------------
import StringIO, re, os
import codecs

from moment import Moment

import timestamp
from tag import Tags

[docs]class Log(StringIO.StringIO): """ Log is an in memory buffer (StringIO) that holds a text format for a list of entries / moments. The goal for this format is to be easy to create and update in a text editor For each entry: will create a Moment (with or without timestamp) """ def __init__(self, filename=None): StringIO.StringIO.__init__(self) if filename: self.name = filename else: self.name = '' self.seek(0) # until we have entries (from to_entries or from_entries), assume we don't: self.has_entries = False
[docs] def from_file(self, filename=None): """ if the file exists, read in its contents otherwise set our filename and stay empty """ if not self.name: #we don't have a file associated with the EntryList: if not filename: print "UNKNOWN FILE!" exit else: self.name = filename elif filename and filename != self.name: #ambiguous which file to use print "different file than what log was initialized with" exit else: #we have an original filename and none passed in #or the original filename equals the one passed in #should be good to go pass if os.path.exists(self.name): #f = open(self.name, "U") #2009.04.02 20:44:31 #very strange behavior when opening up utf-8 files #characters get reincoded #this is especially prominent when using check_feed.py #was using latin_1... going back to utf-8 #f = codecs.open(self.name, encoding='latin_1') #codecs.ignore_errors(UnicodeDecodeError) f = codecs.open(self.name, encoding='utf-8', errors='ignore') self.write(f.read()) f.close self.seek(0) else: print "NO FILE ASSOCIATED WITH LOG: %s" % self.name
[docs] def to_file(self, filename=None): """ save our content to the file """ name = None if filename is not None: name = filename elif self.name: name = self.name if name: #f = open(self.name, 'w') f = codecs.open(name, 'w', encoding='utf-8') self.seek(0) f.write(self.read()) f.close() else: print "No log_name for this log"
[docs] def from_entries(self, entries, omits=[], include_path=False): """ take a collection of entries and put together a log buffer omit tags allow us to omit a certain tag on export/extract if omit tag is given, do not print the tag for any of the entries. """ #need to make an explicit decision on where to start writing #with out that it is completely dependent on where the last #seek operation left the pointer in the file #could be the beginning, could be the end #need to be explicit about how from_entries operates though #think the right idea is that from_entries should over write any #other data in the log. that means it should be extracted first #if it should be kept self.seek(0) for entry in entries: entry.tags.omit(omits) self.write(entry.render(include_path=include_path)) if len(entries): self.has_entries = True
[docs] def to_entries(self, add_tags=[], add_time=False, moments_only=False): """ convert log to a list of entry objects (essentially what a log is) if moments_only is true, only Moments will be created if add_time is false, and moments_only is true, upon reaching an Entry only (*... ) (no timestamp) that information will be added to the previous Moment (this is useful when parsing data that was not originally intended to be used as part of a moment... it may contain lines that start with '*') """ entries = [] entry_regex = "\*" entry_search = re.compile(entry_regex) cur_entry = Moment() cur_entry.path = self.name new_entry = None try: self.seek(0) line = self.readline() line = unicode(line) except: print "Problem reading file" return entries #first line of a log should have an entry... this is our check if entry_search.match(line): self.has_entries = True while line: #we might have found a new entry... #see what kind, if any: (ts, line_tags) = timestamp.parse_line_for_time(line) if ts: new_entry = Moment() new_entry.created = timestamp.Timestamp(ts) elif entry_search.match(line): if not moments_only: new_entry = Moment() elif add_time and moments_only: #ok to make a default time for the entry new_entry = Moment() print "no timestamp found in this entry" else: #must be moments only, #but we don't want to add a timestamp #just include the data with the previous moment new_entry = None if new_entry: #finish up last entry... #only need to add if it had information if cur_entry.data or cur_entry.tags: entries.append(cur_entry) new_entry.path = self.name current_tags = line_tags.strip().split() if add_tags: temp_tags = add_tags[:] for t in current_tags: if t not in temp_tags: temp_tags.append(t) current_tags = temp_tags new_entry.tags.extend(current_tags) cur_entry = new_entry new_entry = None else: # only want to add the entry itself cur_entry.data += line line = unicode(self.readline()) #need to get the last entry from the file, if there is one. if cur_entry.data: entries.append(cur_entry) #if not, don't scan else: print "File does not start with an entry: %s" % self.name return entries