Skip to content

Commit

Permalink
Further improvements, add Ruff configs
Browse files Browse the repository at this point in the history
  • Loading branch information
TeamSpen210 committed Sep 8, 2024
1 parent b21d7e8 commit dc550d3
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 37 deletions.
66 changes: 66 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,69 @@ include_trailing_comma = true
from_first = true
combine_as_imports = true
src_paths = ["src"]

[tool.ruff]
line-length = 127

[tool.ruff.lint]
select = [
"UP", "F", "C4", "ANN", "B", "PIE", "RUF",
"PLC", "PLE", "PLW", # Pylint.

"TCH005", # Empty type-checking block.
]
allowed-confusables = [
"×", # Multiplication sign
]
extend-ignore = [
# Allow *-imports.
"F403",
# name may be undefined, or defined from star imports: module
"F405",
"F841", # Unused local var, detects tuple unpacks.
# Flake8-annotations.
# Type annotations for self & cls are not important.
"ANN101",
"ANN102",
# Allow typing.Any
"ANN401",

# PyLint:
"PLC0414", # import x as x is used for type checking.
"PLC0415", # We use non-toplevel imports to fetch our databases after initialising the classes.
"PLC1901", # Allow compare to empty string, can be more clear.
"PLE1205", # Too many arguments for logging, doesn't handle our format
"PLW0603", # Allow use of global statement.
"PLW2901", # Allow redefining loop var inside the loop.

# Ruff:
"RUF100", # Sometimes use # noqa for other linters
"RUF022", # All not sorted
"RUF023", # Slots not sorted

# Flake8-bugbear:
# Loop control var not used, triggers on unpackings.
"B007",
# Stacklevel parameter required for warnings.warn() - doesn't detect positional args.
"B028",

# Pycodestyle, when out of preview:
"E221", # Allow multiple spaces before operators if we want to align
"E226", # Allow no spaces like "1+1", sometimes useful to indicate precedence

# Pyupgrade:
# Keep using typing types even with __future__.annotations.
"UP006", "UP007",

# Flake8-pie:
# Prefer to use pass in empty functions, even if docstring is present
"PIE790",
# Allow aliases for enum values, used often.
"PIE796",
]

[tool.ruff.lint.flake8-bugbear]
extend-immutable-calls = [
"srctools.math.FrozenVec", "srctools.math.FrozenAngle", "srctools.math.FrozenMatrix",
"typing.cast", "srctools.logger.get_logger",
]
2 changes: 2 additions & 0 deletions src/hammeraddons/bsp_transform/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import inspect

import attrs
import trio.lowlevel

from srctools import FGD, VMF, EmptyMapping, Entity, FileSystem, Keyvalues, Output
from srctools.bsp import BSP
Expand Down Expand Up @@ -174,6 +175,7 @@ def deco(func: TransFuncT) -> TransFuncT:
else:
async def async_wrapper(ctx: Context) -> None:
"""Just freeze all other tasks to run this."""
await trio.lowlevel.checkpoint()
func(ctx)
TRANSFORMS[name.casefold()] = Transform(async_wrapper, name, priority)
return func
Expand Down
6 changes: 3 additions & 3 deletions src/hammeraddons/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ def parse(map_path: Path, game_folder: Optional[str]='') -> Config:
conf_path = folder / CONF_NAME
if conf_path.exists():
LOGGER.info('Config path: "{}"', conf_path.absolute())
with open(conf_path) as f:
with open(conf_path, encoding='utf8') as f:
kv = Keyvalues.parse(f, conf_path)
opts.path = conf_path
opts.load(kv)
Expand Down Expand Up @@ -148,7 +148,7 @@ def parse(map_path: Path, game_folder: Optional[str]='') -> Config:
paths_conf_loc = opts.path.with_name(PATHS_NAME)
LOGGER.info('Paths config: {}', paths_conf_loc)
try:
with open(paths_conf_loc) as f:
with open(paths_conf_loc, encoding='utf8') as f:
for kv in Keyvalues.parse(f).find_children('Paths'):
if kv.has_children():
LOGGER.warning('Paths configs may not be blocks!')
Expand All @@ -162,7 +162,7 @@ def parse(map_path: Path, game_folder: Optional[str]='') -> Config:
)
path_roots[name] = Path(kv.value)
except FileNotFoundError:
with open(paths_conf_loc, 'w') as f:
with open(paths_conf_loc, 'w', encoding='utf8') as f:
f.write(PATHS_CONF_STARTER)

