Closed armona closed 1 year ago
It's possible and I've been asked about it before. It would just be alot of work.
I might have a poke at it on my spare times. Any guidance on how it should be implemented? which areas need change/additions?
The ideal implementation would likely involve: 1) A new function / callable datatype. New data types are a lot of work. 2) Parser support for making a function call. 3) An AST node for the function call with a reduction method. The reduction should probably support the function being known at parse time which would involve a bit of research into solutions and patterns. 4) Type hinting and propagation as necessary for the AST node of the function call. 5) Unit tests for the whole thing. 6) Documentation updates describing how to use it.
This may be something that I work on if it becomes necessary in my project (right now I can get around it, but this is a fairly important feature). @armona have you done any work on this?
@rwspielman I started working on it (not a lot though), but as @zeroSteiner said it is a lot of wok and I can't find the time to implement it.
I'm also interested about custom functions, I have an use case like this :
last_seen <= now('-15d')
Where last_seen
is a date in ISO format with timezone aware.
@nicolas-rdgs
You can do that already as long as last_seen
is a datetime.datetime
instance. DATETIME objects are timezone aware already. If there's no timezone information associated with it, then the default_timezone
is used from the context.
edit the 'context' and 'thing' objects as necessary
>>> import datetime
>>> thing = {'last_seen': datetime.datetime.now()}
>>>
exiting the edit console...
rule > last_seen <= ($now - t"P15D")
result:
False
rule >
I've started on this in a feature branch. There's still quite a bit left to do. I still need to:
So far the parsing and AST node generation with reduction is in place and appears to be working just fine.
PYTHONPATH=lib python -m rule_engine.debug_repl --edit-console
edit the 'context' and 'thing' objects as necessary
>>> thing = {'noargs': lambda: 'hello!', 'add': lambda a,b: a + b, 'greet': lambda name: 'Hello ' + name}
>>>
exiting the edit console...
rule > noargs()
result:
'hello!'
rule > add(1, 2)
result:
Decimal('3.0')
rule > greet('Spencer')
result:
'Hello Spencer'
rule >
The branch is feat/functions
if anyone is interested in previewing it.
Progress is slow and steady. Will probably be done in another 3 weeks. Maybe less, maybe more.
This ticket has now been completed.
Functions are included in the latest release, version 4.0.0. This release included a few breaking changes that are noted in the change log. There are 12 builtin functions that are available out of the box. I included functions from all of the tickets I'd marked as duplicates of this request since this it was opened about a year a half ago (sum
, parse_datetime
, etc.). I've written documentation that describes the syntax and how function types can be defined.
@zeroSteiner it's not clear from the documentation how/where to define a new custom function when the rule is to be applied to an object. Would you please provide an example of such a case or point me to where I can find one?
Also, this part of the documentation about FUNCTION is a bit confusing:
Additional functions can be either added them to the evaluated object or by extending the builtin symbols. It is only possible to call a function from within the rule text. Functions can not be defined as other data types can be.
I clarified that a bit in the documentation. For anyone else that comes across this in the future, you add a function just like you'd add any other value.
thing = {'name': 'Test Case', 'my_function': my_function}
Rule('my_function(name)').evaluate(thing)
Alternatively, you can expose it through changing the builtin symbols and access it with the $
prefix.
Was wondering if it's possible to implement custom functions to the rule engine, something of the sort of: