def new_entry(self, raw, date=None, sort=True): """Constructs a new entry from some raw text input. If a date is given, it will parse and use this, otherwise scan for a date in the input first.""" raw = raw.replace("\\n ", "\n").replace("\\n", "\n") # Split raw text into title and body sep = re.search(r"\n|[?!.]+ +\n?", raw) first_line = raw[:sep.end()].strip() if sep else raw starred = False if not date: colon_pos = first_line.find(": ") if colon_pos > 0: date = time.parse( raw[:colon_pos], default_hour=self.config["default_hour"], default_minute=self.config["default_minute"], ) if date: # Parsed successfully, strip that from the raw text starred = raw[:colon_pos].strip().endswith("*") raw = raw[colon_pos + 1:].strip() starred = (starred or first_line.startswith("*") or first_line.endswith("*") or raw.startswith("*")) if not date: # Still nothing? Meh, just live in the moment. date = time.parse("now") entry = Entry.Entry(self, date, raw, starred=starred) entry.modified = True self.entries.append(entry) if sort: self.sort() return entry
def filter( self, tags=[], start_date=None, end_date=None, starred=False, strict=False, short=False, contains=None, exclude=[], ): """Removes all entries from the journal that don't match the filter. tags is a list of tags, each being a string that starts with one of the tag symbols defined in the config, e.g. ["@John", "#WorldDomination"]. start_date and end_date define a timespan by which to filter. starred limits journal to starred entries If strict is True, all tags must be present in an entry. If false, the exclude is a list of the tags which should not appear in the results. entry is kept if any tag is present, unless they appear in exclude.""" self.search_tags = {tag.lower() for tag in tags} excluded_tags = {tag.lower() for tag in exclude} end_date = time.parse(end_date, inclusive=True) start_date = time.parse(start_date) # If strict mode is on, all tags have to be present in entry tagged = self.search_tags.issubset if strict else self.search_tags.intersection excluded = lambda tags: len([tag for tag in tags if tag in excluded_tags]) > 0 if contains: contains_lower = contains.casefold() result = [ entry for entry in self.entries if (not tags or tagged(entry.tags)) and (not starred or entry.starred) and (not start_date or entry.date >= start_date) and (not end_date or entry.date <= end_date) and (not exclude or not excluded(entry.tags)) and ( not contains or ( contains_lower in entry.title.casefold() or contains_lower in entry.body.casefold() ) ) ] self.entries = result
def test_default_minute_is_added(): assert (time.parse( "2020-06-20", inclusive=False, default_hour=0, default_minute=30, bracketed=False, ) == datetime.datetime(2020, 6, 20, 0, 30))
def _parse(self, journal_txt): """Parses a journal that's stored in a string and returns a list of entries""" # Return empty array if the journal is blank if not journal_txt: return [] # Initialise our current entry entries = [] date_blob_re = re.compile("(?:^|\n)\\[([^\\]]+)\\] ") last_entry_pos = 0 for match in date_blob_re.finditer(journal_txt): date_blob = match.groups()[0] try: new_date = datetime.strptime(date_blob, self.config["timeformat"]) except ValueError: # Passing in a date that had brackets around it new_date = time.parse(date_blob, bracketed=True) if new_date: if entries: entries[-1].text = journal_txt[last_entry_pos:match.start( )] last_entry_pos = match.end() entries.append(Entry.Entry(self, date=new_date)) # If no entries were found, treat all the existing text as an entry made now if not entries: entries.append(Entry.Entry(self, date=time.parse("now"))) # Fill in the text of the last entry entries[-1].text = journal_txt[last_entry_pos:] for entry in entries: entry._parse_text() return entries
def test_default_hour_is_added(): assert time.parse("2020-06-20", inclusive=False, default_hour=9, default_minute=0, bracketed=False) == datetime.datetime(2020, 6, 20, 9)