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

Fix timezone aware datetimes backwards compatibility #72

Merged
merged 23 commits into from
Feb 4, 2025

Conversation

mraspaud
Copy link
Member

@mraspaud mraspaud commented Jan 29, 2025

This PR fixes some backwards incompatibility, in particular in the name server, so that replies are the same message version as the request.

Closes #71

@mraspaud mraspaud requested review from adybbroe and pnuu January 29, 2025 19:38
@mraspaud mraspaud self-assigned this Jan 29, 2025
@mraspaud mraspaud added the bug label Jan 29, 2025
@mraspaud mraspaud marked this pull request as ready for review January 30, 2025 09:53
Copy link
Contributor

@adybbroe adybbroe left a comment

Choose a reason for hiding this comment

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

Great work, nice refactoring also. And the tests help a lot understanding what is going on.
It seems to do what it shall - I have tested the nameserver in development at SMHI and seems like it supports both new and old (without timezone) messages - so indeed backward compatible. Will let it run over the night and see if it continues to behave well.

Would be good if someone else could review this PR also, as I have very little insight in this library.

Copy link

codecov bot commented Jan 31, 2025

Codecov Report

Attention: Patch coverage is 86.75958% with 38 lines in your changes missing coverage. Please review.

Project coverage is 89.42%. Comparing base (87962f3) to head (c032ad3).
Report is 39 commits behind head on main.

Files with missing lines Patch % Lines
posttroll/ns.py 39.21% 31 Missing ⚠️
posttroll/address_receiver.py 86.20% 4 Missing ⚠️
posttroll/backends/zmq/subscriber.py 50.00% 2 Missing ⚠️
posttroll/message_broadcaster.py 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #72      +/-   ##
==========================================
- Coverage   89.59%   89.42%   -0.18%     
==========================================
  Files          25       25              
  Lines        2278     2411     +133     
==========================================
+ Hits         2041     2156     +115     
- Misses        237      255      +18     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@mraspaud
Copy link
Member Author

mraspaud commented Feb 3, 2025

@pnuu I think this pr is finally ready for you review. It has grown much bigger than what I would have expected/wanted, but I found quite a few bugs that I couldn’t leave in the code. Hopefully the tests are now also more isolated/reliable, even there is still some work left in that domain.

Copy link
Member

@pnuu pnuu left a comment

Choose a reason for hiding this comment

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

In general I approve the changes. Some comments inline.

I'm really hopeless with type hinting, so I got confused about the foo:list[str] = [] syntax. The syntax in the function declarations seem to be different that I've seen in Satpy and in internet. Are the added type hints checked by mypy, and are they crucial where they are added? There are function declarations that were updated but the type hints were not added, and others where the hints are added only to some arguments but not all.

return config.get("address_publish_port", DEFAULT_ADDRESS_PUBLISH_PORT)


def get_local_ips():
"""Get local IP addresses."""
inet_addrs = [netifaces.ifaddresses(iface).get(netifaces.AF_INET)
for iface in netifaces.interfaces()]
ips = []
ips:list[str] = []
Copy link
Member

Choose a reason for hiding this comment

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

What does this do? I don't undersand the syntax.

Copy link
Member

Choose a reason for hiding this comment

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

Oh, a type hint. I think there should be a space: ips: list[str] = [] 🤔

Copy link
Member Author

Choose a reason for hiding this comment

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

addressed in 18b6c1a

@@ -204,7 +204,7 @@ def set_up_address_receiver(self, port):
"""Set up the address receiver depending on if it is multicast or not."""
nameservers = False
if self._multicast_enabled:
while True:
while True: # should this really be tried forever? wouldn't it be enough with 3?
Copy link
Member

Choose a reason for hiding this comment

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

I agree. If it keeps on failing, better fail so that it is visible.

Copy link
Member Author

Choose a reason for hiding this comment

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

addressed in 18b6c1a

@@ -15,39 +16,55 @@
nslock = Lock()


def zmq_get_pub_address(name, timeout=10, nameserver="localhost"):
def zmq_get_pub_address(name:str, timeout:float|int=10, nameserver:str="localhost"):
Copy link
Member

Choose a reason for hiding this comment

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

I'm not at all familiar with type hinting syntax, but this looks different to the examples I see on the net or in Satpy

  • whitespace between the variable and type name: str
  • whitespace between possible types and kwarg default values: timetout: float | int = 1

Copy link
Member Author

Choose a reason for hiding this comment

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

addressed in 18b6c1a

Comment on lines 85 to 86
self.running:bool = True
self.listener:SocketReceiver|None = None
Copy link
Member

Choose a reason for hiding this comment

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

Here the typehints should have spaces added for clarity.

Copy link
Member Author

Choose a reason for hiding this comment

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

addressed in 18b6c1a


def stop(self):
"""Stop the nameserver."""
return self._ns.stop()


def main():
Copy link
Member

Choose a reason for hiding this comment

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

Could the runnable script stay outside of the library? Or is there a benefit of moving it within?

Copy link
Member Author

Choose a reason for hiding this comment

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

yes, we can then have it as a script in pyproject.toml if it’s defined in the library

Copy link
Member

Choose a reason for hiding this comment

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

Right, so the scripts actually can't be outside of the package with pyproject.toml 🙈 I've liked to have them outside so that they don't affect the test coverage 😅

@mraspaud
Copy link
Member Author

mraspaud commented Feb 3, 2025

Regarding type hints: I got basedpyright running in my editor, and the posttroll code lit up like a Christmas tree. Hence my starting to fix a few of the issues. I then found out how to dim the lights a bit so that only the errors would show, and then I stopped adding type hints. I could remove them, but I thought it was a step in the right direction.

Comment on lines +235 to +250
Handling timezone-aware datetime objects
----------------------------------------

Timezone-aware datetime object were historically unsupported in posttroll, such as encoding or decoding them was
leading to problems. Recent versions of posttroll were fixed to address the problem, however message sent with these
versions are not backwards compatible. To ensure backwards compatibility, it is possible to configure posttroll to send
message that drop the timezone information on encoding. This can be done with an environment variable::

POSTTROLL_MESSAGE_VERSION=v1.01

or within python code::

>>> from posttroll import config
>>> with config.set(message_version="v1.01"):
...

Copy link
Member

Choose a reason for hiding this comment

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

Reading this it is possible to get the impression that also the datetimes within the message data could be affected. But as far as I've understood the code changes, it is actually only the header portion (the message creation time) that is affected and the times within the message data come from what ever created them.

Copy link
Member Author

Choose a reason for hiding this comment

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

No, the metadata is also affected. That’s actually how we noticed the problem in the first place, as an older version of posttroll was refusing to decode the start_time item of the metadata and was leaving it as a string.

Copy link
Member

Choose a reason for hiding this comment

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

Ok, got it. When receiving messages with tz aware datetimes, there's a problem decoding the messages. I didn't see this in my tests because the crash happened already with the message creation time.

So the processes earlier in the chain can't use tz aware datetimes within the message data unless the later parts have the fix. So the later parts will need the fix first, so they will already handle both aware and unaware datetimes. Nameserver only needs to understand the message creation time, as it doesn't need to actually parse the messages.

Did I get that right or did I miss something?

Copy link
Member Author

Choose a reason for hiding this comment

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

That’s correct. Nameserver messages don’t have any encoded time in their body (it’s just text iirc).

@mraspaud mraspaud merged commit 2fde7e5 into pytroll:main Feb 4, 2025
6 of 7 checks passed
@mraspaud mraspaud deleted the backwards_compat branch February 4, 2025 12:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants