def test_repository_raises_error_if_get_finds_more_than_one_entity( self, repo: Repository) -> None: """ Given: Two entities of different type with the same ID When: We get the ID without specifying the model Then: a TooManyEntitiesError error is raised """ entities = AuthorFactory.batch(2, name="same name") repo.add(entities) repo.commit() with pytest.raises(TooManyEntitiesError, match=""): repo.get("same name", Author, "name") # act
def test_repository_raises_error_if_no_entity_found_by_get( self, repo: Repository, entity: Entity, ) -> None: """As the entity is not inserted into the repository, it shouldn't be found.""" with pytest.raises( EntityNotFoundError, match=( f"There are no entities of type {entity.model_name} in the " f"repository with id_ {entity.id_}."), ): repo.get(entity.id_, type(entity))
def test_thaw_task_by_id( self, runner: CliRunner, insert_frozen_parent_task_e2e: RecurrentTask, repo_e2e: Repository, caplog: LogCaptureFixture, ) -> None: """ Given: A frozen recurrent task When: Thawed Then: The task is back active and it's next children is breed. """ parent_task = insert_frozen_parent_task_e2e now = datetime.now() result = runner.invoke(cli, ["thaw", str(parent_task.id_)]) parent_task = repo_e2e.get(parent_task.id_, [RecurrentTask]) child_task = repo_e2e.search({"parent_id": parent_task.id_}, [Task])[0] assert result.exit_code == 0 assert ( "pydo.services", logging.INFO, f"Thawed task {parent_task.id_}: {parent_task.description}, and created " f"it's next child task with id {child_task.id_}", ) in caplog.record_tuples assert parent_task.state == TaskState.BACKLOG assert parent_task.active is True assert child_task.state == TaskState.BACKLOG assert child_task.active is True assert child_task.due is not None assert child_task.due > now
def test_modify_task_can_remove_tag_that_starts_with_p( self, runner: CliRunner, insert_tasks_e2e: List[Task], faker: Faker, repo_e2e: Repository, caplog: LogCaptureFixture, ) -> None: """ Given: A task with a tag that starts with a p When: removing the tag Then: the tag is removed It's necessary in case we start using the `--parent` flag as `-p`, in that case when using `pydo mod 0 -python`, it interprets that the parent flag is set and that the tag is ython. """ task = insert_tasks_e2e[0] task.tags = ["python"] repo_e2e.add(task) repo_e2e.commit() result = runner.invoke(cli, ["mod", str(task.id_), "-python"]) modified_task = repo_e2e.get(task.id_, [Task]) assert result.exit_code == 0 assert re.match(f"Modified task {task.id_}", caplog.records[0].msg) assert modified_task.tags == [] assert modified_task.description == task.description
def freeze_tasks( repo: Repository, selector: TaskSelector, ) -> None: """Freeze a list of tasks based on a task filter.""" tasks = _tasks_from_selector(repo, selector) for task in tasks: if type(task) == Task: child_task = task if child_task.parent_id is None: raise ValueError( f"Task {child_task.id_}: {child_task.description} is not the child" " of any recurrent task, so it can't be frozen") parent_task = repo.get(child_task.parent_id, [RecurrentTask]) elif type(task) == RecurrentTask: parent_task = task try: child_task = repo.search( { "active": True, "parent_id": task.id_ }, [Task])[0] except EntityNotFoundError as error: raise EntityNotFoundError( f"The recurrent task {task.id_}: {task.description} has no active " "children") from error parent_task.freeze() repo.add(parent_task) repo.delete(child_task) log.info( f"Frozen recurrent task {parent_task.id_}: {parent_task.description} and " f"deleted it's last child {child_task.id_}") repo.commit()
def test_repository_raises_error_if_get_finds_more_than_one_entity( self, repo: Repository, inserted_entity: Entity ) -> None: """ Given: Two entities of different type with the same ID When: We get the ID without specifying the model Then: a TooManyEntitiesError error is raised """ other_entity = OtherEntity(id_=inserted_entity.id_, name="Other entity") repo.models = [type(inserted_entity), OtherEntity] # type: ignore repo.add(other_entity) repo.commit() with pytest.warns( UserWarning, match="In 2022-06-10.*deprecated" ), pytest.raises(TooManyEntitiesError, match=""): repo.get(inserted_entity.id_) # act
def test_repository_can_retrieve_an_entity_if_no_model_defined( self, repo: Repository, inserted_entity: Entity, ) -> None: """Given an entity_id the repository returns the entity object.""" repo.models = [type(inserted_entity)] # type: ignore with pytest.warns(UserWarning, match="In 2022-06-10.*deprecated"): result: Entity = repo.get(inserted_entity.id_) assert result == inserted_entity assert result.id_ == inserted_entity.id_
def test_repository_can_retrieve_an_entity_if_list_of_models_defined( self, repo: Repository, inserted_entity: Entity, ) -> None: """Given an entity_id the repository returns the entity object.""" entity_models: List[Type[Entity]] = [type(inserted_entity), OtherEntity] repo.models = entity_models # type: ignore with pytest.warns(UserWarning, match="In 2022-06-10.*deprecated"): result = repo.get(inserted_entity.id_, entity_models) assert result == inserted_entity assert result.id_ == inserted_entity.id_
def test_add_a_task_with_an_inexistent_tag( self, runner: CliRunner, faker: Faker, caplog: LogCaptureFixture, repo_e2e: Repository, ) -> None: """Test the insertion of a task with a tag.""" description = faker.sentence() tag = faker.word() result = runner.invoke(cli, ["add", description, f"+{tag}"]) task = repo_e2e.get(0, [Task]) assert result.exit_code == 0 assert re.match(f"Added task .*: {description}", caplog.records[0].msg) assert tag in task.tags
def test_repository_can_retrieve_an_entity_by_a_different_attribute( self, repo: Repository, inserted_str_entity: Entity, ) -> None: """ Given an attribute and it's value, the repository returns the entity object. The entity is also added to the cache. """ entity = inserted_str_entity result = repo.get(entity.name, type(entity), "name") assert result == entity assert result.id_ == entity.id_ assert repo.cache.get(entity) == entity assert result.defined_values == {}
def test_thaw_task_by_id_accepts_state( self, runner: CliRunner, insert_frozen_parent_task_e2e: RecurrentTask, repo_e2e: Repository, caplog: LogCaptureFixture, ) -> None: """Test thawing accepts the thawing state of the tasks.""" parent_task = insert_frozen_parent_task_e2e result = runner.invoke( cli, ["thaw", str(parent_task.id_), "-s", "todo"]) parent_task = repo_e2e.get(parent_task.id_, [RecurrentTask]) child_task = repo_e2e.search({"parent_id": parent_task.id_}, [Task])[0] assert result.exit_code == 0 # T101: fixme found (T O D O). Lol, it's not a comment to fix something assert parent_task.state == TaskState.TODO # noqa: T101 assert child_task.state == TaskState.TODO # noqa: T101
def test_repository_can_retrieve_an_entity( self, repo: Repository, inserted_entity: Entity, ) -> None: """Given an entity_id the repository returns the entity object. The entity is also added to the cache. The entity _desired_values are empty. This is needed because otherwise all attributes are set when you do repo.get() and therefore the merge behaves weirdly. """ result = repo.get(inserted_entity.id_, type(inserted_entity)) assert result == inserted_entity assert result.id_ == inserted_entity.id_ assert repo.cache.get(inserted_entity) == inserted_entity assert result.defined_values == {}
def _close_task( repo: Repository, task: Task, state: TaskState, close_date_str: str = "now", delete_parent: bool = False, ) -> None: """Close a task. It gathers the common actions required to complete or delete tasks. """ close_date = convert_date(close_date_str) task.close(state, close_date) repo.add(task) # If it's a child task of another task if task.parent_id is not None: log.info( f"Closing child task {task.id_}: {task.description} with state {state}" ) parent_task = repo.get(task.parent_id, [Task, RecurrentTask]) # If we want to close the parent of the task. if delete_parent: parent_task.close(state, close_date) repo.add(parent_task) log.info( f"Closing parent task {parent_task.id_}: {parent_task.description} with" f" state {state}") # If it's a child task of a recurrent one, we need to spawn the next child. elif isinstance(parent_task, RecurrentTask): new_child_task = parent_task.breed_children(task) repo.add(new_child_task) log.info( f"Added child task {new_child_task.id_}: {new_child_task.description}", ) # If it's a simple task else: log.info( f"Closing task {task.id_}: {task.description} with state {state}") if delete_parent: log.info(f"Task {task.id_} doesn't have a parent")
def _tasks_from_selector(repo: Repository, selector: TaskSelector) -> List[TaskType]: """Return the tasks that match the criteria of the task selector.""" tasks: List[TaskType] = [ repo.get(task_id, [selector.model]) for task_id in selector.task_ids ] if selector.task_filter != {}: # Remove the tasks that don't meet the task_filter for task in tasks: # Check if the task_filter is not a subset of the properties of the task. # SIM205: Use 'selector.task_filter.items() > task.dict().items()' instead # No can't do, if we do, the subset checking doesn't work if not selector.task_filter.items() <= task.dict().items( ): # noqa: SIM205 tasks.remove(task) with suppress(EntityNotFoundError): tasks.extend(repo.search(selector.task_filter, [selector.model])) # Remove duplicates return list(set(tasks))
def test_modify_task_can_unset_attribute( self, runner: CliRunner, insert_tasks_e2e: List[Task], faker: Faker, repo_e2e: Repository, caplog: LogCaptureFixture, ) -> None: """ Given: A task with the priority attribute set When: setting the attribute to none Then: the priority is set to None """ task = insert_tasks_e2e[0] task.priority = 3 repo_e2e.add(task) repo_e2e.commit() result = runner.invoke(cli, ["mod", str(task.id_), "pri:"]) modified_task = repo_e2e.get(task.id_, [Task]) assert result.exit_code == 0 assert modified_task.priority is None
def create_greeting(repo: Repository, author_id: int) -> str: author = repo.get(author_id, Author) return f"Hi {author.first_name}!"