def test_get(self): # 存在しないパスをgetする self.assertFalse(os.path.exists(self.root)) self.assertIsNone(Manager.get(self.root, self.profile)) # タスクトリでないディレクトリをgetする self.assertIsNone(Manager.get('/Users/taku', self.profile)) # 空タスクトリをputしてからgetする t0 = Tasktory('', 1) Manager.put(self.root, t0, self.profile) self.assertTrue(os.path.exists(self.root)) self.assertTrue(os.path.isfile(os.path.join(self.root, self.profile))) t0_ = Manager.get(self.root, self.profile, False) self.assertIsNot(t0, t0_) self.check(t0_, '', 1, None, OPEN, None, '') t0_ = Manager.get(self.root, self.profile) self.check(t0_, 'work', 1, None, OPEN, None, '') # 名前付きタスクトリ t1 = Tasktory('#123.あいうえお', 123, CLOSE) t1.add_time(10,20) t1.comments = 'コメント' Manager.put(self.root, t1, self.profile) self.assertTrue(os.path.exists(os.path.join(self.root, t1.name))) self.assertTrue(os.path.isfile(os.path.join(self.root, t1.name, self.profile))) t1_ = Manager.get(os.path.join(self.root, t1.name), self.profile, False) self.check(t1_, '#123.あいうえお', 123, None, CLOSE, None, 'コメント') return
def leaf(self, attrs): task = Tasktory( self.root + attrs['PATH'], attrs['DEADLINE'], attrs['STATUS'], attrs['COMMENT']) for start, sec in attrs['TIMETABLE']: task.punch(start, sec) return task
def commit_task(self, date, attrs): # コミットしたタスクの数 commit_num = 0 # タスクを作成する if not attrs: return 0 leafs, inners = zip(*(self.tb.build(attr) for attr in attrs)) # leafs, inners = zip(*map(self.tb.build, attrs)) # 当日の午前零時から翌日の午前零時 a = datetime.datetime(date.year, date.month, date.day, 0, 0, 0) b = a + datetime.timedelta(1) a = int(a.timestamp()) b = int(b.timestamp()) def at_date(t): return a <= t[0] and t[0] < b # 内部ノードは存在しないもののみコミットする for task in sum(inners, []): if not Tasktory.istask(task.path): task.sync() commit_num += 1 self.info("CREATE", str(task)) # 葉ノードは変更があるもののみコミットする for task in leafs: # 存在しなければコミットする if not Tasktory.istask(task.path): task.sync() commit_num += 1 self.info("CREATE", str(task)) continue # 既存のタスクを復元する org = Tasktory.restore(task.path) # 変更が無ければ無視する if all([ org.deadline == task.deadline, org.status == task.status, set(filter(at_date, org.timetable)) == set(task.timetable), org.comment == task.comment, ]): continue # 当日分の作業時間を削除する org.timetable = [t for t in org.timetable if not at_date(t)] # マージしてコミットする org.merge(task).sync() commit_num += 1 self.info("UPDATE", str(task)) return commit_num
def timetable(): # クエリが無ければ、クエリを付けてリダイレクト if not request.query.date: redirect("{}?date={}".format(URL_TIMETABLE, datetime.date.today().toordinal())) # クエリパラメータから日付取得 date = datetime.date.fromordinal(int(request.query.date)) # コンフィグ読み込み config = configparser.ConfigParser() config.read(MAIN_CONF_FILE) # タスク復元 tasks = Tasktory.restore(config["Main"]["ROOT"]) # HTMLテンプレートを準備する env = Environment(loader=FileSystemLoader(HTML_DIR)) template = env.get_template("timetable.html") # テンプレートに渡す変数を用意する a = datetime.datetime(date.year, date.month, date.day, 0, 0, 0) b = a + datetime.timedelta(1) a = int(a.timestamp()) b = int(b.timestamp()) return template.render(path=URL_TIMETABLE, today=date, tasks=[t for t in tasks if t.at(date)], root=config["Main"]["ROOT"], a=a, b=b)
def commit(self): # ジャーナルを解析する date, attrs, memos, _ = self.read() # ファイルシステムにコミットする commit_task_num = self.commit_task(date, attrs) # メモのタスクが存在するか確認する for memo in memos: if not Tasktory.istask(memo["PATH"]): raise JournalManagerNoExistTaskOfMemoError(memo["PATH"]) # メモをコミットする now = datetime.datetime.now() for memo in memos: if Tasktory.restore(memo["PATH"]).memo.put(now, memo["TEXT"]): self.info("MEMO", memo["PATH"]) return commit_task_num, len(memos)
def test_get_tree(self): # 存在しないパス self.assertFalse(os.path.exists(self.root)) self.assertIsNone(Manager.get_tree(self.root, self.profile)) # タスクトリでないパス self.assertIsNone(Manager.get_tree('/Users/taku', self.profile)) # タスクトリ t0 = Tasktory('', 1) t1 = Tasktory('00.あ', 2) t2 = Tasktory('01.か', 3) t21 = Tasktory('02.き', 4) t22 = Tasktory('02.きき', 5) t0.append(t1) t0.append(t2) t2.append(t21) t2.append(t22) for node in t0: Manager.put(self.root, node, self.profile) t0_ = Manager.get_tree(self.root, self.profile) for n, n_ in zip(t0, t0_): self.check(n_, n.name, n.deadline, n_.parent, n.status, n.category, n.comments) return
def analize(self, root): # ルートパスからタスクトリ名一覧を取得する paths = [(p, n) for p, names, _ in walk(root) for n in names] tasknames = [n for p, n in paths if Tasktory.istask(join(p, n))] # 番号付き名前分離 names = [self.r_name.match(n).group(1) for n in tasknames] # バージョンタグ ver_tags = list(set([n for n in names if self.r_ver.match(n)])) # リビジョンタグ rev_tags = list(set([n for n in names if self.r_rev.match(n)])) # 番号タグ num_tags = list(set([n for n in names if self.r_num.match(n)])) # 重複タグ dup_tags = list(set([n for n in names if names.count(n) > 1])) return ver_tags + rev_tags + num_tags + dup_tags + self.reg_tags
def sync(): # コンフィグ読み込み config = configparser.ConfigParser() config.read(MAIN_CONF_FILE) root_path = config["Main"]["ROOT"] # テスト day0 = datetime.datetime.fromordinal(request.json["date"]) day1 = day0 + datetime.timedelta(1) ts0 = int(day0.timestamp()) ts1 = int(day1.timestamp()) for data in request.json["datas"]: task = Tasktory.restore(root_path + data["path"]) print(task.path) for s, t in filter(lambda v: ts0 <= v[0] < ts1, task.timetable): print(s, t) print() for term in data["terms"]: print(ts0 + term["s"] * 60, term["t"] * 60) print() return
def checkout(self, date): # 既存のジャーナルからメモを読み出す _, _, _, plain_memo = self.read() # ファイルシステムからタスクを復元する root_task = Tasktory.restore(self.root) if root_task is None: tasks = [] else: self.jt.date = date tasks = [t for t in root_task if self.jt.test(t)] # tasksのuniqを取る tasks = unique(tasks, lambda t: t.path) # ジャーナルディレクトリを作成する os.makedirs(os.path.dirname(self.journal), exist_ok=True) # ジャーナルを書き出す with open(self.journal, 'w', encoding='utf-8') as f: f.write(self.jb.build(date, tasks, plain_memo))
def timetable(): # クエリが無ければ、クエリを付けてリダイレクト if not request.query.date: redirect("{}?date={}".format( URL_TIMETABLE, datetime.date.today().toordinal() )) # クエリパラメータから日付取得 date = datetime.date.fromordinal(int(request.query.date)) # コンフィグ読み込み config = configparser.ConfigParser() config.read(MAIN_CONF_FILE) # タスク復元 tasks = Tasktory.restore(config["Main"]["ROOT"]) # HTMLテンプレートを準備する env = Environment(loader=FileSystemLoader(HTML_DIR)) template = env.get_template("timetable.html") # テンプレートに渡す変数を用意する a = datetime.datetime(date.year, date.month, date.day, 0, 0, 0) b = a + datetime.timedelta(1) a = int(a.timestamp()) b = int(b.timestamp()) return template.render( path=URL_TIMETABLE, today=date, tasks=[t for t in tasks if t.at(date)], root=config["Main"]["ROOT"], a=a, b=b )
def test_journal(self): j_tmpl ="""%YEAR/%MONTH/%DAY $ Todo %OPENTASKS $ Wait %WAITTASKS $ Done %CLOSETASKS $ Const %CONSTTASKS $ MEMO %MEMO """ date = datetime.date(2014, 4, 1) j_tmpl = RWTemplate(j_tmpl) tl_tmpl = RWTemplate('%PATH @%DEADLINE [%TIMES]') tm_tmpl = RWTemplate('%SHOUR:%SMIN-%EHOUR:%EMIN') tm_delim = ',' stamp = datetime.date(2014, 4, 1).toordinal() tstamp = datetime.datetime(2014, 4, 1, 0, 0, 0).timestamp() # None self.assertRaises(TypeError, Journal.journal, date, None, '', j_tmpl, tl_tmpl, tm_tmpl, tm_delim, 365) # 出力タスクトリなし root = Tasktory('', stamp + 366) j = Journal.journal(date, root, '', j_tmpl, tl_tmpl, tm_tmpl, tm_delim, 365) journal = """2014/04/01 $ Todo $ Wait $ Done $ Const $ MEMO """ self.assertEqual(j, journal) # タスクトリ root = Tasktory('', stamp + 366); root.comments += 'Root task' proj = Tasktory('Project', stamp + 30); proj.comments += 'Project task' root.append(proj) task1 = Tasktory('Task1', stamp + 3).add_time(tstamp, 3600) task1.comments = 'task1\nほげほげ' proj.append(task1) task2 = Tasktory('Task2', stamp + 3).add_time( tstamp+3600, 3600).add_time(tstamp+10800, 3600) proj.append(task2) task3 = Tasktory('Task3', stamp + 0, CLOSE).add_time(tstamp+7200, 3600) proj.append(task3) ctask = Tasktory('ConstTask', stamp + 365, CONST).add_time(tstamp+14400, 3600) proj.append(ctask) j = Journal.journal(date, root, 'This is memo\nhogehoge', j_tmpl, tl_tmpl, tm_tmpl, tm_delim, 365) journal = """2014/04/01 $ Todo /Project @30 [] # Project task /Project/Task1 @3 [0:00-1:00] # task1 # ほげほげ /Project/Task2 @3 [1:00-2:00,3:00-4:00] $ Wait $ Done $ Const /Project/ConstTask @365 [4:00-5:00] $ MEMO This is memo hogehoge """ self.assertEqual(j, journal) return
import datetime import configparser from jinja2 import Environment, FileSystemLoader from lib.core.Tasktory import Tasktory from lib.common.common import HTML_DIR from lib.common.common import MAIN_CONF_FILE if __name__ == '__main__': config = configparser.ConfigParser() config.read(MAIN_CONF_FILE) # タスク作成 tasks = Tasktory.restore(config["Main"]["ROOT"]) # HTML作成準備 env = Environment(loader=FileSystemLoader(HTML_DIR)) template = env.get_template("timetable.html") path = "/Users/taku/tmp/html/test.html" today = datetime.date.today() a = datetime.datetime(today.year, today.month, today.day, 0, 0, 0) b = a + datetime.timedelta(1) a = int(a.timestamp()) b = int(b.timestamp()) # HTML書き出し with open(path, "w", encoding="utf-8") as f: f.write(template.render(
def leaf(self, attrs): task = Tasktory(self.root + attrs['PATH'], attrs['DEADLINE'], attrs['STATUS'], attrs['COMMENT']) for start, sec in attrs['TIMETABLE']: task.punch(start, sec) return task
def inner(self, path, attrs): return Tasktory(self.root + path, attrs['DEADLINE'], Tasktory.OPEN, '')
def test_taskline(self): date = datetime.date(2014, 4, 1) datestamp = date.toordinal() timestamp = int(datetime.datetime(2014, 4, 1).timestamp()) tl_tmpl = RWTemplate('%PATH @%DEADLINE [%TIMES]') tm_tmpl = RWTemplate('%SHOUR:%SMIN-%EHOUR:%EMIN') tm_delim = ',' # 空タスクトリ t = Tasktory('', datestamp + 3650) self.assertEqual(Journal.taskline(date, t, tl_tmpl, tm_tmpl, tm_delim), '/ @3650 []') # 名前付き t1 = Tasktory('#123.あいうえお', datestamp + 30) self.assertEqual(Journal.taskline(date, t1, tl_tmpl, tm_tmpl, tm_delim), '/#123.あいうえお @30 []') t.append(t1) t1.add_time(timestamp, 3600) self.assertEqual(Journal.taskline(date, t1, tl_tmpl, tm_tmpl, tm_delim), '/#123.あいうえお @30 [0:00-1:00]') t11 = Tasktory('かきくけこ', datestamp + 15) self.assertEqual(Journal.taskline(date, t11, tl_tmpl, tm_tmpl, tm_delim), '/かきくけこ @15 []') t1.append(t11) t11.add_time(timestamp+3600, 1800) t11.add_time(timestamp+36000, 7200) self.assertEqual(Journal.taskline(date, t11, tl_tmpl, tm_tmpl, tm_delim), '/#123.あいうえお/かきくけこ @15 [1:00-1:30,10:00-12:00]') return
#!/usr/bin/env python3 # -*- coding: utf-8 -*- from configparser import ConfigParser from lib.core.Tasktory import Tasktory from lib.ui.report.Report import Report from lib.common.common import MAIN_CONF_FILE if __name__ == '__main__': config = ConfigParser() config.read(MAIN_CONF_FILE) root = Tasktory.restore(config["Main"]["ROOT"]) report = Report("weekly.tmpl") print(report.test(root))
from lib.ui.journal.tester.JournalTester import JournalTester from lib.common.common import MAIN_CONF_FILE if __name__ == '__main__': # read config config = configparser.ConfigParser() config.read(MAIN_CONF_FILE) # today date = datetime.date.today() - datetime.timedelta(2) # TaskLineBuilder builder = TaskLineBuilder(date, config) root_dir = config['Main']['ROOT'] root_task = Tasktory.restore(root_dir) root_task = [] if root_task is None else root_task # Filter test tester = JournalTester() tester.date = date # show all for task in root_task: print(builder.build(task), task.status) # show separator print("\n==========\n") # show for task in [t for t in root_task if tester.test(t)]: