Skip to content

Commit 8b65175

Browse files
committed
Updated linters and reformatters
1 parent 70c004a commit 8b65175

13 files changed

+142
-57
lines changed

.github/workflows/pre-commit.yml

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
name: pre-commit
2+
3+
on:
4+
push:
5+
pull_request:
6+
types: [ opened, synchronize ]
7+
8+
jobs:
9+
pre-commit:
10+
runs-on: ubuntu-latest
11+
env:
12+
PYTHON_VER: 3.12
13+
steps:
14+
- name: Checkout
15+
uses: actions/checkout@v4
16+
- name: Set up Python ${{ env.PYTHON_VER }}
17+
uses: actions/setup-python@v5
18+
with:
19+
python-version: ${{ env.PYTHON_VER }}
20+
- name: Run pre-commit tasks
21+
uses: pre-commit/[email protected]

.pre-commit-config.yaml

+9-8
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,20 @@ repos:
66
rev: 'v0.6.2'
77
hooks:
88
- id: ruff
9-
args: [ --fix ]
9+
args:
10+
- --fix
1011
- id: ruff-format
1112

12-
- repo: https://github.com/PyCQA/bandit
13-
rev: 1.7.9
14-
hooks:
15-
- id: bandit
16-
args: [ "-c", "pyproject.toml" ]
17-
additional_dependencies: ["bandit[toml]"]
18-
1913
- repo: https://github.com/pre-commit/mirrors-mypy
2014
rev: v1.11.2
2115
hooks:
2216
- id: mypy
2317
additional_dependencies:
2418
- types-requests
19+
20+
- repo: https://github.com/PyCQA/bandit
21+
rev: 1.7.9
22+
hooks:
23+
- id: bandit
24+
args: [ "-c", "pyproject.toml" ]
25+
additional_dependencies: [ "bandit[toml]" ]

mjml/apps.py

+4-5
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,12 @@ def _get_renderer_params(cls) -> Dict[str, Any]:
5050
else mjml_settings.MJML_CHECK_CMD_ON_STARTUP
5151
),
5252
}
53-
elif mjml_settings.MJML_BACKEND_MODE == "tcpserver":
53+
if mjml_settings.MJML_BACKEND_MODE == "tcpserver":
5454
return {
5555
"BACKEND": "mjml.backends.TCPServerBackend",
5656
"SERVERS": mjml_settings.MJML_TCPSERVERS or [("127.0.0.1", 28101)],
5757
}
58-
elif mjml_settings.MJML_BACKEND_MODE == "httpserver":
58+
if mjml_settings.MJML_BACKEND_MODE == "httpserver":
5959
return {
6060
"BACKEND": "mjml.backends.RequestsHTTPServerBackend",
6161
"SERVERS": [
@@ -68,12 +68,11 @@ def _get_renderer_params(cls) -> Dict[str, Any]:
6868
{
6969
"URL": "https://api.mjml.io/v1/render",
7070
"HTTP_AUTH": None, # None (default) or ('login', 'password')
71-
}
71+
},
7272
]
7373
],
7474
}
75-
else:
76-
RuntimeError("Invalid MJML settings")
75+
RuntimeError("Invalid MJML settings")
7776