if not game_folder:
Expand Down
3 changes: 3 additions & 0 deletions src/hammeraddons/mdl_compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@

class GenModel(Generic[OutT]):
"""Tracks information about this model."""
name: str
used: bool
result: OutT
def __init__(self, mdl_name: str, result: OutT) -> None:
self.name = mdl_name # This is just the filename.
self.used = False
Expand Down
64 changes: 34 additions & 30 deletions src/hammeraddons/propcombine.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
import math
from typing import (
Callable, Dict, FrozenSet, Iterable, Iterator, List, Literal, MutableMapping, Optional, Set,
Tuple,
Union, Sequence,
Tuple, Union, Sequence,
)
from typing_extensions import TypeAlias, Unpack
from collections import defaultdict
from enum import Enum
from pathlib import Path
Expand Down Expand Up @@ -101,15 +101,15 @@ def unify_mdl(path: str) -> str:
"""Compute a 'canonical' path for a given model."""
path = path.casefold().replace('\\', '/').lstrip('/')
if not path.startswith('models/'):
path = 'models/' + path
path = f'models/{path}'
if not path.endswith(('.mdl', '.glb', '.gltf')):
path = path + '.mdl'
path = f'{path}.mdl'
return path


class CombineVolume:
"""Parsed comp_propcombine_* ents."""
def __init__(self, group_name: str, skinset: FrozenSet, origin: Vec) -> None:
def __init__(self, group_name: str, skinset: FrozenSet[str], origin: Vec) -> None:
self.group = group_name
self.skinset = skinset
# For sorting.
Expand Down Expand Up @@ -183,11 +183,15 @@ class PropPos:
solidity: CollType


