0% found this document useful (0 votes)
7 views5 pages

Biocatch Pred

The document outlines an assignment to implement a Python module for parsing and evaluating predicates against Python objects, focusing on code quality and functionality. It specifies the structure of predicates, supported operations, feature extraction rules, and the required API for the Predicate class and a RemotePredicateResource class for fetching predicates from a web service. Additionally, it includes examples of usage and emphasizes the importance of performance, readability, and testability in the implementation.

Uploaded by

tendorlock
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
7 views5 pages

Biocatch Pred

The document outlines an assignment to implement a Python module for parsing and evaluating predicates against Python objects, focusing on code quality and functionality. It specifies the structure of predicates, supported operations, feature extraction rules, and the required API for the Predicate class and a RemotePredicateResource class for fetching predicates from a web service. Additionally, it includes examples of usage and emphasizes the importance of performance, readability, and testability in the implementation.

Uploaded by

tendorlock
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 5

Biocatch Practical Exercise: Predicates

Your assignment is to implement a python module that can accept and parse
predicates, and can then test these predicates against python objects.

Focus
For this assignment, focus on code quality as well as functionality. Your code
should be readable and easily extendible.
• Use type annotations on all functions
• You don’t need to add a docstring to every function, but it should be clear
from the function signature what each function is doing.
• Add comments to pieces of your code that you think aren’t self-explanatory.
• You don’t need to add tests, but your code should be easily testable.
• If you see something that should be done but you don’t have time to do,
you can add a #todo comment, explaining what needs to be done.
• Keep performance in mind. Don’t sacrifice readability for optimizations,
but your code should be efficient.
• If you use GenAI to help you implement this code, please add the
entire conversation you had with the AI to the files you submit!

Main Product
Implement a function that can parse a json string into a predicate. A predicate
always has one feature and one operation to test against it. A predicate will be
of the following format:

Predicate Format
A predicate will be of the format:
Predicate: {
"feature": <string>
"operation": <Operation>
}

Operation: {
"operator": <UnaryOperator>
}
OR {
"operator": <BinaryOperator>
"operand": Any
}
OR {
"operator": <GroupOperator>
"operations": list[<Operation>]

1
}

UnaryOperator: "isNone" | "isNotNone"


BinaryOperator: "eqTo" | "notEqualTo" | "isLessThan" | "isGreaterThan"
GroupOperator: "and" | "or"
An example predicate:
{
"feature": ".x.y.z",
"operation": {
"operator": "and",
"operations": [
{
"operator": "isNotNone"
},
{
"operator": "isGreaterThan",
"operand": 13
},
{
"operator": "isLessThan",
"operand": 45
}
]
}
}
This predicate checks that the attribute z of attribute y of attribute x of the
root is not None, is greater than 13 and is less than 45.

Supported Operations
Your module should support the following operators:
• isNone: Will return true if the feature is the singleton None.
• isNotNone: Will return true if the feature is not the singleton None.
• eqTo: Will return true if the feature is equal to the operand.
• notEqTo: Will return true if the feature is not equal to the operand.
• isLessThan: Will return true if the feature is strictly less than the operand.
• isGreaterThan: Will return true if the feature is strictly greater than the
operand.
• and: Will return true if all of the given operations return true for the
feature.
• or: Will return true if any of the given operations return true for the
feature.
If any operation raises an exception, a log should be sent, and the operation

2
should be treated as though it returned false.

Feature Extraction
A feature specification should always be of the form:
(.<attribute>)*
Where <attribute> is a non-empty combination of letters, digits, and underlines,
that does not begin with an underline or digit. Each attribute accessor operates on
the result of the previous accessor. The following are valid feature specifications:
• .x
• .x.y.z
• .a_b12_
• .x.z
• (an empty string, means to test the root directly)
If a feature does not exist, the predicate should fail (i.e. act as though its
operation returned False).
Implement a function that can test a predicate against a given object (called
the “root”). The function should fetch the value of the feature from the root
object, and return whether the predicate’s operation return true.
You should implement the following API:
class Predicate:
@classmethod
def from_json(cls, json_string: str)->Predicate:
...

def evaluate(self, root: object)->bool:


...

# Example usage:
from types import SimpleNamespace

j_str = '''{"feature": ".x.y", "operation": {"operator": "eqTo", "operand": 5}}'''

predicate = Predicate.from_json(j_str)

ns1 = SimpleNamespace(x=SimpleNamespace(y=5))
ns2 = SimpleNamespace(x=SimpleNamespace(y=3))
ns3 = SimpleNamespace(z=SimpleNamespace(y=5))

assert predicate.evaluate(ns1)
assert not predicate.evaluate(ns2)
assert not predicate.evaluate(ns3)

3
# Another Example

from dataclasses import dataclass

@dataclass
class User:
name: str
level: int

@dataclass
class Game:
user: User

g = Game(user=User(name="bob", level=6))

pred_str1 = '''{"feature": ".user.name",


"operation": {"operator": "eqTo", "operand": "bob"}}'''
pred1 = Predicate.from_json(pred_str1)

pred_str2 = '''{"feature": ".users.level",


"operation": {"operator": "isLessThan", "operand": 3.6}}'''
pred2 = Predicate.from_json(pred_str2)

assert pred1.evaluate(g) # pred1 returns true because the `user`


# has `name` equal to "bob"
assert not pred2.evaluate(g) # pred2 returns false because the `user`
# has `level` that is not less than 3.6

Bonus Goal: Continuous Resource


We now want the predicate to be fetched from the web, we should also be
prepared for the remote predicate to change over time, and we want stay to up-
to-date with the latest predicate, with up to a 2-minute delay. For this purpose,
we want to create a background asyncio task that will wait for 2 minutes and
update the predicate periodically. The predicate will be the response content of a
GET HTTP query to the endpoint {url}/api/v1/predicate where url is the
value of the environment variable PREDICATE_SERVICE_URL. If the environment
variable is missing, raise an exception.
Implement the following API:
class RemotePredicateResource:
@classmethod
async def from_env(cls) -> RemotePredicateResource:
...

4
@property
def predicate(self) -> Predicate:
...
Note that:
• The endpoint supports the Etag header in its response, as well as the
If-None-Match header in its requests.
• The HTTP request should be asynchronous (with async/await).

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy