Skip to content

Commit

Permalink
chore: adding a warning message about Python 3.8
Browse files Browse the repository at this point in the history
  • Loading branch information
Severine Bonnechere committed Nov 25, 2024
1 parent b82d7ca commit 00ac1d0
Show file tree
Hide file tree
Showing 7 changed files with 112 additions and 21 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,9 @@ documentation.

`ggshield` works on macOS, Linux and Windows.

It requires **Python 3.8 and newer** (except for standalone packages) and git.
It requires **Python 3.8 or above** (except for standalone packages) and git.

:warning: Python 3.8 is no longer supported by the Python Software Foundation since October, 14th 2024. GGShield will soon require Python 3.9 or above to run.

Some commands require additional programs:

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<!--
A new scriv changelog fragment.
Uncomment the section that is right (remove the HTML comment wrapper).
-->

<!--
### Removed
- A bullet item for the Removed category.
-->
<!--
### Added
- A bullet item for the Added category.
-->

### Changed

Warning message: Python 3.8 is no longer supported by the Python Software Foundation since October, 14th 2024. GGShield will soon require Python 3.9 or above to run.

<!--
### Deprecated
- A bullet item for the Deprecated category.
-->
<!--
### Fixed
- A bullet item for the Fixed category.
-->
<!--
### Security
- A bullet item for the Security category.
-->
12 changes: 9 additions & 3 deletions ggshield/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from ggshield.cmd.utils.common_options import add_common_options
from ggshield.cmd.utils.context_obj import ContextObj
from ggshield.cmd.utils.debug import setup_debug_mode
from ggshield.cmd.utils.output_format import OutputFormat
from ggshield.core import check_updates, ui
from ggshield.core.cache import Cache
from ggshield.core.config import Config
Expand Down Expand Up @@ -138,9 +139,14 @@ def _set_color(ctx: click.Context):
ctx.color = True


def _display_deprecation_message(cfg: Config) -> None:
for message in cfg.user_config.deprecation_messages:
def _display_deprecation_message(ctx: click.Context) -> None:
for message in ctx.config.user_config.deprecation_messages:
ui.display_warning(message)
if sys.version_info < (3, 9) and ctx.output_format is OutputFormat.TEXT:
ui.display_warning(
"Python 3.8 is no longer supported by the Python Software Foundation. "
"GGShield will soon require Python 3.9 or above to run."
)


