diff --git a/src/task/tag.rs b/src/task/tag.rs index 7f3a03a..7216728 100644 --- a/src/task/tag.rs +++ b/src/task/tag.rs @@ -1,17 +1,26 @@ -use pyo3::prelude::*; +use pyo3::{exceptions::PyValueError, prelude::*}; use taskchampion::Tag as TCTag; -/// TODO: following the api there currently is no way to construct the task by hand, not sure if this is -/// correct #[pyclass] -pub struct Tag(pub(crate) TCTag); +pub struct Tag(TCTag); #[pymethods] impl Tag { #[new] - pub fn new(tag: String) -> anyhow::Result { - Ok(Tag(tag.parse()?)) + pub fn new(tag: String) -> PyResult { + Ok(Tag(tag + .parse() + .map_err(|_| PyValueError::new_err("Invalid tag"))?)) } + + pub fn __repr__(&self) -> String { + format!("{:?}", self.0) + } + + pub fn __str__(&self) -> String { + self.0.to_string() + } + pub fn is_synthetic(&self) -> bool { self.0.is_synthetic() } @@ -21,6 +30,18 @@ impl Tag { } } +impl AsRef for Tag { + fn as_ref(&self) -> &TCTag { + &self.0 + } +} + +impl From for Tag { + fn from(value: TCTag) -> Self { + Tag(value) + } +} + impl From for TCTag { fn from(value: Tag) -> Self { value.0 diff --git a/src/task/task.rs b/src/task/task.rs index 2865ff3..fed54b2 100644 --- a/src/task/task.rs +++ b/src/task/task.rs @@ -93,10 +93,8 @@ impl Task { /// /// Returns: /// bool: if the task has a given tag - // TODO: Not very user friendly; User has to construct a Tag object and then pass is into here. - // Should probably use a string pub fn has_tag(&self, tag: &Tag) -> bool { - self.0.has_tag(&tag.0) + self.0.has_tag(tag.as_ref()) } /// Get task tags @@ -104,7 +102,7 @@ impl Task { /// Returns: /// list[str]: list of tags pub fn get_tags(&self) -> Vec { - self.0.get_tags().map(Tag).collect() + self.0.get_tags().map(Tag::from).collect() } /// Get task annotations /// @@ -280,7 +278,7 @@ impl Task { pub fn add_tag(&mut self, tag: &Tag) -> anyhow::Result> { let mut ops: Vec = Vec::new(); - self.0.add_tag(&tag.0, &mut ops).expect(""); + self.0.add_tag(tag.as_ref(), &mut ops).expect(""); Ok(ops.iter().map(|op| Operation(op.clone())).collect()) } @@ -288,7 +286,7 @@ impl Task { pub fn remove_tag(&mut self, tag: &Tag) -> anyhow::Result> { let mut ops: Vec = Vec::new(); - self.0.remove_tag(&tag.0, &mut ops).expect(""); + self.0.remove_tag(tag.as_ref(), &mut ops).expect(""); Ok(ops.iter().map(|op| Operation(op.clone())).collect()) } diff --git a/tests/test_tag.py b/tests/test_tag.py index e0ec831..fa2ab86 100644 --- a/tests/test_tag.py +++ b/tests/test_tag.py @@ -12,6 +12,23 @@ def synthetic_tag(): return Tag("UNBLOCKED") +def test_invalid(): + with pytest.raises(ValueError): + Tag("-24098") + with pytest.raises(ValueError): + Tag("FOO") + + +def test_repr(user_tag, synthetic_tag): + assert repr(user_tag) == 'Tag(User("user_tag"))' + assert repr(synthetic_tag) == "Tag(Synthetic(Unblocked))" + + +def test_str(user_tag, synthetic_tag): + assert str(user_tag) == "user_tag" + assert str(synthetic_tag) == "UNBLOCKED" + + def test_user_tag(user_tag: Tag): assert user_tag.is_user() assert not user_tag.is_synthetic()