Skip to content

Commit

Permalink
implemented DataKeySelector and AnnotationDataSelector #10
Browse files Browse the repository at this point in the history
  • Loading branch information
proycon committed Jan 10, 2024
1 parent 691eeab commit 3851845
Show file tree
Hide file tree
Showing 6 changed files with 163 additions and 1 deletion.
2 changes: 2 additions & 0 deletions src/annotation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ impl PyAnnotation {
annotation: Some(annotation.handle()),
resource: None,
dataset: None,
key: None,
data: None,
offset: if annotation
.as_ref()
.target()
Expand Down
37 changes: 37 additions & 0 deletions src/annotationdata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use crate::annotationdataset::PyAnnotationDataSet;
use crate::annotationstore::MapStore;
use crate::error::PyStamError;
use crate::query::*;
use crate::selector::{PySelector, PySelectorKind};
use stam::*;

#[pyclass(dict, module = "stam", name = "DataKey")]
Expand Down Expand Up @@ -145,6 +146,24 @@ impl PyDataKey {
fn annotations_count(&self) -> usize {
self.map(|key| Ok(key.annotations_count())).unwrap()
}

/// Returns a Selector (DataKeySelector) pointing to this DataKey
fn select(&self) -> PyResult<PySelector> {
self.map(|key| {
Ok(PySelector {
kind: PySelectorKind {
kind: SelectorKind::DataKeySelector,
},
dataset: None,
annotation: None,
resource: None,
key: Some((key.set().handle(), key.handle())),
data: None,
offset: None,
subselectors: Vec::new(),
})
})
}
}

impl MapStore for PyDataKey {
Expand Down Expand Up @@ -479,6 +498,24 @@ impl PyAnnotationData {
fn annotations_len(&self) -> usize {
self.map(|data| Ok(data.annotations_len())).unwrap()
}

/// Returns a Selector (AnnotationDataSelector) pointing to this AnnotationData
fn select(&self) -> PyResult<PySelector> {
self.map(|data| {
Ok(PySelector {
kind: PySelectorKind {
kind: SelectorKind::AnnotationDataSelector,
},
dataset: None,
annotation: None,
resource: None,
data: Some((data.set().handle(), data.handle())),
key: None,
offset: None,
subselectors: Vec::new(),
})
})
}
}

impl MapStore for PyAnnotationData {
Expand Down
2 changes: 2 additions & 0 deletions src/annotationdataset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,8 @@ impl PyAnnotationDataSet {
dataset: Some(dataset.handle()),
annotation: None,
resource: None,
key: None,
data: None,
offset: None,
subselectors: Vec::new(),
})
Expand Down
2 changes: 2 additions & 0 deletions src/resources.rs
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,8 @@ impl PyTextResource {
resource: Some(resource.handle()),
annotation: None,
dataset: None,
key: None,
data: None,
offset: None,
subselectors: Vec::new(),
})
Expand Down
115 changes: 114 additions & 1 deletion src/selector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use pyo3::prelude::*;
use pyo3::pyclass::CompareOp;

use crate::annotation::PyAnnotation;
use crate::annotationdata::{PyAnnotationData, PyDataKey};
use crate::annotationdataset::PyAnnotationDataSet;
use crate::annotationstore::{MapStore, PyAnnotationStore};
use crate::resources::{PyOffset, PyTextResource};
Expand Down Expand Up @@ -63,6 +64,8 @@ pub(crate) struct PySelector {
pub(crate) resource: Option<TextResourceHandle>,
pub(crate) annotation: Option<AnnotationHandle>,
pub(crate) dataset: Option<AnnotationDataSetHandle>,
pub(crate) key: Option<(AnnotationDataSetHandle, DataKeyHandle)>,
pub(crate) data: Option<(AnnotationDataSetHandle, AnnotationDataHandle)>,
pub(crate) offset: Option<PyOffset>,
pub(crate) subselectors: Vec<PySelector>,
}
Expand Down Expand Up @@ -93,6 +96,26 @@ impl PySelector {
.expect("pyselector of type datasetselector must have dataset, was checked on instantiation")
.into(),
),
SelectorKind::DataKeySelector => SelectorBuilder::DataKeySelector(
self.key
.expect("pyselector of type datakeyselector must have key, was checked on instantiation")
.0
.into(),
self.key
.expect("pyselector of type datakeyselector must have key, was checked on instantiation")
.1
.into(),
),
SelectorKind::AnnotationDataSelector => SelectorBuilder::AnnotationDataSelector(
self.data
.expect("pyselector of type annotationdataselector must have key, was checked on instantiation")
.0
.into(),
self.data
.expect("pyselector of type annotationdataselector must have key, was checked on instantiation")
.1
.into(),
),
SelectorKind::MultiSelector => {
SelectorBuilder::MultiSelector(self.subselectors.iter().map(|subselector| subselector.build()).collect())
}
Expand All @@ -110,12 +133,14 @@ impl PySelector {
#[pymethods]
impl PySelector {
#[new]
#[pyo3(signature = (kind, resource=None, annotation=None, dataset=None, offset=None, subselectors=Vec::new()))]
#[pyo3(signature = (kind, resource=None, annotation=None, dataset=None, key=None, data=None, offset=None, subselectors=Vec::new()))]
fn new(
kind: &PySelectorKind,
resource: Option<PyRef<PyTextResource>>,
annotation: Option<PyRef<PyAnnotation>>,
dataset: Option<PyRef<PyAnnotationDataSet>>,
key: Option<PyRef<PyDataKey>>,
data: Option<PyRef<PyAnnotationData>>,
offset: Option<PyRef<PyOffset>>,
subselectors: Vec<PyRef<PySelector>>,
) -> PyResult<Self> {
Expand All @@ -127,6 +152,8 @@ impl PySelector {
resource: Some(resource.handle),
annotation: None,
dataset: None,
key: None,
data: None,
offset: None,
subselectors: Vec::new(),
})
Expand All @@ -142,6 +169,8 @@ impl PySelector {
annotation: Some(annotation.handle),
resource: None,
dataset: None,
key: None,
data: None,
offset: Some(offset.clone()),
subselectors: Vec::new(),
})
Expand All @@ -151,6 +180,8 @@ impl PySelector {
annotation: Some(annotation.handle),
resource: None,
dataset: None,
key: None,
data: None,
offset: None,
subselectors: Vec::new(),
})
Expand All @@ -167,6 +198,8 @@ impl PySelector {
resource: Some(resource.handle),
annotation: None,
dataset: None,
key: None,
data: None,
offset: Some(offset.clone()),
subselectors: Vec::new(),
})
Expand All @@ -184,13 +217,47 @@ impl PySelector {
resource: None,
annotation: None,
dataset: Some(dataset.handle),
key: None,
data: None,
offset: None,
subselectors: Vec::new(),
})
} else {
Err(PyValueError::new_err("'dataset' keyword argument must be specified for DataSetSelector and point to an AnnotationDataSet instance"))
}
}
SelectorKind::DataKeySelector => {
if let Some(key) = key {
Ok(PySelector {
kind: kind.clone(),
resource: None,
annotation: None,
dataset: None,
key: Some((key.set, key.handle)),
data: None,
offset: None,
subselectors: Vec::new(),
})
} else {
Err(PyValueError::new_err("'key' keyword argument must be specified for DataKeySelector and point to a DataKey instance"))
}
}
SelectorKind::AnnotationDataSelector => {
if let Some(data) = data {
Ok(PySelector {
kind: kind.clone(),
resource: None,
annotation: None,
dataset: None,
data: Some((data.set, data.handle)),
key: None,
offset: None,
subselectors: Vec::new(),
})
} else {
Err(PyValueError::new_err("'key' keyword argument must be specified for DataKeySelector and point to a DataKey instance"))
}
}
SelectorKind::MultiSelector
| SelectorKind::CompositeSelector
| SelectorKind::DirectionalSelector => {
Expand All @@ -202,6 +269,8 @@ impl PySelector {
resource: None,
annotation: None,
dataset: None,
key: None,
data: None,
offset: None,
subselectors: subselectors.into_iter().map(|sel| sel.clone()).collect(),
})
Expand All @@ -221,6 +290,8 @@ impl PySelector {
Some(resource),
None,
None,
None,
None,
Some(offset),
Vec::new(),
)
Expand All @@ -237,6 +308,8 @@ impl PySelector {
None,
Some(annotation),
None,
None,
None,
offset,
Vec::new(),
)
Expand All @@ -251,6 +324,8 @@ impl PySelector {
None,
None,
None,
None,
None,
Vec::new(),
)
}
Expand All @@ -264,6 +339,8 @@ impl PySelector {
None,
Some(annotationset),
None,
None,
None,
Vec::new(),
)
}
Expand All @@ -278,6 +355,8 @@ impl PySelector {
None,
None,
None,
None,
None,
subselectors,
)
}
Expand All @@ -292,6 +371,8 @@ impl PySelector {
None,
None,
None,
None,
None,
subselectors,
)
}
Expand All @@ -306,6 +387,8 @@ impl PySelector {
None,
None,
None,
None,
None,
subselectors,
)
}
Expand Down Expand Up @@ -370,6 +453,28 @@ impl PySelector {
})
}