def _check_for_updates(check_for_updates: bool) -> None:
Expand All @@ -165,7 +171,7 @@ def before_exit(ctx: click.Context, exit_code: int, *args: Any, **kwargs: Any) -
The argument exit_code is the result of the previously executed click command.
"""
ctx_obj = ContextObj.get(ctx)
_display_deprecation_message(ctx_obj.config)
_display_deprecation_message(ctx_obj)
_check_for_updates(ctx_obj.check_for_updates)
sys.exit(exit_code)

Expand Down
19 changes: 18 additions & 1 deletion tests/unit/cmd/auth/test_login.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import json
import sys
import urllib.parse as urlparse
from datetime import datetime, timedelta, timezone
from enum import IntEnum, auto
Expand Down Expand Up @@ -562,6 +563,12 @@ def test_valid_process(
'You do not need to run "ggshield auth login" again. Future requests will automatically use the token.\n'
)

if sys.version_info < (3, 9):
message += (
"Warning: Python 3.8 is no longer supported by the Python Software Foundation. "
"GGShield will soon require Python 3.9 or above to run.\n"
)

assert output.endswith(message)

self._assert_config("mysupertoken")
Expand Down Expand Up @@ -758,7 +765,12 @@ def _assert_last_print(output: str, expected_str: str):
"""
assert that the last log output is the same as the one passed in param
"""
assert output.rsplit("\n", 2)[-2] == expected_str
if sys.version_info < (3, 9):
expected_str += (
"\nWarning: Python 3.8 is no longer supported by the Python Software Foundation. "
"GGShield will soon require Python 3.9 or above to run.\n"
)
assert output.endswith(expected_str)

def _assert_open_url(
self,
Expand Down Expand Up @@ -887,6 +899,11 @@ def test_bad_sso_url(
exit_code, output = self.run_cmd(cli_fs_runner, method=method)
assert exit_code > 0, output
self._webbrowser_open_mock.assert_not_called()
if sys.version_info < (3, 9):
expected_error += (
"Warning: Python 3.8 is no longer supported by the Python Software Foundation. "
"GGShield will soon require Python 3.9 or above to run.\n"
)
self._assert_last_print(output, expected_error)

@pytest.mark.parametrize(
Expand Down
7 changes: 7 additions & 0 deletions tests/unit/cmd/auth/test_logout.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import sys
from typing import Optional, Tuple
from unittest.mock import Mock

Expand Down Expand Up @@ -81,6 +82,12 @@ def test_valid_logout(self, revoke, instance_url, monkeypatch, cli_fs_runner):
"from your configuration.\n"
)

if sys.version_info < (3, 9):
expected_output += (
"Warning: Python 3.8 is no longer supported by the Python Software Foundation. "
"GGShield will soon require Python 3.9 or above to run.\n"
)

assert output == expected_output

def test_logout_revoke_timeout(self, monkeypatch, cli_fs_runner):
Expand Down
10 changes: 9 additions & 1 deletion tests/unit/cmd/scan/test_docker.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import json
import sys
from pathlib import Path
from unittest.mock import Mock, patch

Expand Down Expand Up @@ -75,7 +76,14 @@ def test_docker_scan_abort(
["-v", "secret", "scan", "docker", "ggshield-non-existant"],
)
assert_invoke_ok(result)
assert result.output == ""

expected_output = ""
if sys.version_info < (3, 9):
expected_output += (
"Warning: Python 3.8 is no longer supported by the Python Software Foundation. "
"GGShield will soon require Python 3.9 or above to run.\n"
)
assert result.output == expected_output

@patch("ggshield.cmd.secret.scan.docker.docker_save_to_tmp")
@patch("ggshield.cmd.secret.scan.docker.docker_scan_archive")
Expand Down
40 changes: 25 additions & 15 deletions tests/unit/cmd/test_config.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import json
import sys
from datetime import datetime, timezone
from typing import Tuple

Expand Down Expand Up @@ -49,6 +50,15 @@
"""


def _check_expected_output(output: str, expected_output: str):
if sys.version_info < (3, 9) and "Error:" not in expected_output:
expected_output += (
"Warning: Python 3.8 is no longer supported by the Python Software Foundation. "
"GGShield will soon require Python 3.9 or above to run.\n"
)
assert output == expected_output


class TestConfigList:

@pytest.fixture
Expand Down Expand Up @@ -80,7 +90,7 @@ def test_valid_list(self, cli_fs_runner, setup_configs):
exit_code, output = self.run_cmd(cli_fs_runner)

assert exit_code == ExitCode.SUCCESS, output
assert output == EXPECTED_OUTPUT
_check_expected_output(output, EXPECTED_OUTPUT)

