Skip to content

Commit

Permalink
Rating implementation
Browse files Browse the repository at this point in the history
A fixed field called rating is implemented, accepting values from 1 to 10,
or None if not set.
  • Loading branch information
pboettch authored and jeandet committed Nov 15, 2023
1 parent 058bd9e commit c37ce8f
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 8 deletions.
2 changes: 1 addition & 1 deletion tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ def test_entities_fix_keys_and_values_can_be_retrieved(self):
e = create_event(dt.datetime.now(), dt.datetime.now() + dt.timedelta(days=1), "Patrick", other_attr="asd",
other_attr2=123)
keys = list(sorted(e.fixed_attributes().keys()))
self.assertListEqual(sorted(['author', 'products', 'start', 'stop', 'tags', 'uuid']), keys)
self.assertListEqual(sorted(['author', 'products', 'start', 'stop', 'tags', 'uuid', 'rating']), keys)

keys = list(sorted(e.variable_attributes().keys()))
self.assertListEqual(sorted(['other_attr', 'other_attr2']), keys)
Expand Down
29 changes: 28 additions & 1 deletion tests/test_event.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def test_constructor_various_combinations_all_ok(self, start, stop, author, uuid
tags = re.escape(str(tags))
products = re.escape(str(products))
r = r'^Event\(start=.*, stop=.*, author=' + author + r', uuid=[0-9a-f-]{36}, tags=' + tags \
+ r', products=' + products + r'\) attributes\(' + attr_repr + r'\)$'
+ r', products=' + products + r', rating=None\) attributes\(' + attr_repr + r'\)$'

self.assertRegex(f'{e}', r)

Expand Down Expand Up @@ -102,3 +102,30 @@ def test_constructor_with_dynamic_attribute_manual_access(self):
self.assertEqual(e.field_str, "string-test")
self.assertEqual(e.field_bool, True)
self.assertEqual(e.field_dt, dt_val)

def test_event_rating(self):
t1, t2 = dt.datetime.now(), dt.datetime.now() + dt.timedelta(days=1)

e = create_event(t1, t2, "Patrick")
self.assertEqual(e.rating, None)

e.rating = 1
self.assertEqual(e.rating, 1)

e.rating = 5
self.assertEqual(e.rating, 5)

e.rating = None
self.assertEqual(e.rating, None)

with self.assertRaises(ValueError):
e.rating = -1

with self.assertRaises(ValueError):
e.rating = 0

with self.assertRaises(ValueError):
e.rating = 1.5

with self.assertRaises(ValueError):
e.rating = 11
19 changes: 14 additions & 5 deletions tscat/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def backend() -> orm_sqlalchemy.Backend:


def _listify(v) -> Union[List, Tuple]:
if type(v) in [list, tuple]:
if isinstance(v, (list, tuple)):
return v
else:
return [v]
Expand Down Expand Up @@ -144,13 +144,14 @@ def is_removed(self) -> bool:
return self._removed

class _Event(_BackendBasedEntity):
_fixed_keys = ['start', 'stop', 'author', 'uuid', 'tags', 'products']
_fixed_keys = ['start', 'stop', 'author', 'uuid', 'tags', 'products', 'rating']

def __init__(self, start: dt.datetime, stop: dt.datetime,
author: str,
uuid: Optional[str] = None,
tags: Iterable[str] = [],
products: Iterable[str] = [],
rating: Optional[int] = None,
_insert: bool = True,
**kwargs):
self._in_ctor = True
Expand All @@ -161,6 +162,7 @@ def __init__(self, start: dt.datetime, stop: dt.datetime,
self.author = author
self.tags = list(tags)
self.products = list(products)
self.rating = rating

if not uuid:
self.uuid = str(uuid4())
Expand All @@ -178,6 +180,7 @@ def __init__(self, start: dt.datetime, stop: dt.datetime,
'uuid': self.uuid,
'tags': self.tags,
'products': self.products,
'rating': self.rating,
'attributes': kwargs,
})

Expand All @@ -193,10 +196,16 @@ def __setattr__(self, key, value):
if value < self.start:
raise ValueError("stop date has to be after start date")
elif key in ['tags', 'products']:
if any(type(v) != str for v in value):
if any(not isinstance(v, str) for v in value):
raise ValueError("a tag has to be a string")
if any(',' in v for v in value):
raise ValueError("a string-list value shall not contain a comma")
elif key == 'rating':
if value is not None:
if not isinstance(value, int):
raise ValueError("rating has to be an integer value")
if value < 1 or value > 10:
raise ValueError("rating has to be between 1 and 10")

super(_Event, self).__setattr__(key, value)

Expand Down Expand Up @@ -253,7 +262,7 @@ def __setattr__(self, key, value):
if not value:
raise ValueError('Catalogue name cannot be emtpy.')
elif key == 'tags':
if any(type(v) != str for v in value):
if any(not isinstance(v, str) for v in value):
raise ValueError("a tag has to be a string")
if any(',' in v for v in value):
raise ValueError("a string-list value shall not contain a comma")
Expand Down Expand Up @@ -351,7 +360,7 @@ def get_events(base: Union[Predicate, _Catalogue, None] = None,

events = []
for ev in backend().get_events(base_dict):
e = _Event(ev['start'], ev['stop'], ev['author'], ev['uuid'], ev['tags'], ev['products'],
e = _Event(ev['start'], ev['stop'], ev['author'], ev['uuid'], ev['tags'], ev['products'], ev['rating'],
**ev['attributes'], _insert=False)
e._removed = removed_items
e._backend_entity = ev['entity']
Expand Down
4 changes: 4 additions & 0 deletions tscat/import_export.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,9 @@ def __init__(self, attrs: Dict[str, str], tscat_name: Optional[str] = None) -> N
__VOTableTSCatFieldSpecialDateTime({'name': "Start Time", 'ID': "TimeIntervalStart", 'ucd': "time.start"}, 'start'),
__VOTableTSCatFieldSpecialDateTime({'name': "Stop Time", 'ID': "TimeIntervalStop", 'ucd': "time.end"}, 'stop'),
__VOTableTSCatFieldSpecialDateTime({}),
__VOTableTSCatField(int, {'datatype': 'long'},
lambda x: 0 if x is None else x,
lambda x: None if x == 0 else x, 'rating'),
__VOTableTSCatField(int, {'datatype': 'long'}, int, int),
__VOTableTSCatField(float, {'datatype': 'double'}, float, float),
__VOTableTSCatField(bool, {'datatype': 'boolean'}, bool, bool),
Expand Down Expand Up @@ -246,6 +249,7 @@ def export_votable(catalogues: Union[List[_Catalogue], _Catalogue]) -> VOTableFi
('uuid', __vo_table_field_from(str)),
('tags', __vo_table_field_from(list)),
('products', __vo_table_field_from(list)),
('rating', __vo_table_field_from('rating')),
]

events = get_events(catalogue)
Expand Down
3 changes: 3 additions & 0 deletions tscat/orm_sqlalchemy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ def add_event(self, event: Dict) -> orm.Event:
event['uuid'],
event['tags'],
event['products'],
event['rating'],
event['attributes'])

def add_events_to_catalogue(self, catalogue: orm.Catalogue, events: List[orm.Event]) -> None:
Expand Down Expand Up @@ -248,6 +249,7 @@ def get_events(self, base: Dict = {}) -> List[Dict]:
"uuid": e.uuid,
"tags": e.tags,
"products": e.products,
"rating": e.rating,
"attributes": e.attributes,
"entity": e}
events.append(event)
Expand All @@ -264,6 +266,7 @@ def get_events_by_uuid_list(self, uuids: List[str]) -> Dict[str, Dict]:
"uuid": e.uuid,
"tags": e.tags,
"products": e.products,
"rating": e.rating,
"attributes": e.attributes,
"entity": e}

Expand Down
4 changes: 3 additions & 1 deletion tscat/orm_sqlalchemy/orm.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,20 @@ class Event(Base):

tags: List[str] = Column(ScalarListType(str), default=[], info={"type": (list, "string_list")})
products: List[str] = Column(ScalarListType(str), default=[], info={"type": (list, "string_list")})
rating: int = Column(Integer, default=None, nullable=True)

removed: bool = Column(Boolean, default=False, nullable=False)

attributes: Dict[str, Any] = Column(MutableDict.as_mutable(JSON))

def __init__(self, start, stop, author, uuid, tags, products, attributes):
def __init__(self, start, stop, author, uuid, tags, products, rating, attributes):
self.start = start
self.stop = stop
self.author = author
self.uuid = uuid
self.tags = tags
self.products = products
self.rating = rating
self.attributes = attributes

def __repr__(self): # pragma: no cover
Expand Down

0 comments on commit c37ce8f

Please sign in to comment.