/// Returns the key this selector points at, if any.
/// Works only for DataKeySelector, returns None otherwise.
/// Requires to explicitly pass the store so the resource can be found.
fn key(&self, store: PyRef<PyAnnotationStore>) -> Option<PyDataKey> {
self.key.map(|(set_handle, key_handle)| PyDataKey {
set: set_handle,
handle: key_handle,
store: store.get_store().clone(),
})
}

/// Returns the annotationdata this selector points at, if any.
/// Works only for AnnotationDataSelector, returns None otherwise.
/// Requires to explicitly pass the store so the resource can be found.
fn annotationdata(&self, store: PyRef<PyAnnotationStore>) -> Option<PyAnnotationData> {
self.data.map(|(set_handle, data_handle)| PyAnnotationData {
set: set_handle,
handle: data_handle,
store: store.get_store().clone(),
})
}

/// Returns the annotation this selector points at, if any.
/// Works only for AnnotationSelector, returns None otherwise.
/// Requires to explicitly pass the store so the resource can be found.
Expand Down Expand Up @@ -420,6 +525,14 @@ impl PySelector {
Selector::AnnotationSelector(a_id, ..) => Some(*a_id),
_ => None,
},
key: match selector {
Selector::DataKeySelector(set_id, key_id) => Some((*set_id, *key_id)),
_ => None,
},
data: match selector {
Selector::AnnotationDataSelector(set_id, data_id) => Some((*set_id, *data_id)),
_ => None,
},
offset: selector.offset(store).map(|offset| PyOffset { offset }),
subselectors: if selector.is_complex() {
if let Some(subselectors) = selector.subselectors() {
Expand Down
6 changes: 6 additions & 0 deletions stam.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -868,6 +868,9 @@ class DataKey:
The maximum number of results to return (default: unlimited)
"""

def select(self) -> Selector:
"""Returns a selector pointing to this key (DataKeySelector)"""

class DataValue:
"""Encapsulates a value and its type. Held by :class:`AnnotationData`. This type is not a reference but holds the actual value."""

Expand Down Expand Up @@ -963,6 +966,9 @@ class AnnotationData:
The maximum number of results to return (default: unlimited)
"""

def select(self) -> Selector:
"""Returns a selector pointing to this data (AnnotationDataSelector)"""

class Data:
"""
A `Data` object holds an arbitrary collection of annotation data.
Expand Down

0 comments on commit 3851845

Please sign in to comment.