def test_list_json_output(
self, cli_fs_runner, config_list_json_schema, setup_configs
Expand All @@ -91,7 +101,6 @@ def test_list_json_output(
THEN all configs should be listed with the correct format
"""
exit_code_json, output_json = self.run_cmd(cli_fs_runner, json=True)

assert exit_code_json == ExitCode.SUCCESS, output_json
dct = json.loads(output_json)
jsonschema.validate(dct, config_list_json_schema)
Expand Down Expand Up @@ -149,7 +158,7 @@ def test_set_lifetime_default_config_value(self, value, cli_fs_runner):
), "The instance config should remain unchanged"

assert exit_code == ExitCode.SUCCESS, output
assert output == ""
_check_expected_output(output, "")

@pytest.mark.parametrize("value", [0, 365])
def test_set_lifetime_instance_config_value(self, value, cli_fs_runner):
Expand Down Expand Up @@ -185,7 +194,7 @@ def test_set_lifetime_instance_config_value(self, value, cli_fs_runner):
), "The default auth config should remain unchanged"

assert exit_code == ExitCode.SUCCESS, output
assert output == ""
_check_expected_output(output, "")

def test_set_invalid_field_name(self, cli_fs_runner):
"""
Expand Down Expand Up @@ -236,8 +245,8 @@ def test_set_lifetime_invalid_instance(self, cli_fs_runner):

exit_code, output = self.run_cmd(cli_fs_runner, 0, instance_url=instance_url)

assert exit_code == ExitCode.AUTHENTICATION_ERROR, output
assert output == f"Error: Unknown instance: '{instance_url}'\n"
assert exit_code == ExitCode.AUTHENTICATION_ERROR
_check_expected_output(output, f"Error: Unknown instance: '{instance_url}'\n")

config = Config()
assert (
Expand Down Expand Up @@ -322,7 +331,7 @@ def test_unset_lifetime_instance_config_value(self, cli_fs_runner):
), "The default auth config should remain unchanged"

assert exit_code == ExitCode.SUCCESS, output
assert output == ""
_check_expected_output(output, "")

def test_unset_lifetime_default_config_value(self, cli_fs_runner):
"""
Expand All @@ -343,7 +352,7 @@ def test_unset_lifetime_default_config_value(self, cli_fs_runner):
), "Unrelated instance config should remain unchanged"

assert exit_code == ExitCode.SUCCESS, output
assert output == ""
_check_expected_output(output, "")

def test_unset_lifetime_all(self, cli_fs_runner):
"""
Expand All @@ -370,7 +379,7 @@ def test_unset_lifetime_all(self, cli_fs_runner):
assert config.auth_config.default_token_lifetime is None, output

assert exit_code == ExitCode.SUCCESS, output
assert output == ""
_check_expected_output(output, "")

def test_unset_lifetime_invalid_instance(self, cli_fs_runner):
"""
Expand All @@ -386,7 +395,7 @@ def test_unset_lifetime_invalid_instance(self, cli_fs_runner):
exit_code, output = self.run_cmd(cli_fs_runner, instance_url=instance_url)

assert exit_code == ExitCode.AUTHENTICATION_ERROR, output
assert output == f"Error: Unknown instance: '{instance_url}'\n"
_check_expected_output(output, f"Error: Unknown instance: '{instance_url}'\n")

config = Config()
assert (
Expand All @@ -409,7 +418,7 @@ def test_unset_instance(self, cli_fs_runner):
exit_code, output = self.run_cmd(cli_fs_runner, param="instance")

assert exit_code == ExitCode.SUCCESS, output
assert output == ""
_check_expected_output(output, "")

config, _ = UserConfig.load(config_path)
assert config.instance is None
Expand Down Expand Up @@ -461,7 +470,7 @@ def test_get_lifetime_default(

exit_code, output = self.run_cmd(cli_fs_runner)

assert output == f"default_token_lifetime: {expected_value}\n"
_check_expected_output(output, f"default_token_lifetime: {expected_value}\n")
assert exit_code == ExitCode.SUCCESS

@pytest.mark.parametrize(
Expand Down Expand Up @@ -497,7 +506,8 @@ def test_get_lifetime_instance(

exit_code, output = self.run_cmd(cli_fs_runner, instance_url=instance_url)

assert output == f"default_token_lifetime: {expected_value}\n"
expected_output = f"default_token_lifetime: {expected_value}\n"
_check_expected_output(output, expected_output)
assert exit_code == ExitCode.SUCCESS

def test_unset_lifetime_invalid_instance(self, cli_fs_runner):
Expand All @@ -510,7 +520,7 @@ def test_unset_lifetime_invalid_instance(self, cli_fs_runner):
exit_code, output = self.run_cmd(cli_fs_runner, instance_url=instance_url)

assert exit_code == ExitCode.AUTHENTICATION_ERROR, output
assert output == f"Error: Unknown instance: '{instance_url}'\n"
_check_expected_output(output, f"Error: Unknown instance: '{instance_url}'\n")

def test_get_invalid_field_name(self, cli_fs_runner):
"""
Expand Down Expand Up @@ -546,7 +556,7 @@ def test_get_instance(self, default_value, expected_value, cli_fs_runner):

exit_code, output = self.run_cmd(cli_fs_runner, param="instance")

assert output == f"instance: {expected_value}\n"
_check_expected_output(output, f"instance: {expected_value}\n")
assert exit_code == ExitCode.SUCCESS

@staticmethod
Expand Down

0 comments on commit 00ac1d0

Please sign in to comment.