Skip to content

Commit e154856

Browse files
authored
Merge pull request ceph#65155 from phlogistonjohn/jjm-py-common-fmt-black
python-common: enable consistent code formatting with 'black' Reviewed-by: Adam King <[email protected]>
2 parents b983b03 + 7e3d460 commit e154856

File tree

4 files changed

+117
-52
lines changed

4 files changed

+117
-52
lines changed

src/python-common/ceph/cephadm/images.py

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,32 +19,53 @@ def _create_image(image_ref: str, key: str) -> ContainerImage:
1919
return ContainerImage(
2020
image_ref,
2121
f'{_img_prefix}{key}',
22-
f'{description} container image'
22+
f'{description} container image',
2323
)
2424

2525

2626
class DefaultImages(Enum):
27-
PROMETHEUS = _create_image('quay.io/prometheus/prometheus:v2.51.0', 'prometheus')
27+
PROMETHEUS = _create_image(
28+
'quay.io/prometheus/prometheus:v2.51.0', 'prometheus'
29+
)
2830
LOKI = _create_image('docker.io/grafana/loki:3.0.0', 'loki')
2931
PROMTAIL = _create_image('docker.io/grafana/promtail:3.0.0', 'promtail')
3032
ALLOY = _create_image('docker.io/grafana/alloy:latest', 'alloy')
31-
NODE_EXPORTER = _create_image('quay.io/prometheus/node-exporter:v1.7.0', 'node_exporter')
32-
ALERTMANAGER = _create_image('quay.io/prometheus/alertmanager:v0.27.0', 'alertmanager')
33+
NODE_EXPORTER = _create_image(
34+
'quay.io/prometheus/node-exporter:v1.7.0', 'node_exporter'
35+
)
36+
ALERTMANAGER = _create_image(
37+
'quay.io/prometheus/alertmanager:v0.27.0', 'alertmanager'
38+
)
3339
GRAFANA = _create_image('quay.io/ceph/grafana:11.6.0', 'grafana')
3440
HAPROXY = _create_image('quay.io/ceph/haproxy:2.3', 'haproxy')
3541
KEEPALIVED = _create_image('quay.io/ceph/keepalived:2.2.4', 'keepalived')
3642
NVMEOF = _create_image('quay.io/ceph/nvmeof:1.5', 'nvmeof')
37-
SNMP_GATEWAY = _create_image('docker.io/maxwo/snmp-notifier:v1.2.1', 'snmp_gateway')
38-
ELASTICSEARCH = _create_image('quay.io/omrizeneva/elasticsearch:6.8.23', 'elasticsearch')
39-
JAEGER_COLLECTOR = _create_image('quay.io/jaegertracing/jaeger-collector:1.29',
40-
'jaeger_collector')
41-
JAEGER_AGENT = _create_image('quay.io/jaegertracing/jaeger-agent:1.29', 'jaeger_agent')
42-
JAEGER_QUERY = _create_image('quay.io/jaegertracing/jaeger-query:1.29', 'jaeger_query')
43-
SAMBA = _create_image('quay.io/samba.org/samba-server:devbuilds-centos-amd64', 'samba')
44-
SAMBA_METRICS = _create_image('quay.io/samba.org/samba-metrics:devbuilds-centos-amd64',
45-
'samba_metrics')
43+
SNMP_GATEWAY = _create_image(
44+
'docker.io/maxwo/snmp-notifier:v1.2.1', 'snmp_gateway'
45+
)
46+
ELASTICSEARCH = _create_image(
47+
'quay.io/omrizeneva/elasticsearch:6.8.23', 'elasticsearch'
48+
)
49+
JAEGER_COLLECTOR = _create_image(
50+
'quay.io/jaegertracing/jaeger-collector:1.29', 'jaeger_collector'
51+
)
52+
JAEGER_AGENT = _create_image(
53+
'quay.io/jaegertracing/jaeger-agent:1.29', 'jaeger_agent'
54+
)
55+
JAEGER_QUERY = _create_image(
56+
'quay.io/jaegertracing/jaeger-query:1.29', 'jaeger_query'
57+
)
58+
SAMBA = _create_image(
59+
'quay.io/samba.org/samba-server:devbuilds-centos-amd64', 'samba'
60+
)
61+
SAMBA_METRICS = _create_image(
62+
'quay.io/samba.org/samba-metrics:devbuilds-centos-amd64',
63+
'samba_metrics',
64+
)
4665
NGINX = _create_image('quay.io/ceph/nginx:sclorg-nginx-126', 'nginx')
47-
OAUTH2_PROXY = _create_image('quay.io/oauth2-proxy/oauth2-proxy:v7.6.0', 'oauth2_proxy')
66+
OAUTH2_PROXY = _create_image(
67+
'quay.io/oauth2-proxy/oauth2-proxy:v7.6.0', 'oauth2_proxy'
68+
)
4869

