Skip to content

Commit 61f95dc

Browse files
HyeockJinKimclaude
andauthored
chore(BA-4041): Enable S101 linter rule and replace assert statements (#8364)
Co-authored-by: Claude Sonnet 4.5 <[email protected]>
1 parent d2d29b4 commit 61f95dc

File tree

61 files changed

+391
-211
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+391
-211
lines changed

changes/8364.enhance.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Enable S101 linter rule and replace assert statements

pyproject.toml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ select = [
110110
"PLC0415", # pylint-convention: import-outside-toplevel - enforce imports at module level
111111
"ANN", # flake8-annotations: enforces type annotations
112112
"DTZ", # flake8-datetimez: enforces timezone-aware datetime usage
113+
"S101", # flake8-bandit: detects use of assert in production code
113114
]
114115
ignore = [
115116
"E203", # whitespace before ':' - conflicts with Black formatter
@@ -214,8 +215,8 @@ split-on-trailing-comma = true
214215
# - Client func vfolder has progress printing
215216
"src/ai/backend/client/func/vfolder.py" = ["T20"]
216217
# - Alembic migrations may print progress and have standard signatures
217-
"src/ai/backend/*/models/alembic/**/*.py" = ["T20", "ANN", "PLC0415"]
218-
"src/ai/backend/*/*/models/alembic/**/*.py" = ["T20", "ANN", "PLC0415"]
218+
"src/ai/backend/*/models/alembic/**/*.py" = ["T20", "ANN", "PLC0415", "S101"]
219+
"src/ai/backend/*/*/models/alembic/**/*.py" = ["T20", "ANN", "PLC0415", "S101"]
219220
# - Model modules may have circular dependencies between Row classes
220221
"src/ai/backend/*/models/**/*.py" = ["PLC0415"]
221222
"src/ai/backend/*/*/models/**/*.py" = ["PLC0415"]
@@ -255,8 +256,8 @@ split-on-trailing-comma = true
255256
"src/ai/backend/logging/logger.py" = ["PLC0415"]
256257
"src/ai/backend/logging/utils.py" = ["PLC0415"]
257258
# - Test files may use print for debugging and have flexible type annotations
258-
"tests/**/*.py" = ["T20", "ANN"]
259-
"src/ai/backend/test/**/*.py" = ["T20", "ANN"]
259+
"tests/**/*.py" = ["T20", "ANN", "S101"]
260+
"src/ai/backend/test/**/*.py" = ["T20", "ANN", "S101"]
260261
# - Type stub files have their own conventions
261262
"stubs/**/*.pyi" = ["ANN"]
262263
# - Vec2D class intentionally overrides tuple operators with incompatible return types for vector math

src/ai/backend/accelerator/hyperaccel/lpu/lpu_api.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,10 @@ async def list_devices() -> list[LPUDevice]:
2424
x for x in (ddp / "drm").iterdir() if x.name.startswith("renderD")
2525
],
2626
)
27-
assert len(renderD_files) == 1, (
28-
f'no renderD file found under {display_driver_path.as_posix()}/"drm"!'
29-
)
27+
if len(renderD_files) != 1:
28+
raise RuntimeError(
29+
f'no renderD file found under {display_driver_path.as_posix()}/"drm"!'
30+
)
3031
renderD_filename = renderD_files[0].name
3132
devices.append(
3233
LPUDevice(

src/ai/backend/accelerator/ipu/plugin.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,8 @@ async def prepare_networks(self) -> None:
173173
if len(ipv4_subnet) > 1:
174174
raise DockerNetworkError(f"Multiple IPv4 configs on network {network_identifier}")
175175
ip_network = ipaddress.ip_network(ipv4_subnet[0])
176-
assert isinstance(ip_network, ipaddress.IPv4Network)
176+
if not isinstance(ip_network, ipaddress.IPv4Network):
177+
raise RuntimeError(f"Expected IPv4Network but got {type(ip_network).__name__}")
177178
self.subnet_network_map[ip_network] = network_identifier
178179

179180
def get_docker_network(self, device: IPUDevice) -> str:

src/ai/backend/accelerator/mock/plugin.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -613,8 +613,8 @@ async def generate_docker_args(
613613
return docker_config
614614

615615
def _get_share(self, device: MockDevice) -> Decimal:
616-
if isinstance(device, CUDADevice):
617-
assert not device.is_mig_device
616+
if isinstance(device, CUDADevice) and device.is_mig_device:
617+
raise ValueError("Cannot calculate share for MIG devices")
618618
return self._get_share_raw(device.memory_size, device.processing_units)
619619

620620
def _get_share_raw(self, memory_size: int, subproc_count: int) -> Decimal:
@@ -642,8 +642,10 @@ async def generate_resource_data(
642642
active_device_id_list: list[DeviceId] = []
643643
for slot_type, per_device_alloc in device_alloc.items():
644644
if slot_type == SlotTypes.UNIQUE:
645-
assert len(device_alloc) == 1
646-
assert len(per_device_alloc) == 1
645+
if len(device_alloc) != 1:
646+
raise ValueError("UNIQUE slot type requires exactly one slot allocation")
647+
if len(per_device_alloc) != 1:
648+
raise ValueError("UNIQUE slot type requires exactly one device allocation")
647649
device_id = list(per_device_alloc.keys())[0]
648650
active_device_id_list.append(device_id)
649651
is_unique = True
@@ -787,15 +789,17 @@ async def generate_mounts(
787789
return []
788790

789791
def get_metadata(self) -> AcceleratorMetadata:
790-
assert self._all_devices is not None
792+
if self._all_devices is None:
793+
raise RuntimeError("Devices not initialized. Call list_devices() first.")
791794
format_key = ""
792795
if self._mode == AllocationModes.DISCRETE:
793796
format_key = "device"
794797
else:
795798
format_key = "shares"
796799
if self.key == DeviceName("cuda"):
797800
for device in self._all_devices:
798-
assert isinstance(device, CUDADevice)
801+
if not isinstance(device, CUDADevice):
802+
raise RuntimeError(f"Expected CUDADevice but got {type(device).__name__}")
799803
if device.is_mig_device:
800804
format_key = "*-mig"
801805
break

src/ai/backend/accelerator/rebellions/atom_max/plugin.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,10 @@ async def _list_devices(self) -> list[ATOMMaxDevice]:
4545
for device_info in stats.devices:
4646
if device_info.name not in VALID_DEVICE_NAME:
4747
continue
48-
assert device_info.sid is not None, (
49-
"sid value in atom-stats -j response cannot be null for ATOM Max device!"
50-
)
48+
if device_info.sid is None:
49+
raise RuntimeError(
50+
"sid value in atom-stats -j response cannot be null for ATOM Max device!"
51+
)
5152
devices_by_sid[DeviceId(device_info.sid)].append(
5253
ATOMMaxChildDevice(
5354
serial=device_info.uuid,

src/ai/backend/accelerator/rebellions/common/plugin.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,8 @@ async def generate_docker_args(
280280
numa_node_indexes: set[int] = set()
281281
for dev in await self._list_devices():
282282
if dev.device_id in device_alloc.get(self.slot_types[0][0], {}).keys():
283-
assert dev.numa_node is not None, "NUMA node index of accelerator cannot be null!"
283+
if dev.numa_node is None:
284+
raise RuntimeError("NUMA node index of accelerator cannot be null!")
284285
assigned_devices.append(dev)
285286
device_files.extend([Path(x) for x in await self.list_device_files(dev)])
286287
numa_node_indexes.add(dev.numa_node)

src/ai/backend/account_manager/config.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,11 @@ def uid_validator(
8383
value: int | str | None,
8484
) -> int:
8585
if value is None:
86-
assert cls.default_uid, "value is None but default_uid not provided"
86+
if not cls.default_uid:
87+
raise ValueError("value is None but default_uid not provided")
8788
return cls.default_uid
88-
assert isinstance(value, (int, str)), "value must be an integer"
89+
if not isinstance(value, (int, str)):
90+
raise TypeError("value must be an integer or string")
8991
match value:
9092
case int():
9193
if value == -1:
@@ -153,8 +155,11 @@ def uid_validator(
153155
value: int | str | None,
154156
) -> int:
155157
if value is None:
156-
assert cls.default_gid, "value is None but default_gid not provided"
157-
assert isinstance(value, (int, str)), "value must be an integer"
158+
if not cls.default_gid:
159+
raise ValueError("value is None but default_gid not provided")
160+
return cls.default_gid
161+
if not isinstance(value, (int, str)):
162+
raise TypeError("value must be an integer or string")
158163
match value:
159164
case int():
160165
if value == -1:
@@ -445,7 +450,8 @@ def generate_example_json(
445450
res = {}
446451
for name, info in schema.model_fields.items():
447452
config_key = [*parent, name]
448-
assert info.annotation
453+
if not info.annotation:
454+
raise ValueError(f"Field {name} in {schema} has no annotation")
449455
alternative_example = Undefined
450456
if info.examples:
451457
res[name] = info.examples[0]

src/ai/backend/account_manager/server.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -320,9 +320,8 @@ async def server_main(
320320
try:
321321
ssl_ctx = None
322322
if am_config.ssl_enabled:
323-
assert am_config.ssl_cert is not None, (
324-
"Should set `account_manager.ssl-cert` in config file."
325-
)
323+
if am_config.ssl_cert is None:
324+
raise ValueError("Should set `account_manager.ssl-cert` in config file.")
326325
ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
327326
ssl_ctx.load_cert_chain(
328327
str(am_config.ssl_cert),

src/ai/backend/cli/params.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,8 @@ def convert(
191191
ctx: Optional[click.Context],
192192
) -> Any:
193193
key, value = value.split("=", maxsplit=1)
194-
assert self._rx_range_key.match(key), "The key must be a valid slug string."
194+
if not self._rx_range_key.match(key):
195+
self.fail("The key must be a valid slug string.", param, ctx)
195196
try:
196197
if value.startswith("case:"):
197198
return key, value[5:].split(",")

0 commit comments

Comments
 (0)