From 2748859e848e56c7f8714bb23dae7316c727e754 Mon Sep 17 00:00:00 2001 From: Facundo Batista Date: Thu, 18 Jul 2024 13:01:38 -0300 Subject: [PATCH 1/2] Update different details now we support Py>-3.6 only --- fades/__init__.py | 6 +----- fades/envbuilder.py | 6 +++--- fades/helpers.py | 10 +++++----- tests/conftest.py | 15 ++++----------- tests/test_envbuilder.py | 12 ++++++------ tests/test_helpers.py | 15 +++++++-------- 6 files changed, 26 insertions(+), 38 deletions(-) diff --git a/fades/__init__.py b/fades/__init__.py index 6f8de4f..eac8906 100644 --- a/fades/__init__.py +++ b/fades/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2015-2016 Facundo Batista, Nicolás Demarchi +# Copyright 2015-2024 Facundo Batista, Nicolás Demarchi # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General @@ -26,7 +26,3 @@ class FadesError(Exception): REPO_PYPI = 'pypi' REPO_VCS = 'vcs' - -# Not using http.server.HTTPStatus to support python < 3.5 -HTTP_STATUS_NOT_FOUND = 404 -HTTP_STATUS_OK = 200 diff --git a/fades/envbuilder.py b/fades/envbuilder.py index 362531e..1914249 100644 --- a/fades/envbuilder.py +++ b/fades/envbuilder.py @@ -21,7 +21,7 @@ import pathlib import shutil -from datetime import datetime +from datetime import datetime, UTC from venv import EnvBuilder from uuid import uuid4 @@ -199,7 +199,7 @@ def _create_initial_usage_file_if_not_exists(self): def _write_venv_usage(self, file_, venv_data): _, uuid = os.path.split(venv_data['env_path']) - file_.write('{} {}\n'.format(uuid, self._datetime_to_str(datetime.utcnow()))) + file_.write('{} {}\n'.format(uuid, self._datetime_to_str(datetime.now(UTC)))) def _datetime_to_str(self, datetime_): return datetime.strftime(datetime_, "%Y-%m-%dT%H:%M:%S.%f") @@ -219,7 +219,7 @@ def clean_unused_venvs(self, max_days_to_keep): called, this records will be deleted. """ with filelock(self.stat_file_lock): - now = datetime.utcnow() + now = datetime.now(UTC) venvs_dict = self._get_compacted_dict_usage_from_file() for venv_uuid, usage_date in venvs_dict.copy().items(): usage_date = self._str_to_datetime(usage_date) diff --git a/fades/helpers.py b/fades/helpers.py index 8296c28..47fb5e7 100644 --- a/fades/helpers.py +++ b/fades/helpers.py @@ -22,13 +22,14 @@ import logging import subprocess import tempfile +from http.server import HTTPStatus from urllib import request, parse from urllib.error import HTTPError from packaging.requirements import Requirement from packaging.version import Version -from fades import FadesError, HTTP_STATUS_NOT_FOUND, HTTP_STATUS_OK, _version +from fades import FadesError, _version logger = logging.getLogger(__name__) @@ -227,20 +228,19 @@ def _pypi_head_package(dependency): try: response = request.urlopen(req) except HTTPError as http_error: - if http_error.code == HTTP_STATUS_NOT_FOUND: + if http_error.code == HTTPStatus.NOT_FOUND: return False else: raise - if response.status == HTTP_STATUS_OK: + if response.status == HTTPStatus.OK: logger.debug("%r exists in PyPI.", dependency) - return True else: # Maybe we are getting somethink like a redirect. In this case we are only # warning to the user and trying to install the dependency. # In the worst scenery fades will fail to install it. logger.warning("Got a (unexpected) HTTP_STATUS=%r and reason=%r checking if %r exists", response.status, response.reason, dependency) - return True + return True def check_pypi_exists(dependencies): diff --git a/tests/conftest.py b/tests/conftest.py index d8e9981..e35a675 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -14,29 +14,23 @@ # # For further info, check https://github.com/PyAr/fades -import shutil import uuid from pytest import fixture @fixture(scope="function") -def tmp_file(tmpdir_factory): +def tmp_file(tmp_path): """Fixture for a unique tmpfile for each test.""" - dir_path = tmpdir_factory.mktemp("test") - yield str(dir_path.join("testfile")) # Converted to str to support python <3.6 versions - shutil.rmtree(str(dir_path)) + yield str(tmp_path / "testfile") # XXX Facundo 2024-04-17: remove str() after #435 @fixture(scope="function") -def create_tmpfile(tmpdir_factory): - dir_path = tmpdir_factory.mktemp("test") +def create_tmpfile(tmp_path): def add_content(lines): """Fixture for a unique tmpfile for each test.""" - namefile = str( - dir_path.join("testfile_{}".format(uuid.uuid4())) - ) # Converted to str to support python <3.6 versions + namefile = tmp_path / f"testfile_{uuid.uuid4()}" with open(namefile, "w", encoding="utf-8") as f: for line in lines: f.write(line + "\n") @@ -44,7 +38,6 @@ def add_content(lines): return namefile yield add_content - shutil.rmtree(str(dir_path)) def pytest_addoption(parser): diff --git a/tests/test_envbuilder.py b/tests/test_envbuilder.py index 0aa64a6..10e597d 100644 --- a/tests/test_envbuilder.py +++ b/tests/test_envbuilder.py @@ -296,11 +296,11 @@ def test_usage_record_is_recorded(self): msg="Selected uuid is two times in file") def test_usage_file_is_compacted_when_though_no_venv_is_removed(self): - old_date = datetime.utcnow() + old_date = datetime.now() new_date = old_date + timedelta(days=1) with patch('fades.envbuilder.datetime') as mock_datetime: - mock_datetime.utcnow.return_value = old_date + mock_datetime.now.return_value = old_date mock_datetime.strptime.side_effect = lambda *args, **kw: datetime.strptime(*args, **kw) mock_datetime.strftime.side_effect = lambda *args, **kw: datetime.strftime(*args, **kw) @@ -312,7 +312,7 @@ def test_usage_file_is_compacted_when_though_no_venv_is_removed(self): venv = self.venvscache.get_venv(uuid=self.uuids[0]) manager.store_usage_stat(venv, self.venvscache) - mock_datetime.utcnow.return_value = new_date + mock_datetime.now.return_value = new_date manager.store_usage_stat(venv, self.venvscache) lines = self.get_usage_lines(manager) @@ -351,11 +351,11 @@ def test_general_error_exception(self): self.assertEqual(str(cm.exception), "General error while running external venv") def test_when_a_venv_is_removed_it_is_removed_from_everywhere(self): - old_date = datetime.utcnow() + old_date = datetime.now() new_date = old_date + timedelta(days=5) with patch('fades.envbuilder.datetime') as mock_datetime: - mock_datetime.utcnow.return_value = old_date + mock_datetime.now.return_value = old_date mock_datetime.strptime.side_effect = lambda *args, **kw: datetime.strptime(*args, **kw) mock_datetime.strftime.side_effect = lambda *args, **kw: datetime.strftime(*args, **kw) @@ -367,7 +367,7 @@ def test_when_a_venv_is_removed_it_is_removed_from_everywhere(self): venv = self.venvscache.get_venv(uuid=self.uuids[0]) manager.store_usage_stat(venv, self.venvscache) - mock_datetime.utcnow.return_value = new_date + mock_datetime.now.return_value = new_date manager.store_usage_stat(venv, self.venvscache) lines = self.get_usage_lines(manager) diff --git a/tests/test_helpers.py b/tests/test_helpers.py index caf895c..3d262ff 100644 --- a/tests/test_helpers.py +++ b/tests/test_helpers.py @@ -22,7 +22,7 @@ import sys import tempfile import unittest - +from http.server import HTTPStatus from unittest.mock import patch from urllib.error import HTTPError from urllib.request import Request @@ -31,8 +31,7 @@ import pytest from xdg import BaseDirectory -from fades import HTTP_STATUS_NOT_FOUND, HTTP_STATUS_OK, helpers -from fades import parsing +from fades import helpers, parsing PATH_TO_EXAMPLES = "tests/examples/" @@ -307,7 +306,7 @@ def test_exists(self): with patch('urllib.request.urlopen') as mock_urlopen: with patch('http.client.HTTPResponse') as mock_http_response: - mock_http_response.status = HTTP_STATUS_OK + mock_http_response.status = HTTPStatus.OK mock_urlopen.return_value = mock_http_response exists = helpers.check_pypi_exists(deps) @@ -319,7 +318,7 @@ def test_all_exists(self): with patch('urllib.request.urlopen') as mock_urlopen: with patch('http.client.HTTPResponse') as mock_http_response: - mock_http_response.status = HTTP_STATUS_OK + mock_http_response.status = HTTPStatus.OK mock_urlopen.side_effect = [mock_http_response] * 3 exists = helpers.check_pypi_exists(dependencies) @@ -330,7 +329,7 @@ def test_doesnt_exists(self): dependency = parsing.parse_manual(["foo"]) with patch('urllib.request.urlopen') as mock_urlopen: - mock_http_error = HTTPError("url", HTTP_STATUS_NOT_FOUND, "mgs", {}, io.BytesIO()) + mock_http_error = HTTPError("url", HTTPStatus.NOT_FOUND, "mgs", {}, io.BytesIO()) mock_urlopen.side_effect = mock_http_error exists = helpers.check_pypi_exists(dependency) @@ -343,8 +342,8 @@ def test_one_doesnt_exists(self): with patch('urllib.request.urlopen') as mock_urlopen: with patch('http.client.HTTPResponse') as mock_http_response: - mock_http_error = HTTPError("url", HTTP_STATUS_NOT_FOUND, "mgs", {}, io.BytesIO()) - mock_http_response.status = HTTP_STATUS_OK + mock_http_error = HTTPError("url", HTTPStatus.NOT_FOUND, "mgs", {}, io.BytesIO()) + mock_http_response.status = HTTPStatus.OK mock_urlopen.side_effect = [mock_http_response, mock_http_error] exists = helpers.check_pypi_exists(dependencies) From 0ed44abbe6e6b7f41ed40a9904577b22a5a5e904 Mon Sep 17 00:00:00 2001 From: Facundo Batista Date: Thu, 18 Jul 2024 13:08:42 -0300 Subject: [PATCH 2/2] Support for utc in Py<3.11 --- fades/envbuilder.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fades/envbuilder.py b/fades/envbuilder.py index 1914249..2b68618 100644 --- a/fades/envbuilder.py +++ b/fades/envbuilder.py @@ -21,7 +21,7 @@ import pathlib import shutil -from datetime import datetime, UTC +from datetime import datetime, timezone from venv import EnvBuilder from uuid import uuid4 @@ -32,6 +32,9 @@ logger = logging.getLogger(__name__) +# UTC can be imported directly from datetime from Python 3.11 +UTC = timezone.utc + class _FadesEnvBuilder(EnvBuilder): """Create always a virtual environment.