Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,24 @@ Changelog
=========


0.18.2 (not yet released)
~~~~~~~~~~~~~~~~~~~~~~~~~

Bug fixes and minor changes
---------------------------

+ `#83`_, `#84`_: enable ordering on one to many relationships in
class :class:`icat.query.Query`.

+ `#84`_: Add warning classes
:exc:`icat.exception.QueryOneToManyOrderWarning` and
:exc:`icat.exception.QueryWarning`, the latter being a common base
class for warnings emitted during creation of a query.

.. _#83: https://github.com/icatproject/python-icat/issues/83
.. _#84: https://github.com/icatproject/python-icat/pull/84


0.18.1 (2021-04-13)
~~~~~~~~~~~~~~~~~~~

Expand Down
12 changes: 11 additions & 1 deletion doc/src/exception.rst
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,18 @@ Exceptions raised by python-icat
:members:
:show-inheritance:

.. autoexception:: icat.exception.QueryWarning
:members:
:show-inheritance:

.. autoexception:: icat.exception.QueryNullableOrderWarning
:members:
:show-inheritance:

.. autoexception:: icat.exception.QueryOneToManyOrderWarning
:members:
:show-inheritance:

.. autoexception:: icat.exception.ClientVersionWarning
:members:
:show-inheritance:
Expand Down Expand Up @@ -178,7 +186,9 @@ The class hierarchy for the exceptions is::
+-- IDSResponseError
+-- GenealogyError
+-- Warning
+-- QueryNullableOrderWarning
+-- QueryWarning
| +-- QueryNullableOrderWarning
| +-- QueryOneToManyOrderWarning
+-- ClientVersionWarning
+-- DeprecationWarning
+-- ICATDeprecationWarning
Expand Down
28 changes: 24 additions & 4 deletions icat/exception.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
# icat.config
'ConfigError',
# icat.query
'QueryNullableOrderWarning',
'QueryWarning', 'QueryNullableOrderWarning', 'QueryOneToManyOrderWarning',
# icat.client, icat.entity
'ClientVersionWarning', 'ICATDeprecationWarning',
'EntityTypeError', 'VersionMethodError', 'SearchResultError',
Expand Down Expand Up @@ -305,14 +305,34 @@ class ConfigError(_BaseException):

# ================ Exceptions raised in icat.query =================

class QueryNullableOrderWarning(Warning):
"""Warn about using a nullable relation for ordering.
class QueryWarning(Warning):
"""Warning while building a query.

.. versionadded:: 0.18.2
"""
pass

class QueryNullableOrderWarning(QueryWarning):
"""Warn about using a nullable many to one relation for ordering.

.. versionchanged:: 0.18.2
Inherit from :exc:`QueryWarning`.
"""
def __init__(self, attr):
msg = ("ordering on a nullable relation implicitly "
msg = ("ordering on a nullable many to one relation implicitly "
"adds a '%s IS NOT NULL' condition." % attr)
super(QueryNullableOrderWarning, self).__init__(msg)

class QueryOneToManyOrderWarning(QueryWarning):
"""Warn about using a one to many relation for ordering.

.. versionadded:: 0.18.2
"""
def __init__(self, attr):
msg = ("ordering on a one to many relation %s may surprisingly "
"affect the search result." % attr)
super().__init__(msg)


# ======== Exceptions raised in icat.client and icat.entity ========

Expand Down
14 changes: 9 additions & 5 deletions icat/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -262,8 +262,12 @@ def setOrder(self, order):
name and an order direction, the latter being either "ASC"
or "DESC" for ascending or descending order respectively.
:type order: iterable or :class:`bool`
:raise ValueError: if `order` contains invalid attributes that
either do not exist or contain one to many relationships.
:raise ValueError: if any attribute in `order` is not valid.

.. versionchanged:: 0.18.2
allow one to many relationships in `order`. Emit a
:exc:`~icat.exception.QueryOneToManyOrderWarning` rather
then raising a :exc:`ValueError` in this case.
"""
if order is True:

Expand Down Expand Up @@ -291,9 +295,9 @@ def setOrder(self, order):
warn(QueryNullableOrderWarning(pattr),
stacklevel=sl)
elif attrInfo.relType == "MANY":
raise ValueError("Cannot use one to many relationship "
"in '%s' to order %s."
% (obj, self.entity.BeanName))
sl = 3 if self._init else 2
warn(QueryOneToManyOrderWarning(pattr),
stacklevel=sl)

if rclass is None:
# obj is an attribute, use it right away.
Expand Down
28 changes: 28 additions & 0 deletions tests/test_06_query.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from distutils.version import StrictVersion as Version
import re
import sys
import warnings
import pytest
import icat
import icat.config
Expand Down Expand Up @@ -316,6 +317,33 @@ def test_query_nullable_warning_suppressed(client, recwarn):
res = client.search(query)
assert len(res) == 44

def test_query_order_one_to_many(client, recwarn):
"""Sort on a related object in a one yo many relation.
This has been enabled in #84, but a warning is still emitted.
"""
recwarn.clear()
query = Query(client, "Investigation",
order=['investigationInstruments.instrument.fullName'])
w = recwarn.pop(icat.QueryOneToManyOrderWarning)
assert issubclass(w.category, icat.QueryOneToManyOrderWarning)
assert "investigationInstruments" in str(w.message)
print(str(query))
res = client.search(query)
assert len(res) == 3

def test_query_order_suppress_warnings(client, recwarn):
"""Suppress all QueryWarnings.
"""
recwarn.clear()
with warnings.catch_warnings():
warnings.simplefilter("ignore", category=icat.QueryWarning)
query = Query(client, "Investigation",
order=['investigationInstruments.instrument.fullName'])
assert len(recwarn.list) == 0
print(str(query))
res = client.search(query)
assert len(res) == 3

def test_query_limit(client):
"""Add a LIMIT clause to the last example.
"""
Expand Down