From de576903900eedc3195065a70f256a0eb5c3f7fb Mon Sep 17 00:00:00 2001 From: Francis Charette Migneault Date: Fri, 11 Oct 2024 20:33:06 -0400 Subject: [PATCH 1/2] fix typings + drop python 3.8 + pin deps for securit vulnerability fixes --- .github/workflows/tests.yml | 2 +- CHANGES.rst | 5 ++++- cowbird/monitoring/monitor.py | 35 ++++++++++++++++++----------------- cowbird/utils.py | 9 +++++++++ requirements-sys.txt | 2 +- requirements.txt | 4 ++-- setup.py | 4 ++-- 7 files changed, 37 insertions(+), 24 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index aa581661..ac3b0264 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -33,7 +33,7 @@ jobs: strategy: matrix: os: [ubuntu-latest] - python-version: ["3.8", "3.9", "3.10", "3.11"] + python-version: ["3.9", "3.10", "3.11", "3.12"] allow-failure: [false] test-case: [test-only] # add other test variations to run for every python/os/failure combinations # tests with single run diff --git a/CHANGES.rst b/CHANGES.rst index 09d0bc54..0e9ffa48 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -7,7 +7,10 @@ Changes `Unreleased `_ (latest) ------------------------------------------------------------------------------------ -* Nothing yet. +* Drop Python 3.8 support. +* Pin ``watchdog>=5`` to employ typing fixes. +* Pin ``requests>=2.32.3`` to fix security vulnerability. +* Pin ``setuptools>=70.0.0`` to fix security vulnerability. `2.4.0 `_ (2024-07-09) ------------------------------------------------------------------------------------ diff --git a/cowbird/monitoring/monitor.py b/cowbird/monitoring/monitor.py index 5b941662..ee6c1e3f 100644 --- a/cowbird/monitoring/monitor.py +++ b/cowbird/monitoring/monitor.py @@ -17,7 +17,7 @@ from watchdog.observers.api import BaseObserver from cowbird.monitoring.fsmonitor import FSMonitor -from cowbird.utils import get_logger +from cowbird.utils import bytes2str, get_logger LOGGER = get_logger(__name__) @@ -153,11 +153,11 @@ def start(self) -> None: LOGGER.error(msg) raise MonitorException(msg) self.__event_observer = Observer() - self.__event_observer.schedule(self, # type: ignore[no-untyped-call] + self.__event_observer.schedule(self, self.__src_path, recursive=self.__recursive) try: - self.__event_observer.start() # type: ignore[no-untyped-call] + self.__event_observer.start() except OSError: LOGGER.warning("Cannot monitor the following file or directory [%s]: No such file or directory", self.__src_path) @@ -166,46 +166,47 @@ def stop(self) -> None: """ Stop the monitoring so that events stop to be fired. """ - self.__event_observer.stop() # type: ignore[no-untyped-call] + self.__event_observer.stop() self.__event_observer.join() self.__event_observer = None - def on_moved(self, event: Union[DirMovedEvent, FileMovedEvent]) -> None: # type: ignore[override] + def on_moved(self, event: Union[DirMovedEvent, FileMovedEvent]) -> None: """ Called when a file or a directory is moved or renamed. :param event: Event representing file/directory movement. """ - self.__callback.on_deleted(event.src_path) + event_dest_path = bytes2str(event.dest_path) + event_src_path = bytes2str(event.src_path) + self_src_path = bytes2str(self.__src_path) + self.__callback.on_deleted(event_src_path) # If moved outside of __src_path don't send a create event - if event.dest_path.startswith(self.__src_path): + if event_dest_path.startswith(self_src_path): # If move under subdirectory and recursive is False don't send a # create event neither - if self.__recursive or \ - os.path.dirname(event.dest_path) == \ - os.path.dirname(self.__src_path): - self.__callback.on_created(event.dest_path) + if self.__recursive or os.path.dirname(event_dest_path) == os.path.dirname(self_src_path): + self.__callback.on_created(event_dest_path) - def on_created(self, event: Union[DirCreatedEvent, FileCreatedEvent]) -> None: # type: ignore[override] + def on_created(self, event: Union[DirCreatedEvent, FileCreatedEvent]) -> None: """ Called when a file or directory is created. :param event: Event representing file/directory creation. """ - self.__callback.on_created(event.src_path) + self.__callback.on_created(bytes2str(event.src_path)) - def on_deleted(self, event: Union[DirDeletedEvent, FileDeletedEvent]) -> None: # type: ignore[override] + def on_deleted(self, event: Union[DirDeletedEvent, FileDeletedEvent]) -> None: """ Called when a file or directory is deleted. :param event: Event representing file/directory deletion. """ - self.__callback.on_deleted(event.src_path) + self.__callback.on_deleted(bytes2str(event.src_path)) - def on_modified(self, event: Union[DirModifiedEvent, FileModifiedEvent]) -> None: # type: ignore[override] + def on_modified(self, event: Union[DirModifiedEvent, FileModifiedEvent]) -> None: """ Called when a file or directory is modified. :param event: Event representing file/directory modification. """ - self.__callback.on_modified(event.src_path) + self.__callback.on_modified(bytes2str(event.src_path)) diff --git a/cowbird/utils.py b/cowbird/utils.py index 1ae69b38..a2ab0b19 100644 --- a/cowbird/utils.py +++ b/cowbird/utils.py @@ -169,6 +169,15 @@ def bool2str(value: Any) -> str: return "true" if str(value).lower() in truthy else "false" +def bytes2str(string: str | bytes) -> str: + """ + Ensures a string is represented in UTF-8. + """ + if isinstance(string, bytes): + return string.decode("utf-8") + return string + + def islambda(func: Any) -> bool: """ Evaluate if argument is a callable :class:`lambda` expression. diff --git a/requirements-sys.txt b/requirements-sys.txt index dacb35d6..190802fc 100644 --- a/requirements-sys.txt +++ b/requirements-sys.txt @@ -2,4 +2,4 @@ packaging pip>=22.0 -setuptools>=65.5.1 +setuptools>=70.0.0 diff --git a/requirements.txt b/requirements.txt index 87856833..16f715b3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -16,13 +16,13 @@ pyramid_mako>=1.0.2 pyramid_celery @ git+https://github.com/crim-ca/pyramid_celery.git@5.0.0a python-dotenv pyyaml>=5.1 -requests +requests>=2.32.3 requests_file schema simplejson threddsclient==0.4.6 typing_extensions urllib3>=2.2.2 -watchdog>=4 +watchdog>=5 webob zipp>=3.19.1 # not directly required, pinned by Snyk to avoid a vulnerability diff --git a/setup.py b/setup.py index 7a82368c..73d77700 100644 --- a/setup.py +++ b/setup.py @@ -203,12 +203,12 @@ def _extra_requirements(base_requirements: Iterable[str], other_requirements: It "Natural Language :: English", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", ], - python_requires=">=3.8, <4", + python_requires=">=3.9, <4", # -- Package structure ------------------------------------------------- packages=[__meta__.__package__], From 63bab546da12c18a70219e49393575bea145c87c Mon Sep 17 00:00:00 2001 From: Francis Charette Migneault Date: Fri, 11 Oct 2024 20:37:14 -0400 Subject: [PATCH 2/2] backward compat union typing for python 3.9 --- cowbird/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cowbird/utils.py b/cowbird/utils.py index a2ab0b19..9439d435 100644 --- a/cowbird/utils.py +++ b/cowbird/utils.py @@ -169,7 +169,7 @@ def bool2str(value: Any) -> str: return "true" if str(value).lower() in truthy else "false" -def bytes2str(string: str | bytes) -> str: +def bytes2str(string: Union[str, bytes]) -> str: """ Ensures a string is represented in UTF-8. """