From 2e8dd08f5f4f9624facf4d38ea6b276cc8131f56 Mon Sep 17 00:00:00 2001 From: Scott Gasch Date: Thu, 10 Feb 2022 14:52:14 -0800 Subject: [PATCH] More cleanup. --- ml/quick_label.py | 35 ++++++++++++++++++++++------------- type/centcount.py | 13 ++++++++----- type/locations.py | 6 +++++- type/money.py | 12 +++++++----- type/people.py | 6 +++++- type/rate.py | 8 +++++--- 6 files changed, 52 insertions(+), 28 deletions(-) diff --git a/ml/quick_label.py b/ml/quick_label.py index 7e0a6bf..da9a1d2 100644 --- a/ml/quick_label.py +++ b/ml/quick_label.py @@ -1,10 +1,13 @@ #!/usr/bin/env python3 +"""A helper to facilitate quick manual labeling of ML training data.""" + import glob import logging import os import warnings -from typing import Callable, List, NamedTuple, Optional, Set +from dataclasses import dataclass +from typing import Callable, List, Optional, Set import argparse_utils import config @@ -35,14 +38,18 @@ parser.add_argument( ) -class InputSpec(NamedTuple): - image_file_glob: Optional[str] - image_file_prepopulated_list: Optional[List[str]] - image_file_to_features_file: Callable[[str], str] - label: str - valid_keystrokes: List[str] - prompt: str - keystroke_to_label: Callable[[str], str] +@dataclass +class InputSpec: + """A wrapper around the input data we need to operate; should be + populated by the caller.""" + + image_file_glob: Optional[str] = None + image_file_prepopulated_list: Optional[List[str]] = None + image_file_to_features_file: Optional[Callable[[str], str]] = None + label: str = '' + valid_keystrokes: List[str] = [] + prompt: str = '' + keystroke_to_label: Optional[Callable[[str], str]] = None def read_skip_list() -> Set[str]: @@ -56,7 +63,7 @@ def read_skip_list() -> Set[str]: line = line[:-1] line.strip() ret.add(line) - logger.debug(f'Read {quick_skip_file} and found {len(ret)} entries.') + logger.debug('Read %s and found %d entries.', quick_skip_file, len(ret)) return ret @@ -68,7 +75,7 @@ def write_skip_list(skip_list) -> None: filename = filename.strip() if len(filename) > 0: f.write(f'{filename}\n') - logger.debug(f'Updated {quick_skip_file}') + logger.debug('Updated %s', quick_skip_file) def label(in_spec: InputSpec) -> None: @@ -85,8 +92,9 @@ def label(in_spec: InputSpec) -> None: skip_list = read_skip_list() for image in images: if image in skip_list: - logger.debug(f'Skipping {image} because of the skip list') + logger.debug('Skipping %s because of the skip list', image) continue + assert in_spec.image_file_to_features_file features = in_spec.image_file_to_features_file(image) if features is None or not os.path.exists(features): msg = f'File {image} yielded file {features} which does not exist, SKIPPING.' @@ -114,9 +122,10 @@ def label(in_spec: InputSpec) -> None: prompt=in_spec.prompt, ) os.system('killall xv') + assert in_spec.keystroke_to_label label_value = in_spec.keystroke_to_label(keystroke) filtered_lines.append(f"{in_spec.label}: {label_value}\n") with open(features, 'w') as f: - f.writelines("%s\n" % line for line in filtered_lines) + f.writelines(line + '\n' for line in filtered_lines) skip_list.add(image) write_skip_list(skip_list) diff --git a/type/centcount.py b/type/centcount.py index 2cb99e0..4529695 100644 --- a/type/centcount.py +++ b/type/centcount.py @@ -1,7 +1,10 @@ #!/usr/bin/env python3 +"""An amount of money (USD) represented as an integral count of +cents.""" + import re -from typing import Optional, Tuple, TypeVar +from typing import Optional, Tuple import math_utils @@ -36,9 +39,9 @@ class CentCount(object): a = round(a, 2) s = f'{a:,.2f}' if self.currency is not None: - return '%s %s' % (s, self.currency) + return f'{s} {self.currency}' else: - return '$%s' % s + return f'${s}' def __pos__(self): return CentCount(centcount=self.centcount, currency=self.currency) @@ -181,8 +184,8 @@ class CentCount(object): def __ge__(self, other): return self > other or self == other - def __hash__(self): - return self.__repr__ + def __hash__(self) -> int: + return hash(self.__repr__) CENTCOUNT_RE = re.compile(r"^([+|-]?)(\d+)(\.\d+)$") CURRENCY_RE = re.compile(r"^[A-Z][A-Z][A-Z]$") diff --git a/type/locations.py b/type/locations.py index 24ab063..718a5f1 100644 --- a/type/locations.py +++ b/type/locations.py @@ -1,10 +1,14 @@ #!/usr/bin/env python3 +"""An enum to represent locations.""" + import enum @enum.unique -class Location(enum.Enum): +class Location(enum.IntEnum): + """An enum to represent locations.""" + UNKNOWN = 0 HOUSE = 1 CABIN = 2 diff --git a/type/money.py b/type/money.py index 39557aa..b84652b 100644 --- a/type/money.py +++ b/type/money.py @@ -1,8 +1,10 @@ #!/usr/bin/env python3 +"""A class to represent money. See also centcount.py""" + import re from decimal import Decimal -from typing import Optional, Tuple, TypeVar +from typing import Optional, Tuple import math_utils @@ -39,9 +41,9 @@ class Money(object): a = round(a, 2) s = f'{a:,.2f}' if self.currency is not None: - return '%s %s' % (s, self.currency) + return f'{s} {self.currency}' else: - return '$%s' % s + return f'${s}' def __pos__(self): return Money(amount=self.amount, currency=self.currency) @@ -178,8 +180,8 @@ class Money(object): def __ge__(self, other): return self > other or self == other - def __hash__(self): - return self.__repr__ + def __hash__(self) -> int: + return hash(self.__repr__) AMOUNT_RE = re.compile(r"^([+|-]?)(\d+)(\.\d+)$") CURRENCY_RE = re.compile(r"^[A-Z][A-Z][A-Z]$") diff --git a/type/people.py b/type/people.py index 1230db2..3a6f743 100644 --- a/type/people.py +++ b/type/people.py @@ -1,9 +1,13 @@ #!/usr/bin/env python3 +"""An enum to represent people.""" + import enum -class Person(enum.Enum): +class Person(enum.IntEnum): + """An enum to represent people.""" + UNKNOWN = 0 SCOTT = 1 LYNN = 2 diff --git a/type/rate.py b/type/rate.py index 64a4726..c365848 100644 --- a/type/rate.py +++ b/type/rate.py @@ -1,9 +1,13 @@ #!/usr/bin/env python3 +"""A class to represent a rate of change.""" + from typing import Optional class Rate(object): + """A class to represent a rate of change.""" + def __init__( self, multiplier: Optional[float] = None, @@ -28,9 +32,7 @@ class Rate(object): self.multiplier = 1.0 + percent_change / 100 count += 1 if count != 1: - raise Exception( - 'Exactly one of percentage, percent_change or multiplier is required.' - ) + raise Exception('Exactly one of percentage, percent_change or multiplier is required.') def apply_to(self, other): return self.__mul__(other) -- 2.45.2