# The types used during compilation.
PropCombiner = ModelCompiler[
# Function called to get info about a model.
LookupModel: TypeAlias = Callable[[str], Union[Tuple[QC, Model], Tuple[None, None]]]
# Key used to group props. None is an un-combinable prop. The first item is the skinset, all others
# are opaque values.
PropGroup: TypeAlias = Optional[Tuple[FrozenSet[str], Unpack[Tuple[object, ...]]]]
PropCombiner: TypeAlias = ModelCompiler[
Tuple[FrozenSet[PropPos], bool], # Key for deduplication.
# Additional parameters used during compile
Tuple[Callable[[str], Union[Tuple[QC, Model], Tuple[None, None]]], float],
Tuple[LookupModel, float],
# Result of the function
None,
]
Expand All @@ -196,7 +200,7 @@ class PropPos:
async def combine_group(
compiler: PropCombiner,
props: List[StaticProp],
lookup_model: Callable[[str], Union[Tuple[QC, Model], Tuple[None, None]]],
lookup_model: LookupModel,
volume_tolerance: float,
) -> StaticProp:
"""Merge the given props together, compiling a model if required."""
Expand Down Expand Up @@ -301,7 +305,7 @@ async def compile_func(
mdl_key: Tuple[FrozenSet[PropPos], bool],
temp_folder: Path,
mdl_name: str,
args: Tuple[Callable[[str], Union[Tuple[QC, Model], Tuple[None, None]]], float],
args: Tuple[LookupModel, float],
) -> None:
"""Build this merged model."""
LOGGER.info('Compiling {}...', mdl_name)
Expand Down Expand Up @@ -818,8 +822,8 @@ async def decompile_model(


def group_props_ent(
prop_groups: Dict[Optional[tuple], List[StaticProp]],
get_model: Callable[[str], Tuple[Optional[QC], Optional[Model]]],
prop_groups: Dict[PropGroup, List[StaticProp]],
get_model: LookupModel,
brush_models: MutableMapping[Entity, BModel],
grouper_ents: List[Entity],
min_cluster: int,
Expand Down Expand Up @@ -907,7 +911,7 @@ def group_props_ent(
else:
raise AssertionError(ent['classname'])

# We want to apply a ordering to groups, so smaller ones apply first, and
# We want to apply an ordering to groups, so smaller ones apply first, and
# filtered ones override all others.
for group_list in sets_by_skin.values():
group_list.sort(key=operator.attrgetter('volume'))
Expand Down Expand Up @@ -968,8 +972,8 @@ def group_props_ent(


def group_props_auto(
prop_groups: Dict[Optional[tuple], List[StaticProp]],
get_model: Callable[[str], Tuple[Optional[QC], Optional[Model]]],
prop_groups: Dict[PropGroup, List[StaticProp]],
get_model: LookupModel,
min_dist: float,
max_dist: float,
min_cluster: int,
Expand Down Expand Up @@ -1034,7 +1038,7 @@ def find_neighbours(start: StaticProp) -> Sequence[StaticProp]:

clusters: Dict[int, List[StaticProp]] = defaultdict(list)
for prop, key in labels.items():
if type(key) is int:
if isinstance(key, int):
clusters[key].append(prop)

# We now have many potential groups, which may be extremely large.
Expand Down Expand Up @@ -1095,18 +1099,18 @@ async def combine(
game: Game,
studiomdl_loc: Path,
*,
qc_folders: Optional[List[Path]]=None,
crowbar_loc: Optional[Path]=None,
decomp_cache_loc: Optional[Path]=None,
compile_dump: Optional[Path]=None,
blacklist: Iterable[str]=(),
min_auto_range: float=0.0,
max_auto_range: float=math.inf,
min_cluster: int=2,
min_cluster_auto: int=0,
volume_tolerance: float=1.0,
debug_dump: bool=False,
pack_models: bool=True,
qc_folders: Optional[List[Path]] = None,
crowbar_loc: Optional[Path] = None,
decomp_cache_loc: Optional[Path] = None,
compile_dump: Optional[Path] = None,
blacklist: Iterable[str] = (),
min_auto_range: float = 0.0,
max_auto_range: float = math.inf,
min_cluster: int = 2,
min_cluster_auto: int = 0,
volume_tolerance: float = 1.0,
debug_dump: bool = False,
pack_models: bool = True,
) -> None:
"""Combine props in this map."""
LOGGER.debug(
Expand Down Expand Up @@ -1205,7 +1209,7 @@ def get_model(filename: str) -> Union[Tuple[QC, Model], Tuple[None, None]]:
# Ignore this, we handle lighting origin ourselves.
relevant_flags = ~StaticPropFlags.HAS_LIGHTING_ORIGIN

def get_grouping_key(prop: StaticProp) -> Optional[tuple]:
def get_grouping_key(prop: StaticProp) -> PropGroup:
"""Compute a grouping key for this prop.
Only props with matching key can be possibly combined.
Expand Down Expand Up @@ -1235,7 +1239,7 @@ def get_grouping_key(prop: StaticProp) -> Optional[tuple]:
prop_count = 0

# First, construct groups of props that can possibly be combined.
prop_groups: Dict[Optional[tuple], List[StaticProp]] = defaultdict(list)
prop_groups: Dict[PropGroup, List[StaticProp]] = defaultdict(list)
for prop in bsp.props:
prop_groups[get_grouping_key(prop)].append(prop)
prop_count += 1
Expand Down
7 changes: 3 additions & 4 deletions src/hammeraddons/unify_fgd.py
Original file line number Diff line number Diff line change
Expand Up @@ -746,7 +746,7 @@ def action_count(
if 'ENGINE' in tags or kv.type is ValueTypes.SPAWNFLAGS:
continue
if kv.desc: # Blank is not a duplicate!
desc_counts[(kv.desc, )].append((ent.classname, name))
desc_counts[kv.desc, ].append((ent.classname, name))
kv_counts[
kv.name, kv.type, (tuple(kv.val_list) if kv.val_list is not None else ()), kv.desc, kv.default,
].append((ent.classname, name, kv.desc))
Expand Down Expand Up @@ -967,7 +967,7 @@ def action_import(
if not isinstance(helper, HelperExtAppliesTo)
]

with open(path, 'w') as f:
with open(path, 'w', encoding='utf8') as f:
ent.export(f)

print('.', end='', flush=True)
Expand Down Expand Up @@ -1295,8 +1295,7 @@ def action_export(
if as_binary:
with open(output_path, 'wb') as bin_f:
# Private, reserved for us.
# noinspection PyProtectedMember
from srctools._engine_db import serialise
from srctools._engine_db import serialise # noqa
serialise(fgd, bin_f)
else:
with open(output_path, 'w', encoding='iso-8859-1') as txt_f:
Expand Down

0 comments on commit dc550d3

Please sign in to comment.