Skip to content

Commit

Permalink
Remove python 3.8 compatibility code (#2679)
Browse files Browse the repository at this point in the history
* Remove code that was only needed for Python 3.8 compatibility (changes mostly generated using pyupgrade)

* Re-enable some test cases that didnt work on 3.8

* re-organize imports using ruff
  • Loading branch information
cyberw committed Apr 17, 2024
1 parent 6ddfc61 commit 8c64e91
Show file tree
Hide file tree
Showing 11 changed files with 26 additions and 60 deletions.
10 changes: 4 additions & 6 deletions examples/rest.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,10 @@ def t(self):
# use a trailing comma to append the response text to the custom message
assert resp.js["data"]["foo"] == 2, "my custom error message with response text,"

# this only works in python 3.8 and up, so it is commented out:
# if sys.version_info >= (3, 8):
# with self.rest("", "/post", json={"foo": 1}) as resp:
# # assign and assert in one line
# assert (foo := resp.js["foo"])
# print(f"the number {foo} is awesome")
with self.rest("", "/post", json={"foo": 1}) as resp:
# assign and assert in one line
assert (foo := resp.js["foo"])
print(f"the number {foo} is awesome")

# rest() catches most exceptions, so any programming mistakes you make automatically marks the request as a failure
# and stores the callstack in the failure message
Expand Down
2 changes: 1 addition & 1 deletion locust/clients.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

import re
import time
from collections.abc import Generator
from contextlib import contextmanager
from typing import Generator
from urllib.parse import urlparse, urlunparse

import requests
Expand Down
3 changes: 2 additions & 1 deletion locust/contrib/fasthttp.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@
import time
import traceback
from base64 import b64encode
from collections.abc import Generator
from contextlib import contextmanager
from http.cookiejar import CookieJar
from json.decoder import JSONDecodeError
from ssl import SSLError
from typing import Any, Callable, Generator, cast
from typing import Any, Callable, cast
from urllib.parse import urlparse, urlunparse

import gevent
Expand Down
21 changes: 3 additions & 18 deletions locust/dispatch.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
from __future__ import annotations

import contextlib
import functools
import itertools
import math
import sys
import time
from collections import defaultdict
from collections.abc import Generator, Iterator
from operator import attrgetter
from typing import TYPE_CHECKING, Generator, Iterator
from typing import TYPE_CHECKING

import gevent
from roundrobin import smooth
Expand All @@ -18,20 +17,6 @@
from locust.runners import WorkerNode


def compatible_math_gcd(*args: int) -> int:
"""
This function is a workaround for the fact that `math.gcd` in:
- 3.5 <= Python < 3.9 doesn't accept more than two arguments.
- 3.9 <= Python can accept more than two arguments.
See more at https://docs.python.org/3.9/library/math.html#math.gcd
"""
if (3, 5) <= sys.version_info < (3, 9):
return functools.reduce(math.gcd, args)
elif sys.version_info >= (3, 9):
return math.gcd(*args)
raise NotImplementedError("This function is only implemented for Python from 3.5")


# To profile line-by-line, uncomment the code below (i.e. `import line_profiler ...`) and
# place `@profile` on the functions/methods you wish to profile. Then, in the unit test you are
# running, use `from locust.dispatch import profile; profile.print_stats()` at the end of the unit test.
Expand Down Expand Up @@ -406,7 +391,7 @@ def _get_order_of_magnitude(n: float) -> int:
max_order_of_magnitude = _get_order_of_magnitude(min(abs(u[1]) for u in users))
weights = tuple(int(u[1] * max_order_of_magnitude) for u in users)

greatest_common_divisor = compatible_math_gcd(*weights)
greatest_common_divisor = math.gcd(*weights)
normalized_values = [
(
user[0].__name__,
Expand Down
3 changes: 2 additions & 1 deletion locust/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
import logging
import time
import traceback
from collections.abc import Generator
from contextlib import contextmanager
from typing import Any, Generator
from typing import Any

from . import log
from .exception import InterruptTaskSet, RescheduleTask, RescheduleTaskImmediately, StopUser
Expand Down
27 changes: 6 additions & 21 deletions locust/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,12 +250,8 @@ def sigint_handler(_signal, _frame):
# nothing more to do, just wait for the children to exit
for child_pid in children:
_, child_status = os.waitpid(child_pid, 0)
try:
if sys.version_info >= (3, 9):
child_exit_code = os.waitstatus_to_exitcode(child_status)
exit_code = max(exit_code, child_exit_code)
except AttributeError:
pass # dammit python 3.8...
child_exit_code = os.waitstatus_to_exitcode(child_status)
exit_code = max(exit_code, child_exit_code)
sys.exit(exit_code)
else:
options.master = True
Expand All @@ -270,12 +266,8 @@ def kill_workers(children):
try:
_, child_status = os.waitpid(child_pid, os.WNOHANG)
children.remove(child_pid)
try:
if sys.version_info >= (3, 9):
child_exit_code = os.waitstatus_to_exitcode(child_status)
exit_code = max(exit_code, child_exit_code)
except AttributeError:
pass # dammit python 3.8...
child_exit_code = os.waitstatus_to_exitcode(child_status)
exit_code = max(exit_code, child_exit_code)
except OSError as e:
if e.errno == errno.EINTR:
time.sleep(0.1)
Expand All @@ -291,12 +283,8 @@ def kill_workers(children):
pass # never mind, process was already dead
for child_pid in children:
_, child_status = os.waitpid(child_pid, 0)
try:
if sys.version_info >= (3, 9):
child_exit_code = os.waitstatus_to_exitcode(child_status)
exit_code = max(exit_code, child_exit_code)
except AttributeError:
pass # dammit python 3.8...
child_exit_code = os.waitstatus_to_exitcode(child_status)
exit_code = max(exit_code, child_exit_code)
if exit_code > 1:
logging.error(f"Bad response code from worker children: {exit_code}")
# ensure master doesnt finish until output from workers has arrived
Expand Down Expand Up @@ -356,9 +344,6 @@ def kill_workers(children):
See https://github.com/locustio/locust/wiki/Installation#increasing-maximum-number-of-open-files-limit for more info."""
)

if sys.version_info < (3, 9):
logger.warning("Python 3.8 support is deprecated and will be removed soon")

# create locust Environment
locustfile_path = None if not locustfile else os.path.basename(locustfile)

Expand Down
4 changes: 1 addition & 3 deletions locust/runners.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import traceback
from abc import abstractmethod
from collections import defaultdict
from collections.abc import MutableMapping
from collections.abc import Iterator, MutableMapping, ValuesView
from operator import (
itemgetter,
methodcaller,
Expand All @@ -24,10 +24,8 @@
TYPE_CHECKING,
Any,
Callable,
Iterator,
NoReturn,
TypedDict,
ValuesView,
cast,
)
from uuid import uuid4
Expand Down
8 changes: 4 additions & 4 deletions locust/stats.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
import time
from abc import abstractmethod
from collections import OrderedDict, defaultdict, namedtuple
from collections import (
OrderedDict as OrderedDictType,
)
from collections.abc import Iterable
from copy import copy
from html import escape
from itertools import chain
Expand All @@ -19,16 +23,12 @@
TYPE_CHECKING,
Any,
Callable,
Iterable,
NoReturn,
Protocol,
TypedDict,
TypeVar,
cast,
)
from typing import (
OrderedDict as OrderedDictType,
)

import gevent

Expand Down
2 changes: 1 addition & 1 deletion locust/test/mock_logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from typing import List, Union, Dict
from types import TracebackType

LogMessage = List[Union[str, Dict[str, TracebackType]]]
LogMessage = list[Union[str, dict[str, TracebackType]]]


class MockedLoggingHandler(logging.Handler):
Expand Down
4 changes: 1 addition & 3 deletions locust/test/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,6 @@ def my_task(self):
self.assertIn("Shutting down (exit code 0)", stderr)
self.assertEqual(0, proc.returncode)

@unittest.skipIf(sys.version_info < (3, 9), reason="dies in 3.8 on GH and I cant be bothered to investigate it")
def test_default_headless_spawn_options_with_shape(self):
content = MOCK_LOCUSTFILE_CONTENT + textwrap.dedent(
"""
Expand Down Expand Up @@ -2225,7 +2224,6 @@ def mytask(self):

self.assertNotIn("Traceback", stderr)
self.assertIn("INFO/locust.runners: sys.exit(42) called", stderr)
if sys.version_info >= (3, 9):
self.assertEqual(status_code, 42)
self.assertEqual(status_code, 42)
self.assertNotIn("Traceback", master_stderr)
self.assertIn("failed to send heartbeat, setting state to missing", master_stderr)
2 changes: 1 addition & 1 deletion locust/user/task.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@


logger = logging.getLogger(__name__)
TaskT = TypeVar("TaskT", Callable[..., None], Type["TaskSet"])
TaskT = TypeVar("TaskT", Callable[..., None], type["TaskSet"])

LOCUST_STATE_RUNNING, LOCUST_STATE_WAITING, LOCUST_STATE_STOPPING = ["running", "waiting", "stopping"]

Expand Down

0 comments on commit 8c64e91

Please sign in to comment.