Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Require Python 3.6 or newer, use f-strings and variable type annotation syntax #329

Merged
merged 7 commits into from
Aug 5, 2019
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ dist: xenial
language: python
conditions: v1
python:
- 3.5
- 3.6
- 3.7
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you try if there's 3.8 available already?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's available, while a test fails due to the fix for https://pagure.io/python-daemon/issue/34 not being released. Should I add 3.8 and xfail the affected tests on that version?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or the xfail indeed with failing test while it starts passing.

- pypy3
Expand Down
1 change: 1 addition & 0 deletions pytest.ini
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
[pytest]
testpaths = tests/
filterwarnings = error
3 changes: 1 addition & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ def read(fname):
author='Clearcode - The A Room',
author_email='thearoom@clearcode.cc',
license='LGPL',
python_requires='>=3.5',
python_requires='>=3.6',
classifiers=[
'Development Status :: 5 - Production/Stable',
'Environment :: Web Environment',
Expand All @@ -75,7 +75,6 @@ def read(fname):
'Operating System :: OS Independent',
'Programming Language :: Python',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3 :: Only',
Expand Down
28 changes: 11 additions & 17 deletions src/mirakuru/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,11 +151,11 @@ def __init__( # pylint:disable=too-many-arguments
self._stdout = stdout
self._stderr = stderr

self._endtime = None # type: Optional[float]
self.process = None # type: Optional[subprocess.Popen]
self._endtime: Optional[float] = None
self.process: Optional[subprocess.Popen] = None
"""A :class:`subprocess.Popen` instance once process is started."""

self._uuid = '{0}:{1}'.format(os.getpid(), uuid.uuid4())
self._uuid = f'{os.getpid()}:{uuid.uuid4()}'

def __enter__(self: SimpleExecutorType) -> SimpleExecutorType:
"""
Expand Down Expand Up @@ -196,7 +196,7 @@ def _popen_kwargs(self) -> Dict[str, Any]:

:return:
"""
kwargs = {} # type: Dict[str, Any]
kwargs: Dict[str, Any] = {}

if self._stdin:
kwargs['stdin'] = self._stdin
Expand Down Expand Up @@ -239,8 +239,7 @@ def start(self: SimpleExecutorType) -> SimpleExecutorType:
:rtype: SimpleExecutor
"""
if self.process is None:
command = \
self.command # type: Union[str, List[str], Tuple[str, ...]]
command: Union[str, List[str], Tuple[str, ...]] = self.command
if not self._shell:
command = self.command_parts

Expand Down Expand Up @@ -446,20 +445,15 @@ def __repr__(self) -> str:
command = self.command
if len(command) > 10:
command = command[:10] + '...'
return '<{module}.{executor}: "{command}" {id}>'.format(
module=self.__class__.__module__,
executor=self.__class__.__name__,
command=command,
id=hex(id(self))
)
module = self.__class__.__module__
executor = self.__class__.__name__
return f'<{module}.{executor}: "{command}" {hex(id(self))}>'

def __str__(self) -> str:
"""Return readable executor representation."""
return '<{module}.{executor}: "{command}">'.format(
module=self.__class__.__module__,
executor=self.__class__.__name__,
command=self.command
)
module = self.__class__.__module__
executor = self.__class__.__name__
return f'<{module}.{executor}: "{self.command}" {hex(id(self))}>'


class Executor(SimpleExecutor):
Expand Down
4 changes: 2 additions & 2 deletions src/mirakuru/base_env.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ def processes_with_env_ps(env_name: str, env_value: str) -> Set[int]:
environment variable equal certain value
:rtype: set
"""
pids = set() # type: Set[int]
pids: Set[int] = set()
ps_xe = ''
try:
cmd = 'ps', 'xe', '-o', 'pid,cmd'
Expand All @@ -93,7 +93,7 @@ def processes_with_env_ps(env_name: str, env_value: str) -> Set[int]:
except subprocess.CalledProcessError:
log.error("`$ ps xe -o pid,cmd` command exited with non-zero code.")

env = '{0}={1}'.format(env_name, env_value)
env = f'{env_name}={env_value}'

for line in ps_xe:
line = str(line)
Expand Down
21 changes: 11 additions & 10 deletions src/mirakuru/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ def __str__(self) -> str:
:returns: string representation
:rtype: str
"""
return 'Executor {0} timed out after {1} seconds'.format(
self.executor, self.timeout
return (
f'Executor {self.executor} timed out after {self.timeout} seconds'
)


Expand All @@ -63,11 +63,13 @@ def __str__(self) -> str:
:returns: string representation
:rtype: str
"""
return ("Executor {exc.executor} seems to be already running. "
"It looks like the previous executor process hasn't been "
"terminated or killed. Also there might be some completely "
"different service listening on {exc.executor.port} port."
.format(exc=self))
port = getattr(self.executor, 'port')
return (f"Executor {self.executor} seems to be already running. "
f"It looks like the previous executor process hasn't been "
f"terminated or killed."
+ ("" if port is None else
f" Also there might be some completely "
f"different service listening on {port} port."))


class ProcessExitedWithError(ExecutorError):
Expand Down Expand Up @@ -97,6 +99,5 @@ def __str__(self) -> str:
:returns: string representation
:rtype: str
"""
return ("The process invoked by the {exc.executor} executor has "
"exited with a non-zero code: {exc.exit_code}."
.format(exc=self))
return (f"The process invoked by the {self.executor} executor has "
f"exited with a non-zero code: {self.exit_code}.")
2 changes: 1 addition & 1 deletion src/mirakuru/output.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def start(self: OutputExecutorType) -> OutputExecutorType:
"""
super(OutputExecutor, self).start()

polls = [] # type: List[Tuple[select.poll, IO[Any]]]
polls: List[Tuple[select.poll, IO[Any]]] = []

for output_handle, output_method in (
(self._stdout, self.output),
Expand Down
4 changes: 1 addition & 3 deletions tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@
TEST_SOCKET_SERVER_PATH = path.join(TEST_PATH, 'unixsocketserver_for_tests.py')
SAMPLE_DAEMON_PATH = path.join(TEST_PATH, "sample_daemon.py")

HTTP_SERVER_CMD = (
"{python} -m http.server"
).format(python=sys.executable)
HTTP_SERVER_CMD = f"{sys.executable} -m http.server"


def ps_aux():
Expand Down
31 changes: 0 additions & 31 deletions tests/conftest.py

This file was deleted.

13 changes: 7 additions & 6 deletions tests/executors/test_executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ def test_forgotten_stop():
# get substituted with 'sleep 300' and the marked commandline would be
# overwritten.
# Injecting some flow control (`&&`) forces bash to fork properly.
marked_command = 'sleep 300 && true #{0!s}'.format(mark)
marked_command = f'sleep 300 && true #{mark!s}'
executor = SimpleExecutor(marked_command, shell=True)
executor.start()
assert executor.running() is True
Expand All @@ -168,7 +168,7 @@ def test_executor_raises_if_process_exits_with_error():
"""
error_code = 12
failing_executor = Executor(
['bash', '-c', 'exit {0!s}'.format(error_code)],
['bash', '-c', f'exit {error_code!s}'],
timeout=5
)
failing_executor.pre_start_check = mock.Mock( # type: ignore
Expand All @@ -181,7 +181,7 @@ def test_executor_raises_if_process_exits_with_error():
failing_executor.start()

assert exc.value.exit_code == 12
error_msg = 'exited with a non-zero code: {0!s}'.format(error_code)
error_msg = f'exited with a non-zero code: {error_code!s}'
assert error_msg in str(exc.value)

# Pre-start check should have been called - after-start check might or
Expand Down Expand Up @@ -228,14 +228,15 @@ def test_executor_methods_returning_self():

def test_mirakuru_cleanup():
"""Test if cleanup_subprocesses is fired correctly on python exit."""
cmd = '''
cmd = f'''
python -c 'from mirakuru import SimpleExecutor;
from time import sleep;
import gc;
gc.disable();
ex = SimpleExecutor(("python", "{0}")).start();
ex = SimpleExecutor(
("python", "{SAMPLE_DAEMON_PATH}")).start();
sleep(1);
'
'''.format(SAMPLE_DAEMON_PATH)
'''
check_output(shlex.split(cmd.replace('\n', '')))
assert SAMPLE_DAEMON_PATH not in ps_aux()
4 changes: 2 additions & 2 deletions tests/executors/test_executor_kill.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ def test_stopping_brutally():
by executor with SIGKILL automatically.
"""
host_port = "127.0.0.1:8000"
cmd = '{0} {1} {2} True'.format(sys.executable, TEST_SERVER_PATH, host_port)
executor = HTTPExecutor(cmd, 'http://{0!s}/'.format(host_port), timeout=20)
cmd = f'{sys.executable} {TEST_SERVER_PATH} {host_port} True'
executor = HTTPExecutor(cmd, f'http://{host_port!s}/', timeout=20)
executor.start()
assert executor.running() is True

Expand Down
55 changes: 21 additions & 34 deletions tests/executors/test_http_executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,14 @@
HOST = "127.0.0.1"
PORT = 7987

HTTP_NORMAL_CMD = '{0} {1}'.format(HTTP_SERVER_CMD, PORT)
HTTP_SLOW_CMD = '{python} {srv} {host}:{port}' \
.format(python=sys.executable, srv=TEST_SERVER_PATH, host=HOST, port=PORT)
HTTP_NORMAL_CMD = f'{HTTP_SERVER_CMD} {PORT}'
HTTP_SLOW_CMD = f'{sys.executable} {TEST_SERVER_PATH} {HOST}:{PORT}'


slow_server_executor = partial( # pylint: disable=invalid-name
HTTPExecutor,
HTTP_SLOW_CMD,
'http://{0}:{1}/'.format(HOST, PORT),
f'http://{HOST}:{PORT}/',
)


Expand All @@ -37,11 +36,11 @@ def connect_to_server():

def test_executor_starts_and_waits():
"""Test if process awaits for HEAD request to be completed."""
command = 'bash -c "sleep 3 && {0}"'.format(HTTP_NORMAL_CMD)
command = f'bash -c "sleep 3 && {HTTP_NORMAL_CMD}"'

executor = HTTPExecutor(
command,
'http://{0}:{1}/'.format(HOST, PORT),
f'http://{HOST}:{PORT}/',
timeout=20
)
executor.start()
Expand All @@ -60,7 +59,7 @@ def test_shell_started_server_stops():
"""Test if executor terminates properly executor with shell=True."""
executor = HTTPExecutor(
HTTP_NORMAL_CMD,
'http://{0}:{1}/'.format(HOST, PORT),
f'http://{HOST}:{PORT}/',
timeout=20,
shell=True
)
Expand Down Expand Up @@ -89,16 +88,12 @@ def test_slow_method_server_starting(method):
wait for worker processes.
"""

http_method_slow_cmd = '{python} {srv} {host}:{port} False {method}'.format(
python=sys.executable,
srv=TEST_SERVER_PATH,
host=HOST,
port=PORT,
method=method
http_method_slow_cmd = (
f'{sys.executable} {TEST_SERVER_PATH} {HOST}:{PORT} False {method}'
)
with HTTPExecutor(
http_method_slow_cmd,
'http://{0}:{1}/'.format(HOST, PORT), method=method, timeout=30
f'http://{HOST}:{PORT}/', method=method, timeout=30
) as executor:
assert executor.running() is True
connect_to_server()
Expand All @@ -112,16 +107,12 @@ def test_slow_post_payload_server_starting():
wait for worker processes.
"""

http_method_slow_cmd = '{python} {srv} {host}:{port} False {method}'.format(
python=sys.executable,
srv=TEST_SERVER_PATH,
host=HOST,
port=PORT,
method='Key'
http_method_slow_cmd = (
f'{sys.executable} {TEST_SERVER_PATH} {HOST}:{PORT} False Key'
)
with HTTPExecutor(
http_method_slow_cmd,
'http://{0}:{1}/'.format(HOST, PORT),
f'http://{HOST}:{PORT}/',
method='POST',
timeout=30,
payload={'key': 'hole'}
Expand All @@ -136,16 +127,12 @@ def test_slow_post_payload_server_starting():
def test_slow_method_server_timed_out(method):
"""Check if timeout properly expires."""

http_method_slow_cmd = '{python} {srv} {host}:{port} False {method}'.format(
python=sys.executable,
srv=TEST_SERVER_PATH,
host=HOST,
port=PORT,
method=method
http_method_slow_cmd = (
f'{sys.executable} {TEST_SERVER_PATH} {HOST}:{PORT} False {method}'
)
executor = HTTPExecutor(
http_method_slow_cmd,
'http://{0}:{1}/'.format(HOST, PORT), method=method, timeout=1
f'http://{HOST}:{PORT}/', method=method, timeout=1
)

with pytest.raises(TimeoutExpired) as exc:
Expand All @@ -158,10 +145,10 @@ def test_slow_method_server_timed_out(method):
def test_fail_if_other_running():
"""Test raising AlreadyRunning exception when port is blocked."""
executor = HTTPExecutor(
HTTP_NORMAL_CMD, 'http://{0}:{1}/'.format(HOST, PORT),
HTTP_NORMAL_CMD, f'http://{HOST}:{PORT}/',
)
executor2 = HTTPExecutor(
HTTP_NORMAL_CMD, 'http://{0}:{1}/'.format(HOST, PORT),
HTTP_NORMAL_CMD, f'http://{HOST}:{PORT}/',
)

with executor:
Expand All @@ -185,7 +172,7 @@ def test_default_port():
Check if HTTP executor fills in the default port for the TCP check
from the base class if no port is provided in the URL.
"""
executor = HTTPExecutor(HTTP_NORMAL_CMD, 'http://{0}/'.format(HOST))
executor = HTTPExecutor(HTTP_NORMAL_CMD, f'http://{HOST}/')

assert executor.url.port is None
assert executor.port == PORT
Expand Down Expand Up @@ -215,11 +202,11 @@ def test_http_status_codes(accepted_status, expected_timeout):
:param int|str accepted_status: Executor 'status' value
:param bool expected_timeout: if Executor raises TimeoutExpired or not
"""
kwargs = {
kwargs: Dict[str, Any] = {
'command': HTTP_NORMAL_CMD,
'url': 'http://{0}:{1}/badpath'.format(HOST, PORT),
'url': f'http://{HOST}:{PORT}/badpath',
'timeout': 2
} # type: Dict[str, Any]
}
if accepted_status:
kwargs['status'] = accepted_status
executor = HTTPExecutor(**kwargs)
Expand Down
Loading