7877
# default settings
7978
return {

mjml/backends/cmd.py

+10-7
Original file line numberDiff line numberDiff line change
@@ -58,39 +58,42 @@ def render_mjml_to_html(self, mjml_source: str) -> str:
5858
stderr = p.communicate(force_bytes(mjml_source))[1]
5959
except OSError as e:
6060
cmd_str = " ".join(self._cmd_args)
61-
raise RuntimeError(
61+
err_msg = (
6262
f'Problem to run command "{cmd_str}"\n'
6363
f"{e}\n"
6464
"Check that mjml is installed and allow permissions to execute.\n"
6565
"See https://github.com/mjmlio/mjml#installation"
66-
) from e
66+
)
67+
raise RuntimeError(err_msg) from e
6768
stdout_tmp_f.seek(0)
6869
stdout = stdout_tmp_f.read()
6970

7071
if stderr:
71-
raise RuntimeError(f"MJML stderr is not empty: {force_str(stderr)}.")
72+
err_msg = f"MJML stderr is not empty: {force_str(stderr)}."
73+
raise RuntimeError(err_msg)
7274

7375
return force_str(stdout)
7476

7577
def check(self) -> None:
7678
if not self._check_on_startup:
77-
return None
79+
return
7880

7981
try:
8082
html = self.render_mjml_to_html(
81-
"<mjml><mj-body><mj-container><mj-text>" "MJMLv3" "</mj-text></mj-container></mj-body></mjml>"
83+
"<mjml><mj-body><mj-container><mj-text>MJMLv3</mj-text></mj-container></mj-body></mjml>",
8284
)
8385
except RuntimeError:
8486
try:
8587
html = self.render_mjml_to_html(
8688
"<mjml><mj-body><mj-section><mj-column><mj-text>"
8789
"MJMLv4"
88-
"</mj-text></mj-column></mj-section></mj-body></mjml>"
90+
"</mj-text></mj-column></mj-section></mj-body></mjml>",
8991
)
9092
except RuntimeError as e:
9193
raise RendererBackendCheckFailedError(e) from e
9294
if "<html " not in html:
93-
raise RendererBackendCheckFailedError(
95+
err_msg = (
9496
"mjml command returns wrong result.\n"
9597
"Check MJML is installed correctly. See https://github.com/mjmlio/mjml#installation"
9698
)
99+
raise RendererBackendCheckFailedError(err_msg)

mjml/backends/http.py

+14-10
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ def _parse_raw_server_params(cls, raw_server_params: Dict[str, Any]) -> Dict[str
3737
else:
3838
auth_type, auth_params = "BASIC", auth_raw
3939
else:
40-
raise ValueError("Invalid AUTH value")
40+
err_msg = "Invalid AUTH value"
41+
raise ValueError(err_msg)
4142

4243
server_params["auth"] = cls._get_auth_instance(
4344
auth_type=auth_type,
@@ -59,7 +60,8 @@ def _get_auth_instance(cls, auth_type: str, auth_params: Union[List, Tuple, Dict
5960
elif isinstance(auth_params, (list, tuple)):
6061
instance = auth_cls(*auth_params)
6162
else:
62-
raise ValueError("Invalid type of auth_params")
63+
err_msg = "Invalid type of auth_params"
64+
raise ValueError(err_msg)
6365
return instance
6466

6567
def render_mjml_to_html(self, mjml_source: str) -> str:
@@ -91,18 +93,20 @@ def render_mjml_to_html(self, mjml_source: str) -> str:
9193
f'Line: {e.get("line")} Tag: {e.get("tagName")} Message: {e.get("message")}' for e in errors
9294
]
9395
msg_str = "\n".join(msg_lines)
94-
raise RuntimeError(f"MJML compile error (via MJML HTTP server): {msg_str}")
96+
err_msg = f"MJML compile error (via MJML HTTP server): {msg_str}"
97+
raise RuntimeError(err_msg)
9598

9699
return force_str(data["html"])
97-
else:
98-
msg = (
99-
f"[code={response.status_code}, request_id={data.get('request_id', '')}] "
100-
f"{data.get('message', 'Unknown error.')}"
101-
)
102-
raise RuntimeError(f"MJML compile error (via MJML HTTP server): {msg}")
100+
msg = (
101+
f"[code={response.status_code}, request_id={data.get('request_id', '')}] "
102+
f"{data.get('message', 'Unknown error.')}"
103+
)
104+
err_msg = f"MJML compile error (via MJML HTTP server): {msg}"
105+
raise RuntimeError(err_msg)
103106

104-
raise RuntimeError(
107+
err_msg = (
105108
"MJML compile error (via MJML HTTP server): no working server\n"
106109
f"Number of servers: {len(self._servers_params)}\n"
107110
f"Timeouts: {timeouts}"
108111
)
112+
raise RuntimeError(err_msg)

mjml/backends/tcp.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -56,17 +56,18 @@ def render_mjml_to_html(self, mjml_source: str) -> str:
5656
result = force_str(self._socket_recvall(s, result_len))
5757
if ok:
5858
return result
59-
else:
60-
raise RuntimeError(f"MJML compile error (via MJML TCP server): {result}")
59+
err_msg = f"MJML compile error (via MJML TCP server): {result}"
60+
raise RuntimeError(err_msg)
6161
except socket.timeout:
6262
timeouts += 1
6363
finally:
6464
s.close()
65-
raise RuntimeError(
65+
err_msg = (
6666
"MJML compile error (via MJML TCP server): no working server\n"
6767
f"Number of servers: {len(self._servers_params)}\n"
6868
f"Timeouts: {timeouts}"
6969
)
70+
raise RuntimeError(err_msg)
7071

7172
@classmethod
7273
def _socket_recvall(cls, sock: socket.socket, n: int) -> Optional[bytes]:

mjml/settings.py

+26-10
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@
55
# old deprecated settings
66

77
MJML_BACKEND_MODE = getattr(settings, "MJML_BACKEND_MODE", None)
8-
if MJML_BACKEND_MODE is not None:
9-
assert MJML_BACKEND_MODE in {"cmd", "tcpserver", "httpserver"}
8+
if MJML_BACKEND_MODE is not None and MJML_BACKEND_MODE not in {"cmd", "tcpserver", "httpserver"}:
9+
err_msg = f"Invalid value of MJML_BACKEND_MODE: {MJML_BACKEND_MODE}; allowed values: cmd, tcpserver, httpserver"
10+
raise ValueError(err_msg)
1011

1112
# cmd backend mode configs
1213
MJML_EXEC_CMD = getattr(settings, "MJML_EXEC_CMD", None)
@@ -15,19 +16,34 @@
1516
# tcpserver backend mode configs
1617
MJML_TCPSERVERS = getattr(settings, "MJML_TCPSERVERS", None)
1718
if MJML_TCPSERVERS is not None:
18-
assert isinstance(MJML_TCPSERVERS, (list, tuple))
19+
if not isinstance(MJML_TCPSERVERS, (list, tuple)):
20+
err_msg = f"Invalid type of MJML_TCPSERVERS: {type(MJML_TCPSERVERS)}; allowed types: list, tuple"
21+
raise ValueError(err_msg)
22+
1923
for t in MJML_TCPSERVERS:
20-
assert isinstance(t, (list, tuple)) and len(t) == 2 and isinstance(t[0], str) and isinstance(t[1], int)
24+
if not (isinstance(t, (list, tuple)) and len(t) == 2 and isinstance(t[0], str) and isinstance(t[1], int)):
25+
err_msg = "Invalid value of MJML_TCPSERVERS"
26+
raise ValueError(err_msg)
2127

2228
# httpserver backend mode configs
2329
MJML_HTTPSERVERS = getattr(settings, "MJML_HTTPSERVERS", None)
2430
if MJML_HTTPSERVERS is not None:
25-
assert isinstance(MJML_HTTPSERVERS, (list, tuple))
31+
if not isinstance(MJML_HTTPSERVERS, (list, tuple)):
32+
err_msg = f"Invalid type of MJML_HTTPSERVERS: {type(MJML_HTTPSERVERS)}; allowed types: list, tuple"
33+
raise ValueError(err_msg)
34+
2635
for t in MJML_HTTPSERVERS:
27-
assert isinstance(t, dict)
28-
assert "URL" in t and isinstance(t["URL"], str)
36+
if not (isinstance(t, dict) and "URL" in t and isinstance(t["URL"], str)):
37+
err_msg = "Invalid value of MJML_HTTPSERVERS"
38+
raise ValueError(err_msg)
39+
2940
if "HTTP_AUTH" in t:
3041
http_auth = t["HTTP_AUTH"]
31-
assert isinstance(http_auth, (type(None), list, tuple))
32-
if http_auth is not None:
33-
assert len(http_auth) == 2 and isinstance(http_auth[0], str) and isinstance(http_auth[1], str)
42+
if not isinstance(http_auth, (type(None), list, tuple)):
43+
err_msg = "Invalid value of HTTP_AUTH in MJML_HTTPSERVERS"
44+
raise ValueError(err_msg)
45+
if http_auth is not None and not (
46+
len(http_auth) == 2 and isinstance(http_auth[0], str) and isinstance(http_auth[1], str)
47+
):
48+
err_msg = "Invalid value of HTTP_AUTH in MJML_HTTPSERVERS"
49+
raise ValueError(err_msg)

mjml/templatetags/mjml.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ def mjml(parser, token) -> MJMLRenderNode:
3030
parser.delete_first_token()
3131
tokens = token.split_contents()
3232
if len(tokens) != 1:
33-
raise template.TemplateSyntaxError(f"'{tokens[0]!r}' tag doesn't receive any arguments.")
33+
err_msg = f"'{tokens[0]!r}' tag doesn't receive any arguments."
34+
raise template.TemplateSyntaxError(err_msg)
3435
renderer = apps.get_app_config(MJMLConfig.name).get_renderer()
3536
return MJMLRenderNode(nodelist, renderer=renderer)

pyproject.toml

+39-2
Original file line numberDiff line numberDiff line change
@@ -84,12 +84,49 @@ line-length = 118
8484
[tool.ruff.lint]
8585
select = [
8686
"E", # pycodestyle errors
87+
"W", # pycodestyle warnings
8788
"F", # Pyflakes
88-
"UP", # pyupgrade
89+
"I", # isort
8990
"B", # flake8-bugbear
9091
"SIM", # flake8-simplify
9192
"T20", # flake8-print
9293
"BLE", # flake8-blind-except
9394
"C4", # flake8-comprehensions
94-
"I", # isort
95+
"A", # flake8-builtins
96+
"COM", # flake8-commas
97+
"DJ", # flake8-django
98+
"S", # flake8-bandit
99+
"EM", # flake8-errmsg
100+
"FA", # flake8-future-annotations
101+
"ISC", # flake8-implicit-str-concat
102+
"LOG", # flake8-logging
103+
"G", # flake8-logging-format
104+
"PIE", # flake8-pie
105+
"PYI", # flake8-pyi
106+
"Q", # flake8-quotes
107+
"RSE", # flake8-raise
108+
"RET", # flake8-return
109+
"TID", # flake8-tidy-imports
110+
"TCH", # flake8-type-checking
111+
"ARG", # flake8-unused-arguments
112+
"PTH", # flake8-use-pathlib
113+
"TD", # flake8-todos
114+
"FLY", # flynt
115+
"PERF", # Perflint
116+
"UP", # pyupgrade
117+
"C90", # mccabe
95118
]
119+
ignore = [
120+
"S105",
121+
"S603",
122+
"S607",
123+
"TD003",
124+
"TD002",
125+
]
126+
127+
[tool.ruff.lint.pyupgrade]
128+
# Preserve types, even if a file imports `from __future__ import annotations`.
129+
keep-runtime-typing = true
130+
131+
[tool.ruff.lint.mccabe]
132+
max-complexity = 10

tests/settings.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from pathlib import Path
22

3-
BASE_DIR = Path(__file__).absolute().parent
3+
BASE_DIR = Path(__file__).resolve().parent
44

55
SECRET_KEY = "test"
66

tests/test_backends_http.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ def test_http_server_error(self) -> None:
7979
@mock.patch("requests.post")
8080
def test_http_auth(self, post_mock) -> None:
8181
with safe_change_mjml_settings() as mjml_app_config:
82-
for server_conf in mjml_settings.MJML_HTTPSERVERS: # todo fix
82+
for server_conf in mjml_settings.MJML_HTTPSERVERS: # type: ignore # TODO: fix
8383
server_conf["HTTP_AUTH"] = ("testuser", "testpassword")
8484
mjml_app_config.ready()
8585

@@ -92,8 +92,8 @@ def test_http_auth(self, post_mock) -> None:
9292
"html": "html_string",
9393
"mjml": "mjml_string",
9494
"mjml_version": "4.5.1",
95-
}
96-
)
95+
},
96+
),
9797
)
9898
response._content = content
9999
response.encoding = "utf-8"

tests/tests.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
from .tools import MJMLFixtures, render_tpl
55

6-
# class TestMJMLApps(TestCase): # todo rewrite
6+
# class TestMJMLApps(TestCase): # TODO rewrite # noqa
77
# def test_check_mjml_command(self) -> None:
88
# with safe_change_mjml_settings() as mjml_app_config:
99
# mjml_settings.MJML_EXEC_CMD = '/no_mjml_exec_test'

tests/tools.py

+8-6
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,11 @@ def _terminate_processes(cls) -> None:
6464

6565
@classmethod
6666
def _start_tcp_servers(cls) -> None:
67-
root_dir = os.path.dirname(settings.BASE_DIR)
68-
tcpserver_path = os.path.join(root_dir, "mjml-tcpserver", "tcpserver.js")
67+
root_dir = settings.BASE_DIR.parent
68+
tcpserver_path = root_dir / "mjml-tcpserver/tcpserver.js"
6969
env = os.environ.copy()
7070
env["NODE_PATH"] = root_dir
71-
for host, port in mjml_settings.MJML_TCPSERVERS: # todo fix
71+
for host, port in mjml_settings.MJML_TCPSERVERS: # type: ignore # TODO: fix
7272
p = subprocess.Popen(
7373
[
7474
"node",
@@ -90,7 +90,7 @@ def _stop_tcp_servers(cls) -> None:
9090
@classmethod
9191
def _start_http_servers(cls) -> None:
9292
env = os.environ.copy()
93-
for server_conf in mjml_settings.MJML_HTTPSERVERS: # todo fix
93+
for server_conf in mjml_settings.MJML_HTTPSERVERS: # type: ignore # TODO: fix
9494
parsed = urlparse(server_conf["URL"])
9595
host, port = parsed.netloc.split(":")
9696
p = subprocess.Popen(
@@ -119,7 +119,8 @@ def setUpClass(cls) -> None:
119119
elif cls.SERVER_TYPE == "httpserver":
120120
cls._start_http_servers()
121121
else:
122-
raise RuntimeError("Invalid SERVER_TYPE: {}", cls.SERVER_TYPE)
122+
err_msg = f"Invalid SERVER_TYPE: {cls.SERVER_TYPE}"
123+
raise RuntimeError(err_msg)
123124

124125
@classmethod
125126
def tearDownClass(cls) -> None:
@@ -128,7 +129,8 @@ def tearDownClass(cls) -> None:
128129
elif cls.SERVER_TYPE == "httpserver":
129130
cls._stop_http_servers()
130131
else:
131-
raise RuntimeError("Invalid SERVER_TYPE: {}", cls.SERVER_TYPE)
132+
err_msg = f"Invalid SERVER_TYPE: {cls.SERVER_TYPE}"
133+
raise RuntimeError(err_msg)
132134
super().tearDownClass() # type: ignore
133135

134136

0 commit comments

Comments
 (0)