def do_one(tasks_v2_session, t1: Task_v1) -> Optional[Task_v2]: try: if t1.parent: return None t2 = _do_one(tasks_v2_session, t1) except ValueError as e: print(e) print(json.dumps(t1.as_json(), indent=2)) raise try: tasks_v2_session.commit() except StatementError as e: tasks_v2_session.rollback() print(f"ERROR: Hit exception while parsing {t1}, skipping") print() print(e) print() print(json.dumps(t1.as_json(), indent=2)) raise except IntegrityError as e: session.rollback() print(f"ERROR: Hit exception while parsing {t1}, skipping") print() print(e) print() print(json.dumps(t1.as_json(), indent=2)) raise return t2
def test_orphan_properties(task_v1_session): task = Task(desc="orphan", first_scope="2021-ww24.5") task_v1_session.add(task) task_v1_session.commit() assert not task.parent assert not task.children json_dict = task.as_json(include_parents=True, include_children=True) assert 'parent_id' not in json_dict assert 'children' not in json_dict
def test_to_json_legacy(): TEST_DESC = "sample descr aheou;lq" TEST_CATEGORY = "test cat g'l.',.p" TEST_SCOPE = "2011-ww38.3" t = Task(desc=TEST_DESC, category=TEST_CATEGORY, first_scope=TEST_SCOPE) json_dict = t.to_json_dict() assert json_dict['desc'] == TEST_DESC assert json_dict['category'] == TEST_CATEGORY assert json_dict['first_scope'] == TEST_SCOPE assert 'created_at' not in json_dict
def from_csv(csv_entry) -> Task: t = Task(desc=csv_entry['desc']) if 'created_at' in csv_entry and csv_entry['created_at']: t.created_at = parser.parse(csv_entry['created_at']) for field in [ "first_scope", "category", "resolution", "parent_id", "time_estimate", "time_actual" ]: value = csv_entry.get(field) setattr(t, field, value if value else None) return t
def test_as_json(task_v1_session): TEST_DESC = "sample desc hchcoernn1 c" TEST_CATEGORY = "NqMxWNCBthIYp2e9aWrfeX8" TEST_SCOPE = "2021-ww24.5" t = Task(desc=TEST_DESC, category=TEST_CATEGORY, first_scope=TEST_SCOPE) task_v1_session.add(t) task_v1_session.flush() json_dict = t.as_json() assert json_dict['task_id'] assert json_dict['desc'] == TEST_DESC assert json_dict['first_scope'] == TEST_SCOPE assert 'parent_id' not in json_dict
def test_two_generation_properties(task_v1_session): parent_task = Task(desc="parent", first_scope="2021-ww24.5") task_v1_session.add(parent_task) task_v1_session.flush() child_task = Task(desc="child", first_scope="2021-ww24.6") child_task.parent_id = parent_task.task_id task_v1_session.add(child_task) task_v1_session.commit() assert not parent_task.parent assert parent_task.children == [child_task] assert child_task.parent == parent_task assert not child_task.children
def test_create_python(task_v1_session): task = Task(desc="test task for database", first_scope="2020-ww02.2") assert task.task_id is None task_v1_session.add(task) task_v1_session.flush() assert task.task_id is not None
def test_create_and_read_python(task_v1_session): task = Task(desc="injected test task", first_scope="2016-ww27.4") task_v1_session.add(task) task_v1_session.commit() query = Task.query.filter_by(task_id=task.task_id) task_out = query.one() assert task_out.task_id == task.task_id
def test_one_scope(task_v1_session): t = Task(desc="aoetuhnano", first_scope="2000-ww22.2") task_v1_session.add(t) task_v1_session.flush() tts = TaskTimeScope(task_id=t.task_id, time_scope_id=t.first_scope) task_v1_session.add(tts) task_v1_session.commit() assert len(t.scopes) == 1 assert t.scopes[0] == tts assert tts.task == t
def add_from_cli(session): # Read description for the task desc = input(f"Enter description: {Color.RED}") print(Color.END, end='', flush=True) # Read relevant scopes requested_scopes = sorted(_read_validated_scopes()) if not len(requested_scopes): requested_scopes = [TimeScope(datetime.now().strftime("%G-ww%V.%u"))] print(f" => defaulting to {requested_scopes}") if len(requested_scopes) > 1: print(f" => parsed as {requested_scopes}") # Create a Task, now that we have all required fields t = Task(desc=desc, first_scope=requested_scopes[0], created_at=datetime.now()) # And a category category = input(f"Enter category: {Color.RED}") if category is not None and category != "": t.category = category print(Color.END, end='', flush=True) # And a time_estimate time_estimate = input(f"Enter time_estimate: {Color.RED}") if time_estimate is not None and time_estimate != "": if not re.fullmatch(r"\d+\.\d", time_estimate): print(Color.END, end='') print( "time_estimate must be in format like `12.0` (\"\\d+\\.\\d\"), exiting" ) print() return t.time_estimate = time_estimate print(Color.END, end='', flush=True) # Try committing the Task try: session.add(t) session.commit() except StatementError as e: print() print("Hit exception when parsing:") print(json.dumps(t.to_json_dict(), indent=4)) session.rollback() return # Try creating the TaskTimeScopes for requested_scope in requested_scopes: session.add( TaskTimeScope(task_id=t.task_id, time_scope_id=requested_scope)) session.commit() print() print(f"Created task {t.task_id}") print(json.dumps(t.to_json_dict(), indent=4))
def _migrate_simple(session, t1: Task_v1) -> Task_v2: """ Migrate an orphan task Task_v1 only has a few fields that will turn into linkages: - for first_scope, we can add the `created_at` field, and possibly an `as_json()` dump - for the last scope, we set `resolution` + `time_elapsed` - every other linkage has no info, a `roll => wwXX.Y` resolution at most Note that first_scope isn't guaranteed to be the _earliest_ scope, it's intended to be the one where the task was created. """ t2 = Task_v2(desc=t1.desc, category=t1.category, time_estimate=t1.time_estimate) session.add(t2) session.flush() #print(f"DEBUG: {t2} <= _migrate_simple({t1})") created_at_linkage = None prior_linkage = None for scope_id in _get_scopes(t1): linkage = TaskLinkage(task_id=t2.task_id, time_scope_id=scope_id) linkage.created_at = datetime.now() session.add(linkage) # Touch up created_at_linkage if scope_id == _force_day_scope(t1.first_scope): created_at_linkage = linkage created_at_linkage.created_at = t1.created_at if t1.created_at else datetime.now( ) created_at_linkage.detailed_resolution = json.dumps(t1.as_json(), indent=4) # For "ordinary" linkages, append `roll => wwXX.Y` resolution if prior_linkage: min_scope_id = TimeScope(t1.first_scope).minimize(scope_id) prior_linkage.resolution = f"roll => {min_scope_id}" prior_linkage = linkage # For the final linkage, inherit any/all Task_v1 fields final_linkage = prior_linkage if prior_linkage else created_at_linkage final_linkage.resolution = t1.resolution final_linkage.time_elapsed = t1.time_actual return t2
def to_details_html(task: Task): # keep parameters to a minimum, to avoid hitting slow DB accesses as_json = task.as_json(False, False, False) if 'time_scopes' in as_json: # make linked TimeScopes clickable clickable_scopes = [] for s in as_json['time_scopes']: clickable_scopes.append(f'<a href=/report-tasks/{s}>{s}</a>') as_json['time_scopes'] = clickable_scopes as_text = json.dumps(as_json, indent=4, ensure_ascii=False) # make task_ids clickable as_text = re.sub(r'"task_id": (\d*),', r'<a href="/task/\1">"task_id": \1</a>,', as_text) # make first_scopes clickable as_text = re.sub(r'"first_scope": "(.*)",', r'<a href="/report-tasks/\1">"first_scope": "\1"</a>,', as_text) return as_text
def test_multi_scope(task_v1_session): t = Task(desc="hhhhhhhhhh", first_scope="2020-ww20.1") task_v1_session.add(t) task_v1_session.flush() task_v1_session.add( TaskTimeScope(task_id=t.task_id, time_scope_id=t.first_scope)) task_v1_session.add( TaskTimeScope(task_id=t.task_id, time_scope_id="2020-ww20.2")) task_v1_session.add( TaskTimeScope(task_id=t.task_id, time_scope_id="2020-ww20.3")) task_v1_session.add( TaskTimeScope(task_id=t.task_id, time_scope_id="2020-ww20.4")) task_v1_session.add( TaskTimeScope(task_id=t.task_id, time_scope_id="2020-ww20.5")) task_v1_session.commit() assert len(t.scopes) == 5 assert t.scopes[0]
def test_2g_sqlalchemy_relationships(task_v1_session): parent_task = Task(desc="parent", first_scope="2021-ww24.5") task_v1_session.add(parent_task) task_v1_session.flush() child_task = Task(desc="child", first_scope="2021-ww24.6") child_task.parent_id = parent_task.task_id task_v1_session.add(child_task) task_v1_session.commit() bystander = Task(desc="completely unrelated task", first_scope="2021-ww02.1") task_v1_session.add(bystander) bystander2 = Task(desc="totally unrelated task", first_scope="2021-ww03.1") task_v1_session.add(bystander2) task_v1_session.commit() assert not parent_task.parent assert parent_task.children == [child_task] assert child_task.parent == parent_task assert not child_task.children
def test_task_constructor(): task = Task(desc="test task for test_task_constructor", first_scope="2020-ww02.1") assert task
def test_create_quarterly(task_v1_session): task = Task(desc="아니아", first_scope="2020—Q4") time = TimeScope(task.first_scope) assert time.type == TimeScope.Type.quarter