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

PyCharm gets confused about metaclass properties #159

Open
chrisimcevoy opened this issue Jun 4, 2024 · 2 comments
Open

PyCharm gets confused about metaclass properties #159

chrisimcevoy opened this issue Jun 4, 2024 · 2 comments

Comments

@chrisimcevoy
Copy link
Owner

chrisimcevoy commented Jun 4, 2024

While porting Pyoda Time, we need to port static properties from C#, which are properties which are accessed on the class rather than on an instance.

Because these static properties often return instances of the type they are declared on (example), I consistently implement these in Python as properties on a metaclass. Doing this also sidesteps troublesome circular imports by delaying them (example) because in Python we can't always refer to classes the way you might in C#.

However, this probably isn't a very common technique, and IDEs such as PyCharm don't seem to know about the property's return type (even if they know about the property's existence).

Take a simple example like this:

from pyoda_time import Duration, PyodaConstants

foo = PyodaConstants.UNIX_EPOCH + Duration.epsilon

If you were to over over the variable, you would expect the IDE to tell you the type of the variable. But it can't work out what that is.

image

(Note that mypy understands the type of the variable just fine - this is merely a UX thing / IDE issue)

This means that e.g. code completion don't work as you might like.

image

One thing we might do is to add type hints to the classes which use , for example:

--- a/pyoda_time/_pyoda_constants.py
+++ b/pyoda_time/_pyoda_constants.py
@@ -44,6 +44,11 @@ class _PyodaConstantsMeta(type):
 
 
 class PyodaConstants(metaclass=_PyodaConstantsMeta):
+    # Type hints for metaclass properties
+    UNIX_EPOCH: Instant
+    JULIAN_EPOCH: Instant
+    BCL_EPOCH: Instant
+
     HOURS_PER_DAY: Final[int] = 24
     DAYS_PER_WEEK: Final[int] = 7
     SECONDS_PER_MINUTE: Final[int] = 60

and:

--- a/pyoda_time/_duration.py
+++ b/pyoda_time/_duration.py
@@ -64,6 +64,14 @@ class _DurationMeta(type):
 class Duration(metaclass=_DurationMeta):
     """Represents a fixed (and calendar-independent) length of time."""
 
+    # Type hints for metaclass properties
+    zero: Duration
+    epsilon: Duration
+    max_value: Duration
+    min_value: Duration
+    one_week: Duration
+    one_day: Duration
+
     # Implementation note:
     #
     # Noda Time's `Duration` far exceeds the range of the equivalent BCL type, namely `TimeSpan`.

Doing so makes PyCharm aware of the variable type:

image

And makes code completion work again:

image

What doesn't work is in-IDE warnings about assignment to properties with no setter. But you can't have everything, and such assignments will still raise at runtime (if they aren't caught in mypy or other static type checker first).

@chrisimcevoy
Copy link
Owner Author

Uh-oh, this doesn't look right in sphinx docs...

image

@chrisimcevoy
Copy link
Owner Author

Warning for the above when you build html docs

WARNING: duplicate object description of pyoda_time.SystemClock.instance, other instance in pyoda_time, use :no-index: for one of them

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

No branches or pull requests

1 participant