Source code for encomp.misc
import ast
from types import UnionType
from typing import Any, TypeIs, cast, get_args, get_origin
import asttokens
from typeguard import check_type
[docs]
def isinstance_types[T](obj: Any, expected: type[T]) -> TypeIs[T]: # noqa: ANN401
from .units import Quantity
from .utypes import UnknownDimensionality
if get_origin(expected) is UnionType:
try:
return isinstance(obj, expected)
except TypeError:
return any(isinstance_types(obj, n) for n in get_args(expected))
if isinstance(obj, Quantity) and isinstance(expected, type) and (issubclass(expected, Quantity)): # pyright: ignore[reportUnnecessaryIsInstance]
if expected is Quantity:
return isinstance(obj, expected) # pyright: ignore[reportUnnecessaryIsInstance]
expected_dt = getattr(expected, "_dimensionality_type", None) # pyright: ignore[reportUnknownArgumentType]
expected_mt = getattr(expected, "_magnitude_type", None) # pyright: ignore[reportUnknownArgumentType]
if expected_dt == UnknownDimensionality:
if expected_mt is None:
return True
return isinstance_types(obj.m, expected_mt) # pyright: ignore[reportUnknownMemberType]
if expected_dt is not None and obj._dimensionality_type is not expected_dt: # pyright: ignore[reportPrivateUsage]
return False
return not (expected_mt is not None and not isinstance_types(obj.m, expected_mt)) # pyright: ignore[reportUnknownMemberType]
try:
check_type(obj, expected) # pyright: ignore[reportUnknownArgumentType]
return True
except Exception:
return False
[docs]
def grid_dimensions(N: int, nrows: int, ncols: int) -> tuple[int, int]:
"""
Returns image grid dimensions (rows and columns) based
on the total number of items ``N``.
Parameters
----------
N : int
Total number of items
nrows : int
Number or rows, -1 means determined by the number of items
ncols : int
Number of columns, -1 means determined by the number of items
Returns
-------
tuple[int, int]
Number of rows and columns for a grid that fits all items
"""
if nrows == -1 and ncols == -1:
# start with a square grid
nrows = ncols = int(N**0.5)
# increase the number of cols until all items fit in the grid
while nrows * ncols < N:
ncols += 1
return nrows, ncols
if nrows == -1:
nrows = N // ncols if N % ncols == 0 else N // ncols + 1
elif ncols == -1:
ncols = N // nrows if N % nrows == 0 else N // nrows + 1
else:
if nrows * ncols < N:
raise ValueError(f"{N} items cannot be placed in a {nrows} x {ncols} grid")
return nrows, ncols
[docs]
def name_assignments(src: str) -> list[tuple[str, str]]:
assigned_names: list[tuple[str, str]] = []
atok = asttokens.ASTTokens(src, parse=True)
if atok.tree is None:
return assigned_names
for node in ast.walk(atok.tree):
if hasattr(node, "lineno") and isinstance(node, ast.Assign) and isinstance(node.targets[0], ast.Name):
start = cast(int, node.first_token.startpos) # pyright: ignore[reportUnknownMemberType, reportAttributeAccessIssue]
end = cast(int, node.last_token.endpos) # pyright: ignore[reportUnknownMemberType, reportAttributeAccessIssue]
assignment_src = atok.text[start:end]
assigned_names.append((node.targets[0].id, assignment_src))
return assigned_names