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 initial support for ibis.random function #2060

Merged
merged 9 commits into from
Mar 14, 2020
1 change: 1 addition & 0 deletions docs/source/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@ These methods are available directly in the ``ibis`` module namespace.
trailing_window
cumulative_window
trailing_range_window
random

.. _api.expr:

Expand Down
1 change: 1 addition & 0 deletions docs/source/release.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Release Notes
These release notes are for versions of ibis **1.0 and later**. Release
notes for pre-1.0 versions of ibis can be found at :doc:`/release-pre-1.0`

* :feature:`2060` Add initial support for ibis.random function
* :support:`2096` Added round() support for OmniSciDB
* :release:`1.3.0 <2020-02-27>`
* :support:`2066` Add support to Python 3.8
Expand Down
2 changes: 2 additions & 0 deletions ibis/expr/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from ibis.compat import to_date, to_time
from ibis.expr.analytics import bucket, histogram
from ibis.expr.groupby import GroupedTableExpr # noqa
from ibis.expr.random import random # noqa
from ibis.expr.schema import Schema
from ibis.expr.types import ( # noqa
ArrayColumn,
Expand Down Expand Up @@ -187,6 +188,7 @@
'param',
'pi',
'prevent_rewrite',
'random',
'range_window',
'row_number',
'rows_with_max_lookback',
Expand Down
5 changes: 5 additions & 0 deletions ibis/expr/operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -2450,6 +2450,11 @@ def output_type(self):
return dt.timestamp.scalar_type()


class RandomScalar(Constant):
def output_type(self):
return dt.float64.scalar_type()


class E(Constant):
def output_type(self):
return functools.partial(ir.FloatingScalar, dtype=dt.float64)
Expand Down
17 changes: 17 additions & 0 deletions ibis/expr/random.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
"""Ibis random number generation expression definitions."""

import ibis.expr.operations as ops


def random():
"""
Return a random floating point number in the range [0.0, 1.0). Similar to
``random.random`` in the Python standard library
https://docs.python.org/library/random.html

Returns
-------
random : random float value expression
"""
op = ops.RandomScalar()
return op.to_expr()
5 changes: 5 additions & 0 deletions ibis/sql/mysql/compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,10 @@ def _literal(t, expr):
return sa.literal(value)


def _random(t, expr):
return sa.func.random()


_operation_registry.update(
{
ops.Literal: _literal,
Expand All @@ -204,6 +208,7 @@ def _literal(t, expr):
ops.Log2: unary(sa.func.log2),
ops.Log10: unary(sa.func.log10),
ops.Round: _round,
ops.RandomScalar: _random,
# dates and times
ops.Date: unary(sa.func.date),
ops.DateAdd: infix_op('+'),
Expand Down
5 changes: 5 additions & 0 deletions ibis/sql/postgres/compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,10 @@ def _literal(t, expr):
return sa.literal(value)


def _random(t, expr):
return sa.func.random()


def _day_of_week_index(t, expr):
(sa_arg,) = map(t.translate, expr.op().args)
return sa.cast(
Expand Down Expand Up @@ -682,6 +686,7 @@ def _day_of_week_name(t, expr):
ops.Max: _reduction('max'),
ops.Variance: _variance_reduction('var'),
ops.StandardDev: _variance_reduction('stddev'),
ops.RandomScalar: _random,
# now is in the timezone of the server, but we want UTC
ops.TimestampNow: lambda *args: sa.func.timezone('UTC', sa.func.now()),
ops.CumulativeAll: unary(sa.func.bool_and),
Expand Down
14 changes: 14 additions & 0 deletions ibis/tests/all/test_numeric.py
Original file line number Diff line number Diff line change
Expand Up @@ -405,3 +405,17 @@ def test_sa_default_numeric_precision_and_scale(

assert_equal(schema, expected)
con.drop_table(table_name, force=True)


@pytest.mark.only_on_backends([PostgreSQL, MySQL])
def test_random(con):
expr = ibis.random()
result = con.execute(expr)
assert isinstance(result, float)
assert 0 <= result < 1

# Ensure a different random number of produced on subsequent calls
result2 = con.execute(expr)
assert isinstance(result2, float)
assert 0 <= result2 < 1
assert result != result2