Skip to content

update Pydantic #115

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

Merged
merged 41 commits into from
Aug 1, 2023
Merged

Conversation

ImogenBits
Copy link
Collaborator

This PR makes us use the new pydantic version and then uses some of the new features to make defining problems much easier. No idea why some of the diffs are so massive when only a couple lines in the files changed, most of the changes in match.py and util.py aren't actually real.

There are two big changes: the first is that pydantic now uses rust internally, which gives us a speedup of about 20x (not 20%, 20x), though that's not super relevant since most of our runtime is spent in student code anyways. The other is that pydantic now uses much simpler ways to define validation properties. For example, if a problem instance contains a list of numbers that each should be bigger than 4 we can now do this:

class GeInstance(InstanceModel):
    numbers: list[Annotated[int, Ge(4)]]

the Annotated lets us add metadata to a type, in this case that it should be greater or equal to 4. You can also specify more complex logic like saying a dictionary should map english words to how often they are used:

def validate_english(value: str) -> str:
    if not is_english_word(value):
        raise ValueError("Value is not an english word")
    return value

word = Annotated[str, AfterValidator(validate_english)]

class WordInstance(InstanceModel):
    word_counts: dict[word, int]

This makes some stuff nicer, but not a whole lot in our use case since most of our custom validation logic is things like "should be less than the instance size" or "encodes an edge that is in the instance graph". For this I added some fairly complex logic that lets you specify references to model fields and which are then evaluated during validation. So the first case would simply be:

class SizeInstance(InstanceModel
      number: Annotated[int, Lt(InstanceRef.size)]

To make things even simpler I've compiled many common use cases into the algobattle.types module. For example, the solution to a graph automorphism problem encoded as a permutation of the vertices can now simply be defined as

class Automorphism(SolutionModel):
    permutation: Annotated[list[Vertex], UniqueItems, SizeLen]

and it will automatically be validated that every entry is a valid vertex, that none appear twice, and that every vertex is assigned an image. The only thing you have to manually validate is that the mapping preserves edges.

There's still a lot more cool stuff that can be added, but this should be a good start and make things nice enough.

@Benezivas
Copy link
Collaborator

This is a welcome addition, yet I suspect that most common users will not want to go so deep into writing their own typing classes to better formulate their problems. Still, having this option certainly does not hurt, thank you for the PR.

@Benezivas Benezivas merged commit 5682eab into Algorithmic-Battle:4.0.0-rc Aug 1, 2023
@ImogenBits ImogenBits deleted the pydanticv2 branch August 21, 2023 13:06
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.

2 participants