4970
@property
5071
def image_ref(self) -> str:

src/python-common/ceph/fs/earmarking.py

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -69,20 +69,28 @@ def __init__(self, fs: FSOperations, path: str) -> None:
6969
self.fs = fs
7070
self.path = path
7171

72-
def _handle_cephfs_error(self, e: Exception, action: str) -> Optional[str]:
72+
def _handle_cephfs_error(
73+
self, e: Exception, action: str
74+
) -> Optional[str]:
7375
if isinstance(e, ValueError):
74-
raise EarmarkException(errno.EINVAL, f"Invalid earmark specified: {e}") from e
76+
raise EarmarkException(
77+
errno.EINVAL, f"Invalid earmark specified: {e}"
78+
) from e
7579
elif isinstance(e, OSError):
7680
if e.errno == errno.ENODATA:
7781
# Return empty string when earmark is not set
78-
log.info(f"No earmark set for the path while {action}. Returning empty result.")
82+
log.info(
83+
f"No earmark set for the path while {action}. Returning empty result."
84+
)
7985
return ''
8086
else:
8187
log.error(f"Error {action} earmark: {e}")
8288
raise EarmarkException(-e.errno, e.strerror) from e
8389
else:
8490
log.error(f"Unexpected error {action} earmark: {e}")
85-
raise EarmarkException(errno.EFAULT, f"Unexpected error {action} earmark: {e}") from e
91+
raise EarmarkException(
92+
errno.EFAULT, f"Unexpected error {action} earmark: {e}"
93+
) from e
8694

8795
@staticmethod
8896
def parse_earmark(value: str) -> Optional[EarmarkContents]:
@@ -109,7 +117,9 @@ def parse_earmark(value: str) -> Optional[EarmarkContents]:
109117
raise EarmarkParseError("Earmark contains empty sections.")
110118

111119
# Return parsed earmark with top scope and subsections
112-
return EarmarkContents(top=EarmarkTopScope(parts[0]), subsections=parts[1:])
120+
return EarmarkContents(
121+
top=EarmarkTopScope(parts[0]), subsections=parts[1:]
122+
)
113123

114124
def _validate_earmark(self, earmark: str) -> bool:
115125
"""
@@ -130,19 +140,23 @@ def _validate_earmark(self, earmark: str) -> bool:
130140
# Specific validation for 'smb' scope
131141
if parsed.top == EarmarkTopScope.SMB:
132142
# Valid formats: 'smb' or 'smb.cluster.{cluster_id}'
133-
if not (len(parsed.subsections) == 0 or
134-
(len(parsed.subsections) == 2 and
135-
parsed.subsections[0] == 'cluster' and parsed.subsections[1])):
143+
if not (
144+
len(parsed.subsections) == 0
145+
or (
146+
len(parsed.subsections) == 2
147+
and parsed.subsections[0] == 'cluster'
148+
and parsed.subsections[1]
149+
)
150+
):
136151
return False
137152

138153
return True
139154

140155
def get_earmark(self) -> Optional[str]:
141156
try:
142-
earmark_value = (
143-
self.fs.getxattr(self.path, XATTR_SUBVOLUME_EARMARK_NAME)
144-
.decode('utf-8')
145-
)
157+
earmark_value = self.fs.getxattr(
158+
self.path, XATTR_SUBVOLUME_EARMARK_NAME
159+
).decode('utf-8')
146160
return earmark_value
147161
except Exception as e:
148162
return self._handle_cephfs_error(e, "getting")
@@ -155,11 +169,16 @@ def set_earmark(self, earmark: str) -> None:
155169
f"Invalid earmark specified: '{earmark}'. "
156170
"A valid earmark should either be empty or start with 'nfs' or 'smb', "
157171
"followed by dot-separated non-empty components or simply set "
158-
"'smb.cluster.{cluster_id}' for the smb intra-cluster scope."
159-
)
172+
"'smb.cluster.{cluster_id}' for the smb intra-cluster scope.",
173+
)
160174

161175
try:
162-
self.fs.setxattr(self.path, XATTR_SUBVOLUME_EARMARK_NAME, earmark.encode('utf-8'), 0)
176+
self.fs.setxattr(
177+
self.path,
178+
XATTR_SUBVOLUME_EARMARK_NAME,
179+
earmark.encode('utf-8'),
180+
0,
181+
)
163182
log.info(f"Earmark '{earmark}' set on {self.path}.")
164183
except Exception as e:
165184
self._handle_cephfs_error(e, "setting")

src/python-common/ceph/utils.py

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ def datetime_to_str(dt: datetime.datetime) -> str:
3030
ISO 8601 (timezone=UTC).
3131
"""
3232
return dt.astimezone(tz=datetime.timezone.utc).strftime(
33-
'%Y-%m-%dT%H:%M:%S.%fZ')
33+
'%Y-%m-%dT%H:%M:%S.%fZ'
34+
)
3435

