From 5a9370dbecfd55f47f38554d4735133156b1a1b9 Mon Sep 17 00:00:00 2001 From: Edmilson Monteiro Rodrigues Neto Date: Thu, 19 Dec 2024 20:15:36 +0000 Subject: [PATCH 1/4] chore: remove pyrfc3339 and change to datetime.datetime.fromisoformat() and datetime.datetime.isoformat() --- juju/client/gocookies.py | 9 ++++----- juju/machine.py | 9 +++++---- juju/unit.py | 9 +++++---- juju/user.py | 5 ++--- tests/unit/test_gocookies.py | 8 +++++--- 5 files changed, 21 insertions(+), 19 deletions(-) diff --git a/juju/client/gocookies.py b/juju/client/gocookies.py index 0c33f0be..9997d47f 100644 --- a/juju/client/gocookies.py +++ b/juju/client/gocookies.py @@ -6,8 +6,6 @@ import json import time -import pyrfc3339 - class GoCookieJar(cookiejar.FileCookieJar): """A CookieJar implementation that reads and writes cookies @@ -52,7 +50,7 @@ def go_to_py_cookie(go_cookie): """Convert a Go-style JSON-unmarshaled cookie into a Python cookie""" expires = None if go_cookie.get("Expires") is not None: - t = pyrfc3339.parse(go_cookie["Expires"]) + t = datetime.datetime.fromisoformat(go_cookie["Expires"]) expires = t.timestamp() return cookiejar.Cookie( version=0, @@ -101,8 +99,9 @@ def py_to_go_cookie(py_cookie): if py_cookie.path_specified: go_cookie["Path"] = py_cookie.path if py_cookie.expires is not None: - unix_time = datetime.datetime.fromtimestamp(py_cookie.expires) # Note: fromtimestamp bizarrely produces a time without # a time zone, so we need to use accept_naive. - go_cookie["Expires"] = pyrfc3339.generate(unix_time, accept_naive=True) + go_cookie["Expires"] = datetime.datetime.fromtimestamp( + py_cookie.expires + ).isoformat() return go_cookie diff --git a/juju/machine.py b/juju/machine.py index 70b7327b..14e3ef9d 100644 --- a/juju/machine.py +++ b/juju/machine.py @@ -1,12 +1,11 @@ # Copyright 2023 Canonical Ltd. # Licensed under the Apache V2, see LICENCE file for details. +import datetime import ipaddress import logging import typing -import pyrfc3339 - from juju.utils import block_until, juju_ssh_key_paths from . import jasyncio, model, tag @@ -238,7 +237,7 @@ def agent_status(self): @property def agent_status_since(self): """Get the time when the `agent_status` was last updated.""" - return pyrfc3339.parse(self.safe_data["agent-status"]["since"]) + return datetime.datetime.fromisoformat(self.safe_data["agent-status"]["since"]) @property def agent_version(self): @@ -265,7 +264,9 @@ def status_message(self): @property def status_since(self): """Get the time when the `status` was last updated.""" - return pyrfc3339.parse(self.safe_data["instance-status"]["since"]) + return datetime.datetime.fromisoformat( + self.safe_data["instance-status"]["since"] + ) @property def dns_name(self): diff --git a/juju/unit.py b/juju/unit.py index 4cb8e259..e6e7d3f7 100644 --- a/juju/unit.py +++ b/juju/unit.py @@ -1,10 +1,9 @@ # Copyright 2023 Canonical Ltd. # Licensed under the Apache V2, see LICENCE file for details. +import datetime import logging -import pyrfc3339 - from juju.errors import JujuAPIError, JujuError from . import model, tag @@ -25,7 +24,7 @@ def agent_status(self): @property def agent_status_since(self): """Get the time when the `agent_status` was last updated.""" - return pyrfc3339.parse(self.safe_data["agent-status"]["since"]) + return datetime.datetime.fromisoformat(self.safe_data["agent-status"]["since"]) @property def is_subordinate(self): @@ -52,7 +51,9 @@ def workload_status(self): @property def workload_status_since(self): """Get the time when the `workload_status` was last updated.""" - return pyrfc3339.parse(self.safe_data["workload-status"]["since"]) + return datetime.datetime.fromisoformat( + self.safe_data["workload-status"]["since"] + ) @property def workload_status_message(self): diff --git a/juju/user.py b/juju/user.py index 7ff0fcc3..1f270932 100644 --- a/juju/user.py +++ b/juju/user.py @@ -1,10 +1,9 @@ # Copyright 2023 Canonical Ltd. # Licensed under the Apache V2, see LICENCE file for details. +import datetime import logging -import pyrfc3339 - from . import errors, tag from .client import client @@ -31,7 +30,7 @@ def display_name(self): @property def last_connection(self): - return pyrfc3339.parse(self._user_info.last_connection) + return datetime.datetime.fromisoformat(self._user_info.last_connection) @property def access(self): diff --git a/tests/unit/test_gocookies.py b/tests/unit/test_gocookies.py index 7f04f67f..c6e554c3 100644 --- a/tests/unit/test_gocookies.py +++ b/tests/unit/test_gocookies.py @@ -2,19 +2,19 @@ # Licensed under the Apache V2, see LICENCE file for details. """Tests for the gocookies code.""" +import datetime import os import shutil import tempfile import unittest import urllib.request -import pyrfc3339 - from juju.client.gocookies import GoCookieJar # cookie_content holds the JSON contents of a Go-produced # cookie file (reformatted so it's not all on one line but # otherwise unchanged). + cookie_content = """ [ { @@ -223,7 +223,9 @@ def test_expiry_time(self): ]""" jar = self.load_jar(content) got_expires = tuple(jar)[0].expires - want_expires = int(pyrfc3339.parse("2345-11-15T18:16:08Z").timestamp()) + want_expires = int( + datetime.datetime.fromisoformat("2345-11-15T18:16:08Z").timestamp() + ) self.assertEqual(got_expires, want_expires) def load_jar(self, content): From e69f6fa9c497bc179b2214f2ba428e97fbd18ade Mon Sep 17 00:00:00 2001 From: Edmilson Monteiro Rodrigues Neto Date: Sat, 21 Dec 2024 10:57:08 +0000 Subject: [PATCH 2/4] Added backports to tox.ini and pyproject.toml --- juju/__init__.py | 4 ++++ pyproject.toml | 2 +- tox.ini | 4 ++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/juju/__init__.py b/juju/__init__.py index 9da2b17a..742d5ace 100644 --- a/juju/__init__.py +++ b/juju/__init__.py @@ -1,3 +1,7 @@ # Copyright 2024 Canonical Ltd. # Licensed under the Apache V2, see LICENCE file for details. """Python Library for Juju.""" + +from backports.datetime_fromisoformat import MonkeyPatch + +MonkeyPatch.patch_fromisoformat() diff --git a/pyproject.toml b/pyproject.toml index b3c2d427..7a761c9b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,7 +23,6 @@ classifiers = [ ] dependencies = [ "macaroonbakery>=1.1,<2.0", - "pyRFC3339>=1.0,<2.0", "pyyaml>=5.1.2", "websockets>=13.0.1", "paramiko>=2.4.0", @@ -35,6 +34,7 @@ dependencies = [ "packaging", "typing-extensions>=4.5.0", 'backports.strenum>=1.3.1; python_version < "3.11"', + "backports-datetime-fromisoformat>=2.0.2", ] [project.optional-dependencies] dev = [ diff --git a/tox.ini b/tox.ini index d284673b..c9b8f975 100644 --- a/tox.ini +++ b/tox.ini @@ -50,6 +50,10 @@ commands = [testenv:unit] envdir = {toxworkdir}/py3 +deps = + backports-datetime-fromisoformat +allowlist_externals = + pytest commands = pytest {toxinidir}/tests/unit {posargs} From 633bbd49e24bfbb2cb03ee542a320d6b7fbb4942 Mon Sep 17 00:00:00 2001 From: Edmilson Monteiro Rodrigues Neto Date: Sat, 21 Dec 2024 11:09:40 +0000 Subject: [PATCH 3/4] chore: change setup.py to use backports instead of pyrfc --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 93825375..9ec14ccc 100644 --- a/setup.py +++ b/setup.py @@ -21,7 +21,6 @@ package_data={"juju": ["py.typed"]}, install_requires=[ "macaroonbakery>=1.1,<2.0", - "pyRFC3339>=1.0,<2.0", "pyyaml>=5.1.2", "websockets>=13.0.1", "paramiko>=2.4.0", @@ -33,6 +32,7 @@ "packaging", "typing-extensions>=4.5.0", 'backports.strenum>=1.3.1; python_version < "3.11"', + "backports-datetime-fromisoformat>=2.0.2", ], extras_require={ "dev": [ From bc0ade29d328c7a099dd7cbd5d16ef48946bb038 Mon Sep 17 00:00:00 2001 From: Edmilson Monteiro Rodrigues Neto Date: Sat, 21 Dec 2024 11:43:41 +0000 Subject: [PATCH 4/4] lint: ruff --- juju/__init__.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/juju/__init__.py b/juju/__init__.py index 742d5ace..15a0b1c6 100644 --- a/juju/__init__.py +++ b/juju/__init__.py @@ -2,6 +2,9 @@ # Licensed under the Apache V2, see LICENCE file for details. """Python Library for Juju.""" -from backports.datetime_fromisoformat import MonkeyPatch +try: + from backports.datetime_fromisoformat import MonkeyPatch -MonkeyPatch.patch_fromisoformat() + MonkeyPatch.patch_fromisoformat() +except ImportError: + pass