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

Use a custom Enum class for improved speed #117

Closed
wants to merge 34 commits into from

Conversation

Gobot1234
Copy link
Collaborator

Significant speed improvements over the builtin Enum class.

  • 3x faster at creating instances of the enums.
  • Roughly 2x as fast at creating small (15 member) enums.
  • About 3x times faster at creating larger (50 member) enums.
  • About 7x times faster direct attribute access, then 9x faster for name/values.

Full tests here https://gist.github.com/Gobot1234/e3883e9db151ce3b33adf4d38c140936

Fixes a bug discussed on slack relating to to_dict and IndexErrors when using Enums.

@boukeversteegh
Copy link
Collaborator

Hi Gobot, thank you for your efforts.
For the bug, there is already an open pull request: #102

Copy link
Collaborator

@boukeversteegh boukeversteegh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for helping out.
As you know I'm not much convinced to the practical benefits of faster Enums.

If you could cover the new Enum class with unit tests, so it is clear what features are supported, I would be confident enough that it wouldn't break anything so that we can merge it nonetheless.

My two concerns are

  • extra mental load on maintainers and users who, in the course of encountering or fixing bugs (of which we have plenty still, also related to enums), will consider the Enum class as a potential root cause, and spend extra time going through and debugging the Enum code.
    We can avoid this by guaranteeing that our custom Enum implementation behaves 100% the same as the Python one. Full test coverage seems essential in my opinion.
  • Incompatibility with how users were applying betterproto Enums before. Again tests can rule this out to some extent. I did a quick search to see how SQL Alchemy uses Enums for example, but it turns out they don't natively support it, and the same goes for Django forms. Seems that Enum support is not widespread so that lowers concerns for compatibility with other libraries.

For tests, we can probably reuse most tests from the cpython:

https://github.com/python/cpython/blob/6a1e9c26736259413b060b01d1cb52fcf82c0385/Lib/test/test_enum.py#L140

betterproto/enums.py Outdated Show resolved Hide resolved
betterproto/enums.py Outdated Show resolved Hide resolved
@@ -776,7 +757,7 @@ def FromString(cls: Type[T], data: bytes) -> T:
return cls().parse(data)

def to_dict(
self, casing: Casing = Casing.CAMEL, include_default_values: bool = False
self, casing: Optional[Casing] = None, include_default_values: bool = False
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since Enums are not mutable, do we need this change? Or was passing a default not possible with the new class?

I think it was helpful for developers to see the default casing from the parameter.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately it raises an AttributeError as the class hasn't been created yet.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I guess we don't need to use Betterproto Enums for Casing. Perhaps just keep things simple and use the python Enum instead?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's that big of a deal, if someone wants to see the default they can just view source.

betterproto/__init__.py Outdated Show resolved Hide resolved
@Gobot1234
Copy link
Collaborator Author

Everything should now work

@Gobot1234
Copy link
Collaborator Author

This is a bad idea, making these consistent is too much of a pain, sticking with the current implementation is fine.

@Gobot1234 Gobot1234 closed this Jul 13, 2020
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