ruff: enable FBT rules to detect boolean arguments use without kwargs

This commit is contained in:
Dima Gerasimov 2024-08-27 23:37:17 +01:00 committed by karlicoss
parent 118c2d4484
commit 664c40e3e8
19 changed files with 50 additions and 39 deletions

View file

@ -7,7 +7,7 @@ class Combine:
self.modules = modules self.modules = modules
@cdf @cdf
def dataframe(self, with_temperature: bool=True) -> DataFrameT: def dataframe(self, *, with_temperature: bool=True) -> DataFrameT:
import pandas as pd import pandas as pd
# todo include 'source'? # todo include 'source'?
df = pd.concat([m.dataframe() for m in self.modules]) df = pd.concat([m.dataframe() for m in self.modules])

View file

@ -438,7 +438,7 @@ def _ui_getchar_pick(choices: Sequence[str], prompt: str = 'Select from: ') -> i
return result_map[ch] return result_map[ch]
def _locate_functions_or_prompt(qualified_names: List[str], prompt: bool = True) -> Iterable[Callable[..., Any]]: def _locate_functions_or_prompt(qualified_names: List[str], *, prompt: bool = True) -> Iterable[Callable[..., Any]]:
from .query import QueryException, locate_qualified_function from .query import QueryException, locate_qualified_function
from .stats import is_data_provider from .stats import is_data_provider
@ -588,7 +588,7 @@ def query_hpi_functions(
@click.group() @click.group()
@click.option("--debug", is_flag=True, default=False, help="Show debug logs") @click.option("--debug", is_flag=True, default=False, help="Show debug logs")
def main(debug: bool) -> None: def main(*, debug: bool) -> None:
''' '''
Human Programming Interface Human Programming Interface
@ -637,7 +637,7 @@ def _module_autocomplete(ctx: click.Context, args: Sequence[str], incomplete: st
@click.option('-q', '--quick', is_flag=True, help='Only run partial checks (first 100 items)') @click.option('-q', '--quick', is_flag=True, help='Only run partial checks (first 100 items)')
@click.option('-S', '--skip-config-check', 'skip_conf', is_flag=True, help='Skip configuration check') @click.option('-S', '--skip-config-check', 'skip_conf', is_flag=True, help='Skip configuration check')
@click.argument('MODULE', nargs=-1, required=False, shell_complete=_module_autocomplete) @click.argument('MODULE', nargs=-1, required=False, shell_complete=_module_autocomplete)
def doctor_cmd(verbose: bool, list_all: bool, quick: bool, skip_conf: bool, module: Sequence[str]) -> None: def doctor_cmd(*, verbose: bool, list_all: bool, quick: bool, skip_conf: bool, module: Sequence[str]) -> None:
''' '''
Run various checks Run various checks
@ -671,7 +671,7 @@ def config_create_cmd() -> None:
@main.command(name='modules', short_help='list available modules') @main.command(name='modules', short_help='list available modules')
@click.option('--all', 'list_all', is_flag=True, help='List all modules, including disabled') @click.option('--all', 'list_all', is_flag=True, help='List all modules, including disabled')
def module_cmd(list_all: bool) -> None: def module_cmd(*, list_all: bool) -> None:
'''List available modules''' '''List available modules'''
list_modules(list_all=list_all) list_modules(list_all=list_all)
@ -684,7 +684,7 @@ def module_grp() -> None:
@module_grp.command(name='requires', short_help='print module reqs') @module_grp.command(name='requires', short_help='print module reqs')
@click.argument('MODULES', shell_complete=_module_autocomplete, nargs=-1, required=True) @click.argument('MODULES', shell_complete=_module_autocomplete, nargs=-1, required=True)
def module_requires_cmd(modules: Sequence[str]) -> None: def module_requires_cmd(*, modules: Sequence[str]) -> None:
''' '''
Print MODULES requirements Print MODULES requirements
@ -701,7 +701,7 @@ def module_requires_cmd(modules: Sequence[str]) -> None:
is_flag=True, is_flag=True,
help='Bypass PEP 668 and install dependencies into the system-wide python package directory.') help='Bypass PEP 668 and install dependencies into the system-wide python package directory.')
@click.argument('MODULES', shell_complete=_module_autocomplete, nargs=-1, required=True) @click.argument('MODULES', shell_complete=_module_autocomplete, nargs=-1, required=True)
def module_install_cmd(user: bool, parallel: bool, break_system_packages: bool, modules: Sequence[str]) -> None: def module_install_cmd(*, user: bool, parallel: bool, break_system_packages: bool, modules: Sequence[str]) -> None:
''' '''
Install dependencies for modules using pip Install dependencies for modules using pip
@ -782,6 +782,7 @@ def module_install_cmd(user: bool, parallel: bool, break_system_packages: bool,
help='ignore any errors returned as objects from the functions') help='ignore any errors returned as objects from the functions')
@click.argument('FUNCTION_NAME', nargs=-1, required=True, shell_complete=_module_autocomplete) @click.argument('FUNCTION_NAME', nargs=-1, required=True, shell_complete=_module_autocomplete)
def query_cmd( def query_cmd(
*,
function_name: Sequence[str], function_name: Sequence[str],
output: str, output: str,
stream: bool, stream: bool,

View file

@ -26,10 +26,11 @@ Paths = Union[Sequence[PathIsh], PathIsh]
DEFAULT_GLOB = '*' DEFAULT_GLOB = '*'
def get_files( def get_files(
pp: Paths, pp: Paths,
glob: str=DEFAULT_GLOB, glob: str=DEFAULT_GLOB,
sort: bool=True, *,
guess_compression: bool=True, sort: bool=True,
guess_compression: bool=True,
) -> Tuple[Path, ...]: ) -> Tuple[Path, ...]:
""" """
Helper function to avoid boilerplate. Helper function to avoid boilerplate.

View file

@ -96,6 +96,7 @@ class DenyList:
def filter( def filter(
self, self,
itr: Iterator[T], itr: Iterator[T],
*,
invert: bool = False, invert: bool = False,
) -> Iterator[T]: ) -> Iterator[T]:
denyf = functools.partial(self._allow, deny_map=self.load()) denyf = functools.partial(self._allow, deny_map=self.load())
@ -103,7 +104,7 @@ class DenyList:
return filter(lambda x: not denyf(x), itr) return filter(lambda x: not denyf(x), itr)
return filter(denyf, itr) return filter(denyf, itr)
def deny(self, key: str, value: Any, write: bool = False) -> None: def deny(self, key: str, value: Any, *, write: bool = False) -> None:
''' '''
add a key/value pair to the denylist add a key/value pair to the denylist
''' '''
@ -111,7 +112,7 @@ class DenyList:
self._load() self._load()
self._deny_raw({key: self._stringify_value(value)}, write=write) self._deny_raw({key: self._stringify_value(value)}, write=write)
def _deny_raw(self, data: Dict[str, Any], write: bool = False) -> None: def _deny_raw(self, data: Dict[str, Any], *, write: bool = False) -> None:
self._deny_raw_list.append(data) self._deny_raw_list.append(data)
if write: if write:
self.write() self.write()

View file

@ -135,7 +135,7 @@ def main() -> None:
@main.command(name='populate', short_help='populate influxdb') @main.command(name='populate', short_help='populate influxdb')
@click.option('--reset', is_flag=True, help='Reset Influx measurements before inserting', show_default=True) @click.option('--reset', is_flag=True, help='Reset Influx measurements before inserting', show_default=True)
@click.argument('FUNCTION_NAME', type=str, required=True) @click.argument('FUNCTION_NAME', type=str, required=True)
def populate(function_name: str, reset: bool) -> None: def populate(*, function_name: str, reset: bool) -> None:
from .__main__ import _locate_functions_or_prompt from .__main__ import _locate_functions_or_prompt
[provider] = list(_locate_functions_or_prompt([function_name])) [provider] = list(_locate_functions_or_prompt([function_name]))
# todo could have a non-interactive version which populates from all data sources for the provider? # todo could have a non-interactive version which populates from all data sources for the provider?

View file

@ -131,7 +131,7 @@ class UnconsumedError(Exception):
# TODO think about error policy later... # TODO think about error policy later...
@contextmanager @contextmanager
def wrap(j, throw=True) -> Iterator[Zoomable]: def wrap(j, *, throw=True) -> Iterator[Zoomable]:
w, children = _wrap(j) w, children = _wrap(j)
yield w yield w

View file

@ -131,11 +131,12 @@ def attribute_func(obj: T, where: Where, default: Optional[U] = None) -> Optiona
def _generate_order_by_func( def _generate_order_by_func(
obj_res: Res[T], obj_res: Res[T],
key: Optional[str] = None, *,
where_function: Optional[Where] = None, key: Optional[str] = None,
default: Optional[U] = None, where_function: Optional[Where] = None,
force_unsortable: bool = False, default: Optional[U] = None,
force_unsortable: bool = False,
) -> Optional[OrderFunc]: ) -> Optional[OrderFunc]:
""" """
Accepts an object Res[T] (Instance of some class or Exception) Accepts an object Res[T] (Instance of some class or Exception)
@ -274,6 +275,7 @@ def _wrap_unsorted(itr: Iterator[ET], orderfunc: OrderFunc) -> Tuple[Iterator[Un
# the second being items for which orderfunc returned a non-none value # the second being items for which orderfunc returned a non-none value
def _handle_unsorted( def _handle_unsorted(
itr: Iterator[ET], itr: Iterator[ET],
*,
orderfunc: OrderFunc, orderfunc: OrderFunc,
drop_unsorted: bool, drop_unsorted: bool,
wrap_unsorted: bool wrap_unsorted: bool
@ -503,7 +505,12 @@ Will attempt to call iter() on the value""")
# note: can't just attach sort unsortable values in the same iterable as the # note: can't just attach sort unsortable values in the same iterable as the
# other items because they don't have any lookups for order_key or functions # other items because they don't have any lookups for order_key or functions
# to handle items in the order_by_lookup dictionary # to handle items in the order_by_lookup dictionary
unsortable, itr = _handle_unsorted(itr, order_by_chosen, drop_unsorted, wrap_unsorted) unsortable, itr = _handle_unsorted(
itr,
orderfunc=order_by_chosen,
drop_unsorted=drop_unsorted,
wrap_unsorted=wrap_unsorted,
)
# run the sort, with the computed order by function # run the sort, with the computed order by function
itr = iter(sorted(itr, key=order_by_chosen, reverse=reverse)) # type: ignore[arg-type] itr = iter(sorted(itr, key=order_by_chosen, reverse=reverse)) # type: ignore[arg-type]

View file

@ -30,7 +30,7 @@ Stats = Dict[str, Any]
class StatsFun(Protocol): class StatsFun(Protocol):
def __call__(self, quick: bool = False) -> Stats: ... def __call__(self, *, quick: bool = False) -> Stats: ...
# global state that turns on/off quick stats # global state that turns on/off quick stats
@ -176,7 +176,7 @@ def guess_stats(module: ModuleType) -> Optional[StatsFun]:
if len(providers) == 0: if len(providers) == 0:
return None return None
def auto_stats(quick: bool = False) -> Stats: def auto_stats(*, quick: bool = False) -> Stats:
res = {} res = {}
for k, v in providers.items(): for k, v in providers.items():
res.update(stat(v, quick=quick, name=k)) res.update(stat(v, quick=quick, name=k))
@ -355,7 +355,7 @@ def _stat_item(item):
return _guess_datetime(item) return _guess_datetime(item)
def _stat_iterable(it: Iterable[Any], quick: bool = False) -> Stats: def _stat_iterable(it: Iterable[Any], *, quick: bool = False) -> Stats:
from more_itertools import first, ilen, take from more_itertools import first, ilen, take
# todo not sure if there is something in more_itertools to compute this? # todo not sure if there is something in more_itertools to compute this?

View file

@ -12,7 +12,7 @@ from .logging import make_logger
logger = make_logger(__name__, level="info") logger = make_logger(__name__, level="info")
def _structure_exists(base_dir: Path, paths: Sequence[str], partial: bool = False) -> bool: def _structure_exists(base_dir: Path, paths: Sequence[str], *, partial: bool = False) -> bool:
""" """
Helper function for match_structure to check if Helper function for match_structure to check if
all subpaths exist at some base directory all subpaths exist at some base directory

View file

@ -47,5 +47,5 @@ class DummyExecutor(Executor):
return f return f
def shutdown(self, wait: bool = True, **kwargs) -> None: def shutdown(self, wait: bool = True, **kwargs) -> None: # noqa: FBT001,FBT002
self._shutdown = True self._shutdown = True

View file

@ -44,7 +44,7 @@ def workouts() -> Iterable[Res[Workout]]:
from .core.pandas import check_dataframe, DataFrameT from .core.pandas import check_dataframe, DataFrameT
@check_dataframe @check_dataframe
def dataframe(defensive: bool=True) -> DataFrameT: def dataframe(*, defensive: bool=True) -> DataFrameT:
def it(): def it():
for w in workouts(): for w in workouts():
if isinstance(w, Exception): if isinstance(w, Exception):

View file

@ -91,7 +91,7 @@ def _cachew_depends_on() -> List[str]:
# ResultsType is a Union of all of the models in google_takeout_parser # ResultsType is a Union of all of the models in google_takeout_parser
@mcachew(depends_on=_cachew_depends_on, logger=logger, force_file=True) @mcachew(depends_on=_cachew_depends_on, logger=logger, force_file=True)
def events(disable_takeout_cache: bool = DISABLE_TAKEOUT_CACHE) -> CacheResults: def events(disable_takeout_cache: bool = DISABLE_TAKEOUT_CACHE) -> CacheResults: # noqa: FBT001
error_policy = config.error_policy error_policy = config.error_policy
count = 0 count = 0
emitted = GoogleEventSet() emitted = GoogleEventSet()

View file

@ -174,7 +174,7 @@ def hhmm(time: datetime):
# return fromstart / tick # return fromstart / tick
def plot_one(sleep: SleepEntry, fig, axes, xlims=None, showtext=True): def plot_one(sleep: SleepEntry, fig, axes, xlims=None, *, showtext=True):
import matplotlib.dates as mdates # type: ignore[import-not-found] import matplotlib.dates as mdates # type: ignore[import-not-found]
span = sleep.completed - sleep.created span = sleep.completed - sleep.created

View file

@ -24,7 +24,7 @@ def fallback_estimators() -> Iterator[LocationEstimator]:
yield _home_estimate yield _home_estimate
def estimate_location(dt: DateExact, first_match: bool=False, under_accuracy: Optional[int] = None) -> FallbackLocation: def estimate_location(dt: DateExact, *, first_match: bool=False, under_accuracy: Optional[int] = None) -> FallbackLocation:
loc = estimate_from(dt, estimators=list(fallback_estimators()), first_match=first_match, under_accuracy=under_accuracy) loc = estimate_from(dt, estimators=list(fallback_estimators()), first_match=first_match, under_accuracy=under_accuracy)
# should never happen if the user has home configured # should never happen if the user has home configured
if loc is None: if loc is None:

View file

@ -18,7 +18,7 @@ class FallbackLocation(LocationProtocol):
elevation: Optional[float] = None elevation: Optional[float] = None
datasource: Optional[str] = None # which module provided this, useful for debugging datasource: Optional[str] = None # which module provided this, useful for debugging
def to_location(self, end: bool = False) -> Location: def to_location(self, *, end: bool = False) -> Location:
''' '''
by default the start date is used for the location by default the start date is used for the location
If end is True, the start date + duration is used If end is True, the start date + duration is used

View file

@ -18,7 +18,7 @@ def getzone(dt: datetime) -> str:
@pytest.mark.parametrize('fast', [False, True]) @pytest.mark.parametrize('fast', [False, True])
def test_iter_tzs(fast: bool, config) -> None: def test_iter_tzs(*, fast: bool, config) -> None:
# TODO hmm.. maybe need to make sure we start with empty config? # TODO hmm.. maybe need to make sure we start with empty config?
config.time.tz.via_location.fast = fast config.time.tz.via_location.fast = fast

View file

@ -94,7 +94,7 @@ logger = make_logger(__name__)
@lru_cache(None) @lru_cache(None)
def _timezone_finder(fast: bool) -> Any: def _timezone_finder(*, fast: bool) -> Any:
if fast: if fast:
# less precise, but faster # less precise, but faster
from timezonefinder import TimezoneFinderL as Finder from timezonefinder import TimezoneFinderL as Finder
@ -304,7 +304,7 @@ def localize(dt: datetime) -> datetime_aware:
return tz.localize(dt) return tz.localize(dt)
def stats(quick: bool = False) -> Stats: def stats(*, quick: bool = False) -> Stats:
if quick: if quick:
prev, config.sort_locations = config.sort_locations, False prev, config.sort_locations = config.sort_locations, False
res = {'first': next(_iter_local_dates())} res = {'first': next(_iter_local_dates())}

View file

@ -58,7 +58,7 @@ def _parse_one(p: Path) -> Iterator[Res[Competition]]:
h.pop_if_primitive('version', 'id') h.pop_if_primitive('version', 'id')
h = h.zoom('result') h = h.zoom('result')
h.check('success', True) h.check('success', expected=True)
h.check('status', 200) h.check('status', 200)
h.pop_if_primitive('metadata') h.pop_if_primitive('metadata')

View file

@ -1,10 +1,11 @@
target-version = "py38" # NOTE: inferred from pyproject.toml if present target-version = "py38" # NOTE: inferred from pyproject.toml if present
lint.extend-select = [ lint.extend-select = [
"F", # flakes rules -- default, but extend just in case "F", # flakes rules -- default, but extend just in case
"E", # pycodestyle -- default, but extend just in case "E", # pycodestyle -- default, but extend just in case
"C4", # flake8-comprehensions -- unnecessary list/map/dict calls "C4", # flake8-comprehensions -- unnecessary list/map/dict calls
"UP", # detect deprecated python stdlib stuff "UP", # detect deprecated python stdlib stuff
"FBT", # detect use of boolean arguments
] ]
lint.ignore = [ lint.ignore = [