Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add issubset, issuperset and size to Range type #563

Merged
merged 8 commits into from
Aug 2, 2021

Conversation

kdorsel
Copy link
Contributor

@kdorsel kdorsel commented Apr 24, 2020

Adding issubset, issuperset and size methods to the Range type.

This should correctly handle all corner cases with empty, lower/upper included or not for set methods. For empty sets follows the same rules as Python's super and sub set methods.

Size method takes in optional step parameter for when lower_inc == upper_inc since this will either add or remove 1 step size to the size of the range.

If this initial implementation is something worthwhile I can also add tests for it.

Closes #559

asyncpg/types.py Outdated
lowerOk = True
else:
if self._lower is None:
return False
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would read better if you set lowerOk = False here and use an elif. Also, please use lower_ok for the variable name for style consistency.

asyncpg/types.py Outdated
def issuperset(self, other):
return other.issubset(self)

def size(self, step=None):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not understand why the step argument is necessary. The size of the range is determined unambiguously by whether the upper and lower bounds are inclusive.

Copy link
Contributor Author

@kdorsel kdorsel Apr 24, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The returned size for [1,2) and [1,2] should be different. In postgres they have a distinction between a discrete and continuous range. If this was a discrete integer range the results would be 2-1 = 1 and 2-1+1=2. +1 since the discrete step for an integer is 1. What is the step value for continuous range like a float? Or if using datetime what is your lowest time increment you care about.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I think the generic Range class shouldn't be implementing the size() method then. It's too dependent on the data type and, since Postgres allows user-defined range types, hardcoding it for int, float, and date types wouldn't save us.

Copy link
Contributor

@lelit lelit Oct 27, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The distinction between "discrete" and "continuous" ranges has an impact also on issubset() and issuperset().

Consider the following two ranges: (1,2]::int4range and [2,3)::int4range. They represent the very same set of values, and indeed select '(1,2]'::int4range <@ '[2,3)'::int4range returns True, but

>>> r1 = asyncpg.Range(1, 2, lower_inc=False, upper_inc=True)
>>> r2 = asyncpg.Range(2, 3, lower_inc=True, upper_inc=False)
>>> r1.issubset(r2)
False

asyncpg/types.py Outdated

def size(self, step=None):
if self._upper is None or self._lower is None:
return None
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be better to raise a ValueError here. size() on an open range is meaningless and akin to division by zero, returning None in this case risks masking bugs.

Copy link
Contributor Author

@kdorsel kdorsel Apr 24, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I understood it, a None in either lower/upper means infinity which matches the null/missing bound definition of postgres. Hence why I return the "infinity". I'm ok either way.

For numbers this could be changed from None to float("inf"), and for datetimes to datetime.datetime.min/max.

Copy link
Contributor Author

@kdorsel kdorsel Apr 24, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since postgres only has numeric and date/time ranges adding type check for datetime and numeric and returning values for each one and removing None completely might be worthwhile refactor.

It would also simply the logic in here since there is no longer a need for checking None.

asyncpg/types.py Outdated
else:
upperOk = self._upper < other._upper

return lowerOk and upperOk
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lowerOk is always True by this point, so returning just upperOk is sufficient.

@elprans
Copy link
Member

elprans commented Apr 25, 2020

Looks good now. Please add some tests.

@elprans
Copy link
Member

elprans commented May 2, 2020

Please fix flake8 issues, and let's merge. Thanks!

@elprans elprans merged commit de07d0a into MagicStack:master Aug 2, 2021
elprans added a commit that referenced this pull request Aug 10, 2021
Changes
-------

* Drop support for Python 3.5 (#777)
  (by @and-semakin in da58cd2 for #777)

* Add support for Python 3.10 (#795)
  (by @elprans in abf5569 for #795)

* Add support for asynchronous iterables to copy_records_to_table() (#713)
  (by @elprans in 1d33ff6 for #713)

* Add support for coroutine functions as listener callbacks (#802)
  (by @elprans in 41da093 for #802)

* Add support for sslcert, sslkey and sslrootcert parameters to DSN (#768)
  (by @jdobes and @elprans in c674e86 for #768)

* Add copy_ wrappers to Pool (#661)
  (by @elprans in a6b0f28 for #661)

* Add issubset and issuperset methods to the Range type (#563)
  (by @kdorsel in de07d0a for #563)

Fixes
-----

* Break connection internal circular reference (#774)
  (by @fantix in d08a9b8 for #774)

* Make Server Version Extraction More Flexible (#778)
  (by @Natrinicle in d076169 for #778)
@elprans elprans mentioned this pull request Aug 10, 2021
elprans added a commit that referenced this pull request Aug 10, 2021
Changes
-------

* Drop support for Python 3.5 (#777)
  (by @and-semakin in da58cd2 for #777)

* Add support for Python 3.10 (#795)
  (by @elprans in abf5569 for #795)

* Add support for asynchronous iterables to copy_records_to_table() (#713)
  (by @elprans in 1d33ff6 for #713)

* Add support for coroutine functions as listener callbacks (#802)
  (by @elprans in 41da093 for #802)

* Add support for sslcert, sslkey and sslrootcert parameters to DSN (#768)
  (by @jdobes and @elprans in c674e86 for #768)

* Add copy_ wrappers to Pool (#661)
  (by @elprans in a6b0f28 for #661)

* Add issubset and issuperset methods to the Range type (#563)
  (by @kdorsel in de07d0a for #563)

Fixes
-----

* Break connection internal circular reference (#774)
  (by @fantix in d08a9b8 for #774)

* Make Server Version Extraction More Flexible (#778)
  (by @Natrinicle in d076169 for #778)
elprans added a commit that referenced this pull request Aug 10, 2021
Changes
-------

* Drop support for Python 3.5 (#777)
  (by @and-semakin in da58cd2 for #777)

* Add support for Python 3.10 (#795)
  (by @elprans in abf5569 for #795)

* Add support for asynchronous iterables to copy_records_to_table() (#713)
  (by @elprans in 1d33ff6 for #713)

* Add support for coroutine functions as listener callbacks (#802)
  (by @elprans in 41da093 for #802)

* Add support for sslcert, sslkey and sslrootcert parameters to DSN (#768)
  (by @jdobes and @elprans in c674e86 for #768)

* Add copy_ wrappers to Pool (#661)
  (by @elprans in a6b0f28 for #661)

* Add issubset and issuperset methods to the Range type (#563)
  (by @kdorsel in de07d0a for #563)

Fixes
-----

* Break connection internal circular reference (#774)
  (by @fantix in d08a9b8 for #774)

* Make Server Version Extraction More Flexible (#778)
  (by @Natrinicle in d076169 for #778)
@kdorsel kdorsel deleted the range-methods branch October 27, 2022 14:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Using subclass of Range as default return type
3 participants