3536

3637
def str_to_datetime(string: str) -> datetime.datetime:
@@ -50,7 +51,7 @@ def str_to_datetime(string: str) -> datetime.datetime:
5051
"""
5152
fmts = [
5253
'%Y-%m-%dT%H:%M:%S.%f',
53-
'%Y-%m-%dT%H:%M:%S.%f%z'
54+
'%Y-%m-%dT%H:%M:%S.%f%z',
5455
]
5556

5657
# In *all* cases, the 9 digit second precision is too much for
@@ -74,8 +75,11 @@ def str_to_datetime(string: str) -> datetime.datetime:
7475
except ValueError:
7576
pass
7677

77-
raise ValueError("Time data {} does not match one of the formats {}".format(
78-
string, str(fmts)))
78+
raise ValueError(
79+
"Time data {} does not match one of the formats {}".format(
80+
string, str(fmts)
81+
)
82+
)
7983

8084

8185
def parse_timedelta(delta: str) -> Optional[datetime.timedelta]:
@@ -101,13 +105,15 @@ def parse_timedelta(delta: str) -> Optional[datetime.timedelta]:
101105
:return: The `datetime.timedelta` object or `None` in case of
102106
a parsing error.
103107
"""
104-
parts = re.match(r'(?P<seconds>-?\d+)s|'
105-
r'(?P<minutes>-?\d+)m|'
106-
r'(?P<hours>-?\d+)h|'
107-
r'(?P<days>-?\d+)d|'
108-
r'(?P<weeks>-?\d+)w$',
109-
delta,
110-
re.IGNORECASE)
108+
parts = re.match(
109+
r'(?P<seconds>-?\d+)s|'
110+
r'(?P<minutes>-?\d+)m|'
111+
r'(?P<hours>-?\d+)h|'
112+
r'(?P<days>-?\d+)d|'
113+
r'(?P<weeks>-?\d+)w$',
114+
delta,
115+
re.IGNORECASE,
116+
)
111117
if not parts:
112118
return None
113119
parts = parts.groupdict()
@@ -130,17 +136,18 @@ def is_hex(s: str, strict: bool = True) -> bool:
130136
return True
131137

132138

133-
def http_req(hostname: str = '',
134-
port: str = '443',
135-
method: Optional[str] = None,
136-
headers: MutableMapping[str, str] = {},
137-
data: Optional[str] = None,
138-
endpoint: str = '/',
139-
scheme: str = 'https',
140-
ssl_verify: bool = False,
141-
timeout: Optional[int] = None,
142-
ssl_ctx: Optional[Any] = None) -> Tuple[Any, Any, Any]:
143-
139+
def http_req(
140+
hostname: str = '',
141+
port: str = '443',
142+
method: Optional[str] = None,
143+
headers: MutableMapping[str, str] = {},
144+
data: Optional[str] = None,
145+
endpoint: str = '/',
146+
scheme: str = 'https',
147+
ssl_verify: bool = False,
148+
timeout: Optional[int] = None,
149+
ssl_ctx: Optional[Any] = None,
150+
) -> Tuple[Any, Any, Any]:
144151
if not ssl_ctx:
145152
ssl_ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
146153
if not ssl_verify:

src/python-common/tox.ini

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[tox]
2-
envlist = lint, rstcheck, mypy, py3
2+
envlist = lint, rstcheck, mypy, py3, check-black
33
skip_missing_interpreters = true
44

55
[testenv:py3]
@@ -36,3 +36,21 @@ deps =
3636
rstcheck
3737
commands =
3838
rstcheck --report-level info README.rst
39+
40+
41+
# OPT-IN formatting with 'black'
42+
# add your module to the modules list below to use automated formatting
43+
[black]
44+
deps = black>=23,<25
45+
options = -l78 -t py36 --skip-string-normalization
46+
modules = ceph/cephadm ceph/cryptotools ceph/fs ceph/utils.py
47+
48+
[testenv:check-black]
49+
deps = {[black]deps}
50+
commands =
51+
black --check -q {[black]options} {[black]modules}
52+
53+
[testenv:format-black]
54+
deps = {[black]deps}
55+
commands =
56+
black {[black]options} {[black]modules}

0 commit comments

Comments
 (0)