AllenNeuralDynamics / aind-behavior-curriculum

Starter repository for behavior base primitives.
https://aind-behavior-curriculum.readthedocs.io
MIT License
1 stars 0 forks source link

Creating parameters in a simple way #30

Open jeromelecoq opened 1 month ago

jeromelecoq commented 1 month ago

Just going through this with an eye for simplicity. https://github.com/AllenNeuralDynamics/aind-behavior-curriculum/blob/bb28161608b4544e5f71e23c2190a6682f17dcaf/examples/example_project/curriculum.py#L169

I appreciate it is important to validate parameters values against a schema but could external user just pass a dictionary instead of subclassing?

bruno-f-cruz commented 1 month ago

While I strongly disagree with this practice, if you really want to use dictionaries you can.


from typing import Literal, Dict

from pydantic import Field

from aind_behavior_curriculum import (
    Task,
    TaskParameters,
)

# --- TASKS ---
class TaskAParameters(TaskParameters):
    pass

class TaskA(Task):
    name: Literal["Task A"] = "Task A"
    task_parameters: TaskAParameters = Field(
        ..., description="Fill w/ Parameter Defaults", validate_default=True
    )

ThisIsADictionary: Dict[str, float] = {"field_a": 0, "field_b": 0.0}
Foo = TaskA(task_parameters=ThisIsADictionary)
print(Foo)
#name='Task A' description='' task_parameters=TaskAParameters(field_a=0, field_b=0.0)
print(Foo.task_parameters.model_dump()["field_a"])
#0
print(Foo.task_parameters.model_dump() == ThisIsADictionary)
#True
print(Foo.model_dump_json())
#{"name":"Task A","description":"","task_parameters":{"field_a":0,"field_b":0.0}}
print(TaskA.model_validate_json(Foo.model_dump_json()))
#name='Task A' description='' task_parameters=TaskAParameters(field_a=0, field_b=0.0)
jeromelecoq commented 1 month ago

Why do we need to do all those sub-classing? You could not just simply use existing classes?

jeromelecoq commented 1 month ago

An API like this : Foo = Task(task_parameters= {"field_a": 0, "field_b": 0.0})

Would be clear to me for example.

jeromelecoq commented 1 month ago

If you want to give a name to Task you could do : Foo = Task(name="TaskA", task_parameters= {"field_a": 0, "field_b": 0.0})

jeromelecoq commented 1 month ago

I think my concern perhaps comes down to expecting all users to know all of the inner workings of pydantic. Creating curriculum should be simple even if the inner validation are rich and precise.

bruno-f-cruz commented 1 month ago

You can do it, but then you have to deal with python's proclivity for lack of typing :P. I rather encourage people to do things a bit safer. Use at your own risk....

from typing import Literal, Dict

from pydantic import Field

from aind_behavior_curriculum import (
    Task)

ThisIsADictionary: Dict[str, float] = {"field_a": 0, "field_b": 0.0}
Foo = Task(name="IAmAnUnknownTask", task_parameters=ThisIsADictionary)
print(Foo)
#name='IAmAnUnknownTask' description='' task_parameters=TaskParameters(field_a=0, field_b=0.0)
print(Foo.task_parameters.model_dump()["field_a"])
#0
print(Foo.task_parameters.model_dump() == ThisIsADictionary)
#True
print(Foo.model_dump_json())
#{"name":"IAmAnUnknownTask","description":"","task_parameters":{"field_a":0,"field_b":0.0}}
print(Task.model_validate_json(Foo.model_dump_json()))
#name='IAmAnUnknownTask' description='' task_parameters=TaskParameters(field_a=0, field_b=0.0)
jeromelecoq commented 1 month ago

Ok. that's good.