These arguments can be used to indicate the inclusion or exclusion of
binary exclusive behaviors.
+
+ Raises:
+ ValueError: illegal argument value or combination
+
"""
def __init__(self, option_strings, dest, default=None, required=False, help=None):
v: data passed to an argument expecting a bool on the cmdline.
Returns:
- The boolean value of v or raises an ArgumentTypeError on error.
+ The boolean value of v
+
+ Raises:
+ ArgumentTypeError: parse error (e.g. not a valid bool string)
Sample usage::
ip: data passed to a commandline arg expecting an IP(v4) address.
Returns:
- The IP address, if valid. Raises ArgumentTypeError otherwise.
+ The IP address, if valid.
+
+ Raises:
+ ArgumentTypeError: parse error (e.g. not a valid IP address string)
Sample usage::
Returns:
The MAC address passed or raises ArgumentTypeError on error.
+ Raises:
+ ArgumentTypeError: parse error (e.g. not a valid MAC address)
+
Sample usage::
group.add_argument(
Returns:
The number if valid, otherwise raises ArgumentTypeError.
+ Raises:
+ ArgumentTypeError: parse error (e.g. not a valid percentage)
+
Sample usage::
args.add_argument(
Returns:
The filename if valid, otherwise raises ArgumentTypeError.
+ Raises:
+ ArgumentTypeError: parse error (e.g. file doesn't exist)
+
Sample usage::
args.add_argument(
Returns:
the datetime.date described by txt or raises ArgumentTypeError on error.
+ Raises:
+ ArgumentTypeError: parse error (e.g. date not valid)
+
Sample usage::
cfg.add_argument(
Returns:
The datetime.datetime described by txt or raises ArgumentTypeError on error.
+ Raises:
+ ArgumentTypeError: parse error (e.g. invalid datetime string)
+
Sample usage::
cfg.add_argument(
The datetime.timedelta described by txt or raises ArgumentTypeError
on error.
+ Raises:
+ ArgumentTypeError: parse error (e.g. invalid duration string)
+
Sample usage::
cfg.add_argument(
- plain numbers (123456)
- numbers with ISO suffixes (Mb, Gb, Pb, etc...)
- If the byte count is not parsable, raise an ArgumentTypeError.
-
Args:
txt: data passed to a commandline arg expecting a duration.
An integer number of bytes or raises ArgumentTypeError on
error.
+ Raises:
+ ArgumentTypeError: parse error (e.g. byte count not parsable)
+
Sample usage::
cfg.add_argument(
@staticmethod
def _assert_value_must_be_range(value: Any) -> NumericRange:
if not isinstance(value, NumericRange):
- raise Exception(
+ raise TypeError(
"AugmentedIntervalTree expects to use NumericRanges, see bst for a "
+ "general purpose tree usable for other types."
)
def __getitem__(self, item: Sequence[Any]) -> Dict[Any, Any]:
"""Given an item, return its trie node which contains all
- of the successor (child) node pointers. If the item is not
- a node in the Trie, raise a KeyError.
+ of the successor (child) node pointers.
Args:
item: the item whose node is to be retrieved
Returns:
the compressed bytes
+ Raises:
+ ValueError: uncompressed text contains illegal character
+
>>> import binascii
>>> binascii.hexlify(compress('this is a test'))
b'a2133da67b0ee859d0'
bits = ord(letter) - ord("a") + 1 # 1..26
else:
if letter not in special_characters:
- raise Exception(
+ raise ValueError(
f'"{uncompressed}" contains uncompressable char="{letter}"'
)
bits = special_characters[letter]
Otherwise False is returned.
+ Raises:
+ Exception: On error reading from zookeeper
+
>>> to_bool('True')
True
A dict containing the parsed program configuration. Note that this can
be safely ignored since it is also saved in `config.config` and may
be used directly using that identifier.
+
+ Raises:
+ Exception: if unrecognized config argument(s) are detected and the
+ --config_rejects_unrecognized_arguments argument is enabled.
"""
if self.config_parse_called:
return self.config
class RaisingErrorListener(antlr4.DiagnosticErrorListener):
- """An error listener that raises ParseExceptions."""
+ """An error listener that raises ParseExceptions.
+
+ Raises:
+ ParseException: on parse error
+ """
def syntaxError(self, recognizer, offendingSymbol, line, column, msg, e):
raise ParseException(msg)
A datetime.datetime representing the parsed date/time or
None on error.
+ Raises:
+ ParseException: an exception happened during parsing
+
.. note::
Parsed date expressions without any time part return
A datetime identical to dt, the input datetime, except for
that a timezone has been added.
+ Raises:
+ ValueError: if dt is already a timezone aware datetime.
+
.. warning::
This doesn't change the hour, minute, second, day, month, etc...
if is_timezone_aware(dt):
if dt.tzinfo == tz:
return dt
- raise Exception(
+ raise ValueError(
f"{dt} is already timezone aware; use replace_timezone or translate_timezone "
+ "depending on the semantics you want. See the pydocs / code."
)
base: a datetime representing the base date the result should be
relative to.
+ Raises:
+ ValueError: unit is invalid
+
Returns:
A datetime that is count units before of after the base datetime.
Returns:
The minute number requested. Raises `ValueError` on bad input.
+ Raises:
+ ValueError: invalid hour or minute input argument
+
>>> minute_number(0, 0)
0
Returns:
A count of seconds represented by the input string.
+ Raises:
+ ValueError: bad duration and raise_on_error is set.
+
>>> parse_duration('15 days, 2 hours')
1303200
`The Calendar FAQ: Easter <https://www.tondering.dk/claus/cal/easter.php>`_
+ Raises:
+ ValueError if method argument is invalid
+
"""
if not (1 <= method <= 3):
that we should stop calling or False to indicate a retry
is necessary
+ Raises:
+ ValueError: on invalid arguments; e.g. backoff must be >= 1.0,
+ delay_sec must be >= 0.0, tries must be > 0.
+
.. note::
If after `tries` attempts the wrapped function is still
probability_of_call: probability with which to invoke the
wrapped function. Must be 0 <= probabilty <= 1.0.
+ Raises:
+ ValueError: invalid probability of call arg
+
Example usage... this example would skip the invocation of
`log_the_entire_request_message` 95% of the time and only invoke
if 5% of the time.::
Returns:
A dict composed of zipping the keys list and values list together.
+ Raises:
+ ValueError: if keys and values lists not the same length.
+
>>> k = ['name', 'phone', 'address', 'zip']
>>> v = ['scott', '555-1212', '123 main st.', '12345']
>>> parallel_lists_to_dict(k, v)
{'name': 'scott', 'phone': '555-1212', 'address': '123 main st.', 'zip': '12345'}
"""
if len(keys) != len(values):
- raise Exception("Parallel keys and values lists must have the same length")
+ raise ValueError("Parallel keys and values lists must have the same length")
return dict(zip(keys, values))
exited. Raises `TimeoutExpired` after killing the subprocess
if the timeout expires.
+ Raises:
+ TimeoutExpired: if timeout expires before child terminates
+
Side effects:
prints all output of the child process (stdout or stderr)
"""
def cmd_exitcode(command: str, timeout_seconds: Optional[float] = None) -> int:
"""Run a command silently in the background and return its exit
- code once it has finished. If timeout_seconds is provided and the
- command runs longer than timeout_seconds, raise a `TimeoutExpired`
- exception.
+ code once it has finished.
Args:
command: the command to run
the exit status of the subprocess once the subprocess has
exited
+ Raises:
+ TimeoutExpired: if timeout_seconds is provided and the child process
+ executes longer than the limit.
+
>>> cmd_exitcode('/bin/echo foo', 10.0)
0
def run_silently(command: str, timeout_seconds: Optional[float] = None) -> None:
- """Run a command silently but raise
- `subprocess.CalledProcessError` if it fails (i.e. returns a
- non-zero return value) and raise a `TimeoutExpired` if it runs too
- long.
+ """Run a command silently.
Args:
command: the command to run.
No return value; error conditions (including non-zero child process
exits) produce exceptions.
+ Raises:
+ CalledProcessError: if the child process fails (i.e. exit != 0)
+ TimeoutExpired: if the child process executes too long.
+
>>> run_silently("/usr/bin/true")
>>> run_silently("/usr/bin/false")
content to-be-written is identical to the contents of the file on
disk allowing calling code to safely skip the write.
+ Raises:
+ ValueError: directory doesn't exist
+
>>> testfile = '/tmp/directory_filter_text_f39e5b58-c260-40da-9448-ad1c3b2a69c2.txt'
>>> contents = b'This is a test'
>>> with open(testfile, 'wb') as wf:
Returns:
A list of lines from the read and transformed file contents.
+
+ Raises:
+ Exception: filename not found or can't be read.
"""
ret = []
on_error: If set, it's invoked on error conditions and passed then
path and OSError that it caused.
+ Raises:
+ OSError: an exception occurred and on_error not set.
+
See also :meth:`does_file_exist`.
.. warning::
Note that this is required for zookeeper based locks.
override_command: don't use argv to determine our commandline
rather use this instead if provided.
+
+ Raises:
+ Exception: Zookeeper lock path without an expiration timestamp
"""
self.is_locked: bool = False
self.lockfile: str = ""
:meth:`bootstrap.initialize` decorator on your program's entry point,
it will call this for you. See :meth:`pyutils.bootstrap.initialize`
for more details.
+
+ Raises:
+ ValueError: if logging level is invalid
+
"""
global LOGGING_INITIALIZED
handles: if FILEHANDLES bit is set, this should be a list of
already opened filehandles you'd like to output into. The
handles will remain open after the scope of the multiplexer.
+
+ Raises:
+ ValueError: invalid combination of arguments (e.g. the filenames
+ argument is present but the filenames bit isn't set, the handle
+ argument is present but the handles bit isn't set, etc...)
"""
if logger is None:
logger = logging.getLogger(None)
return self.destination_bitv
def set_destination_bitv(self, destination_bitv: int):
- """Change the output destination_bitv to the one provided."""
+ """Change the output destination_bitv to the one provided.
+
+ Args:
+ destination_bitv: the new destination bitvector to set.
+
+ Raises:
+ ValueError: invalid combination of arguments (e.g. the filenames
+ argument is present but the filenames bit isn't set, the handle
+ argument is present but the handles bit isn't set, etc...)
+ """
if destination_bitv & self.Destination.FILENAMES and self.f is None:
raise ValueError("Filename argument is required if bitv & FILENAMES")
if destination_bitv & self.Destination.FILEHANDLES and self.h is None:
self.destination_bitv = destination_bitv
def print(self, *args, **kwargs):
- """Produce some output to all sinks."""
+ """Produce some output to all sinks. Use the same arguments as the
+ print-builtin.
+
+ Raises:
+ TypeError: Illegal argument types encountered
+ """
from pyutils.string_utils import _sprintf, strip_escape_sequences
end = kwargs.pop("end", None)
Args:
lst: a list of operands
+
+ Raises:
+ ValueError: if the list doesn't contain at least one number.
"""
if len(lst) <= 0:
raise ValueError("Need at least one number")
Returns:
True if n is prime and False otherwise.
+ Raises:
+ TypeError: if argument is not an into
+
.. note::
Obviously(?) very slow for very large input numbers until
@overrides
def submit(self, function: Callable, *args, **kwargs) -> fut.Future:
+ """
+ Raises:
+ Exception: executor is shutting down already.
+ """
if self.already_shutdown:
raise Exception('Submitted work after shutdown.')
self.adjust_task_count(+1)
@overrides
def submit(self, function: Callable, *args, **kwargs) -> fut.Future:
+ """
+ Raises:
+ Exception: executor is shutting down already.
+ """
if self.already_shutdown:
raise Exception('Submitted work after shutdown.')
start = time.time()
Args:
workers: A list of remote workers we can call on to do tasks.
policy: A policy for selecting remote workers for tasks.
+
+ Raises:
+ RemoteExecutorException: unable to find a place to schedule work.
"""
super().__init__()
self, bundle: BundleDetails
) -> Optional[fut.Future]:
"""Something unexpectedly failed with bundle. Either retry it
- from the beginning or throw in the towel and give up on it."""
+ from the beginning or throw in the towel and give up on it.
+
+ Raises:
+ RemoteExecutorException: a bundle fails repeatedly.
+ """
is_original = bundle.src_bundle is None
bundle.worker = None
@overrides
def submit(self, function: Callable, *args, **kwargs) -> fut.Future:
"""Submit work to be done. This is the user entry point of this
- class."""
+ class.
+
+ Raises:
+ Exception: executor is already shutting down.
+ """
if self.already_shutdown:
raise Exception('Submitted work after shutdown.')
pickle = _make_cloud_pickle(function, *args, **kwargs)
A thread can be joined many times.
- :meth:`join` raises a RuntimeError if an attempt is made to join the
- current thread as that would cause a deadlock. It is also an
- error to join a thread before it has been started and
- attempts to do so raises the same exception.
+ Raises:
+ RuntimeError: an attempt is made to join the current thread
+ as that would cause a deadlock. It is also an error to join
+ a thread before it has been started and attempts to do so
+ raises the same exception.
"""
threading.Thread.join(self, *args)
return self._return
yield token
def evaluate(corpus: Corpus, stack: List[str]):
+ """
+ Raises:
+ ParseError: bad number of operations, unbalanced parenthesis,
+ unknown operators, internal errors.
+ """
node_stack: List[Node] = []
for token in stack:
node = None
self.operands = operands
def eval(self) -> Set[str]:
- """Evaluate this node."""
+ """Evaluate this node.
+
+ Raises:
+ ParseError: unexpected operands, invalid key:value syntax, wrong
+ number of operands for operation, other invalid queries.
+ """
evaled_operands: List[Union[Set[str], str]] = []
for operand in self.operands:
default_answer: pass this argument to provide the ACL with a
default answer.
+ Raises:
+ ValueError: Invalid Order argument
+
.. note::
By using `order_to_check_allow_deny` and `default_answer` you
Order.ALLOW_DENY,
Order.DENY_ALLOW,
):
- raise Exception(
+ raise ValueError(
'order_to_check_allow_deny must be Order.ALLOW_DENY or '
+ 'Order.DENY_ALLOW'
)
True if the string contains a valid numberic value and
False otherwise.
+ Raises:
+ TypeError: the input argument isn't a string
+
See also :meth:`is_integer_number`, :meth:`is_decimal_number`,
:meth:`is_hexidecimal_integer_number`, :meth:`is_octal_integer_number`,
etc...
>>> is_number(100.5)
Traceback (most recent call last):
...
- ValueError: 100.5
+ TypeError: 100.5
>>> is_number("100.5")
True
>>> is_number("test")
>>> is_number([1, 2, 3])
Traceback (most recent call last):
...
- ValueError: [1, 2, 3]
+ TypeError: [1, 2, 3]
"""
if not is_string(in_str):
- raise ValueError(in_str)
+ raise TypeError(in_str)
return NUMBER_RE.match(in_str) is not None
Returns:
True if the string is a hex integer number and False otherwise.
+ Raises:
+ TypeError: the input argument isn't a string
+
See also :meth:`is_integer_number`, :meth:`is_decimal_number`,
:meth:`is_octal_integer_number`, :meth:`is_binary_integer_number`, etc...
>>> is_hexidecimal_integer_number(12345) # Not a string
Traceback (most recent call last):
...
- ValueError: 12345
+ TypeError: 12345
>>> is_hexidecimal_integer_number(101.4)
Traceback (most recent call last):
...
- ValueError: 101.4
+ TypeError: 101.4
>>> is_hexidecimal_integer_number(0x1A3E)
Traceback (most recent call last):
...
- ValueError: 6718
+ TypeError: 6718
"""
if not is_string(in_str):
- raise ValueError(in_str)
+ raise TypeError(in_str)
return HEX_NUMBER_RE.match(in_str) is not None
Returns:
True if the string is a valid octal integral number and False otherwise.
+ Raises:
+ TypeError: the input argument isn't a string
+
See also :meth:`is_integer_number`, :meth:`is_decimal_number`,
:meth:`is_hexidecimal_integer_number`, :meth:`is_binary_integer_number`,
etc...
False
"""
if not is_string(in_str):
- raise ValueError(in_str)
+ raise TypeError(in_str)
return OCT_NUMBER_RE.match(in_str) is not None
Returns:
True if the string contains a binary integral number and False otherwise.
+ Raises:
+ TypeError: the input argument isn't a string
+
See also :meth:`is_integer_number`, :meth:`is_decimal_number`,
:meth:`is_hexidecimal_integer_number`, :meth:`is_octal_integer_number`,
etc...
False
"""
if not is_string(in_str):
- raise ValueError(in_str)
+ raise TypeError(in_str)
return BIN_NUMBER_RE.match(in_str) is not None
Returns:
The integral value of the string or raises on error.
+ Raises:
+ TypeError: the input argument isn't a string
+
See also :meth:`is_integer_number`, :meth:`is_decimal_number`,
:meth:`is_hexidecimal_integer_number`, :meth:`is_octal_integer_number`,
:meth:`is_binary_integer_number`, etc...
Traceback (most recent call last):
...
ValueError: invalid literal for int() with base 10: 'test'
+ >>> to_int(123)
+ Traceback (most recent call last):
+ ...
+ TypeError: 123
"""
if not is_string(in_str):
- raise ValueError(in_str)
+ raise TypeError(in_str)
if is_binary_integer_number(in_str):
return int(in_str, 2)
if is_octal_integer_number(in_str):
Returns:
The integer whose value was parsed from in_str.
+ Raises:
+ ValueError: unable to parse a chunk of the number string
+
See also :meth:`integer_to_number_string`.
.. warning::
Returns:
A numeric string with thousands separators added appropriately.
+ Raises:
+ ValueError: a non-numeric string argument is presented
+
>>> add_thousands_separator('12345678')
'12,345,678'
>>> add_thousands_separator(12345678)
head = head.replace(" ", "")[1:-1]
return EMAIL_RE.match(head + "@" + tail) is not None
- except ValueError:
+ except (TypeError, ValueError):
# borderline case in which we have multiple "@" signs but the
# head part is correctly escaped.
if ESCAPED_AT_SIGN.search(in_str) is not None:
Returns:
True if in_str is a valid credit card number.
+ Raises:
+ KeyError: card_type is invalid
+
.. warning::
This code is not verifying the authenticity of the credit card (i.e.
not checking whether it's a real card that can be charged); rather
True if the given string contains HTML/XML tags and False
otherwise.
+ Raises:
+ TypeError: the input argument isn't a string
+
See also :meth:`strip_html`.
.. warning::
"""
if not is_string(in_str):
- raise ValueError(in_str)
+ raise TypeError(in_str)
return HTML_RE.search(in_str) is not None
Returns:
The number of words contained in the given string.
+ Raises:
+ TypeError: the input argument isn't a string
+
.. note::
This method is "smart" in that it does consider only sequences
of one or more letter and/or numbers to be "words". Thus a
4
"""
if not is_string(in_str):
- raise ValueError(in_str)
+ raise TypeError(in_str)
return len(WORDS_COUNT_RE.findall(in_str))
A string of the specified size containing random characters
(uppercase/lowercase ascii letters and digits).
+ Raises:
+ ValueError: size < 1
+
See also :meth:`asciify`, :meth:`generate_uuid`.
>>> random.seed(22)
Returns:
The reversed (chracter by character) string.
+ Raises:
+ TypeError: the input argument isn't a string
+
>>> reverse('test')
'tset'
"""
if not is_string(in_str):
- raise ValueError(in_str)
+ raise TypeError(in_str)
return in_str[::-1]
original string if it is not a valid camel case string or some
other error occurs.
+ Raises:
+ TypeError: the input argument isn't a string
+
See also :meth:`is_camel_case`, :meth:`is_snake_case`, and :meth:`is_slug`.
>>> camel_case_to_snake_case('MacAddressExtractorFactory')
'Luke Skywalker'
"""
if not is_string(in_str):
- raise ValueError(in_str)
+ raise TypeError(in_str)
if not is_camel_case(in_str):
return in_str
return CAMEL_CASE_REPLACE_RE.sub(lambda m: m.group(1) + separator, in_str).lower()
provided or the original string back again if it is not valid
snake case or another error occurs.
+ Raises:
+ TypeError: the input argument isn't a string
+
See also :meth:`is_camel_case`, :meth:`is_snake_case`, and :meth:`is_slug`.
>>> snake_case_to_camel_case('this_is_a_test')
'Han Solo'
"""
if not is_string(in_str):
- raise ValueError(in_str)
+ raise TypeError(in_str)
if not is_snake_case(in_str, separator=separator):
return in_str
tokens = [s.title() for s in in_str.split(separator) if is_full_string(s)]
A string with all HTML tags removed (optionally with tag contents
preserved).
+ Raises:
+ TypeError: the input argument isn't a string
+
See also :meth:`contains_html`.
.. note::
'test: click here'
"""
if not is_string(in_str):
- raise ValueError(in_str)
+ raise TypeError(in_str)
r = HTML_TAG_ONLY_RE if keep_tag_content else HTML_RE
return r.sub("", in_str)
by translating all non-ascii chars into their closest possible
ASCII representation (eg: ó -> o, Ë -> E, ç -> c...).
+ Raises:
+ TypeError: the input argument isn't a string
+
See also :meth:`to_ascii`, :meth:`generate_random_alphanumeric_string`.
.. warning::
'eeuuooaaeynAAACIINOE'
"""
if not is_string(in_str):
- raise ValueError(in_str)
+ raise TypeError(in_str)
# "NFKD" is the algorithm which is able to successfully translate
# the most of non-ascii chars.
* all chars are encoded as ascii (by using :meth:`asciify`)
* is safe for URL
+ Raises:
+ TypeError: the input argument isn't a string
+
See also :meth:`is_slug` and :meth:`asciify`.
>>> slugify('Top 10 Reasons To Love Dogs!!!')
'monster-magnet'
"""
if not is_string(in_str):
- raise ValueError(in_str)
+ raise TypeError(in_str)
# replace any character that is NOT letter or number with spaces
out = NO_LETTERS_OR_NUMBERS_RE.sub(" ", in_str.lower()).strip()
Otherwise False is returned.
+ Raises:
+ TypeError: the input argument isn't a string
+
See also :mod:`pyutils.argparse_utils`.
>>> to_bool('True')
True
"""
if not is_string(in_str):
- raise ValueError(in_str)
+ raise TypeError(in_str)
return in_str.lower() in set(["true", "1", "yes", "y", "t", "on"])
Returns:
An indented string created by prepending amount spaces.
+ Raises:
+ TypeError: the input argument isn't a string
+
See also :meth:`dedent`.
>>> indent('This is a test', 4)
' This is a test'
"""
if not is_string(in_str):
- raise ValueError(in_str)
+ raise TypeError(in_str)
line_separator = '\n'
lines = [" " * amount + line for line in in_str.split(line_separator)]
return line_separator.join(lines)
Returns:
txt encoded as an ASCII byte string.
+ Raises:
+ TypeError: the input argument isn't a string or bytes
+
See also :meth:`to_base64`, :meth:`to_bitstring`, :meth:`to_bytes`,
:meth:`generate_random_alphanumeric_string`, :meth:`asciify`.
return txt.encode('ascii')
if isinstance(txt, bytes):
return txt
- raise Exception('to_ascii works with strings and bytes')
+ raise TypeError('to_ascii works with strings and bytes')
def to_base64(
Returns:
The number of rows/columns on the current console or None
if we can't tell or an error occurred.
+
+ Raises:
+ Exception: if the console size can't be determined.
"""
from pyutils.exec_utils import cmd
left_end: the character at the left side of the graph
right_end: the character at the right side of the graph
+ Raises:
+ ValueError: if percentage is invalid
+
See also :meth:`bar_graph`, :meth:`sparkline`.
>>> bar_graph_string(5, 10, fgcolor='', reset_seq='')
* 'r' = right alignment
padding: the padding character to use while justifying
+ Raises:
+ ValueError: if alignment argument is invalid.
+
>>> justify_string('This is another test', width=40, alignment='c')
' This is another test '
>>> justify_string('This is another test', width=40, alignment='l')
else:
string = padding + string
else:
- raise ValueError
+ raise ValueError('alignment must be l, r, j, or c.')
return string
currency: optionally declare the currency being represented by
this instance. If provided it will guard against operations
such as attempting to add it to non-matching currencies.
- strict_mode: if True, the instance created will object if you
- compare or aggregate it with non-CentCount objects; that is,
+ strict_mode: if True, the instance created will object (raise) if
+ compared or aggregated with non-CentCount objects; that is,
strict_mode disallows comparison with literal numbers or
aggregation with literal numbers.
+
+ Raises:
+ ValueError: invalid money string passed in
"""
self.strict_mode = strict_mode
if isinstance(centcount, str):
ret = CentCount._parse(centcount)
if ret is None:
- raise Exception(f'Unable to parse money string "{centcount}"')
+ raise ValueError(f'Unable to parse money string "{centcount}"')
centcount = ret[0]
currency = ret[1]
if isinstance(centcount, float):
return CentCount(centcount=-self.centcount, currency=self.currency)
def __add__(self, other):
+ """
+ Raises:
+ TypeError: if addend is not compatible or the object is in strict
+ mode and the addend is not another CentCount.
+ """
if isinstance(other, CentCount):
if self.currency == other.currency:
return CentCount(
return self.__add__(CentCount(other, self.currency))
def __sub__(self, other):
+ """
+ Raises:
+ TypeError: if amount is not compatible or the object is in strict
+ mode and the amount is not another CentCount.
+ """
if isinstance(other, CentCount):
if self.currency == other.currency:
return CentCount(
def __mul__(self, other):
"""
+ Raises:
+ TypeError: if factor is not compatible.
+
.. note::
Multiplication and division are performed by converting the
def __truediv__(self, other):
"""
+ Raises:
+ TypeError: the divisor is not compatible
+
.. note::
Multiplication and division are performed by converting the
__radd__ = __add__
def __rsub__(self, other):
+ """
+ Raises:
+ TypeError: amount is not compatible or, if the object is in
+ strict mode, the amount is not a CentCount.
+ """
if isinstance(other, CentCount):
if self.currency == other.currency:
return CentCount(
# Override comparison operators to also compare currency.
#
def __eq__(self, other):
+ """
+ Raises:
+ TypeError: In strict mode and the other object isn't a CentCount.
+ """
if other is None:
return False
if isinstance(other, CentCount):
return not result
def __lt__(self, other):
+ """
+ Raises:
+ TypeError: amounts have different currencies or, if this object
+ is in strict mode, the amount must be a CentCount.
+ """
if isinstance(other, CentCount):
if self.currency == other.currency:
return self.centcount < other.centcount
return self.centcount < int(other)
def __gt__(self, other):
+ """
+ Raises:
+ TypeError: amounts have different currencies or, if this object
+ is in strict mode, the amount must be a CentCount.
+ """
if isinstance(other, CentCount):
if self.currency == other.currency:
return self.centcount > other.centcount
Args:
s: the string to be parsed
+
+ Raises:
+ ValueError: input string cannot be parsed.
"""
chunks = CentCount._parse(s)
if chunks is not None:
return CentCount(chunks[0], chunks[1])
- raise Exception(f'Unable to parse money string "{s}"')
+ raise ValueError(f'Unable to parse money string "{s}"')
if __name__ == "__main__":
buckets we are counting population in. See also
:meth:`n_evenly_spaced_buckets` to generate these
buckets more easily.
+
+ Raises:
+ ValueError: buckets overlap
"""
from pyutils.math_utils import NumericPopulation
self.buckets: Dict[Tuple[Bound, Bound], Count] = {}
for start_end in buckets:
if self._get_bucket(start_end[0]) is not None:
- raise Exception("Buckets overlap?!")
+ raise ValueError("Buckets overlap?!")
self.buckets[start_end] = 0
self.sigma: float = 0.0
self.stats: NumericPopulation = NumericPopulation()
Returns:
A list of bounds that define N evenly spaced buckets
+
+ Raises:
+ ValueError: min is not < max
"""
ret: List[Tuple[int, int]] = []
stride = int((max_bound - min_bound) / n)
if stride <= 0:
- raise Exception("Min must be < Max")
+ raise ValueError("Min must be < Max")
imax = math.ceil(max_bound)
imin = math.floor(min_bound)
for bucket_start in range(imin, imax, stride):
strict_mode: if True, disallows comparison or arithmetic operations
between Money instances and any non-Money types (e.g. literal
numbers).
+
+ Raises:
+ ValueError: unable to parse a money string
"""
self.strict_mode = strict_mode
if isinstance(amount, str):
ret = Money._parse(amount)
if ret is None:
- raise Exception(f'Unable to parse money string "{amount}"')
+ raise ValueError(f'Unable to parse money string "{amount}"')
amount = ret[0]
currency = ret[1]
if not isinstance(amount, Decimal):
return Money(amount=-self.amount, currency=self.currency)
def __add__(self, other):
+ """
+ Raises:
+ TypeError: attempt to add incompatible amounts or, if in strict
+ mode, attempt to add a Money with a literal.
+ """
if isinstance(other, Money):
if self.currency == other.currency:
return Money(amount=self.amount + other.amount, currency=self.currency)
)
def __sub__(self, other):
+ """
+ Raises:
+ TypeError: attempt to subtract incompatible amounts or, if in strict
+ mode, attempt to add a Money with a literal.
+ """
if isinstance(other, Money):
if self.currency == other.currency:
return Money(amount=self.amount - other.amount, currency=self.currency)
else:
- raise TypeError("Incompatible currencies in add expression")
+ raise TypeError("Incompatible currencies in sibtraction expression")
else:
if self.strict_mode:
- raise TypeError("In strict_mode only two moneys can be added")
+ raise TypeError("In strict_mode only two moneys can be subtracted")
else:
return Money(
amount=self.amount - Decimal(float(other)),
)
def __mul__(self, other):
+ """
+ Raises:
+ TypeError: attempt to multiply two Money objects.
+ """
if isinstance(other, Money):
raise TypeError("can not multiply monetary quantities")
else:
)
def __truediv__(self, other):
+ """
+ Raises:
+ TypeError: attempt to divide two Money objects.
+ """
if isinstance(other, Money):
raise TypeError("can not divide monetary quantities")
else:
__radd__ = __add__
def __rsub__(self, other):
+ """
+ Raises:
+ TypeError: attempt to subtract incompatible amounts or, if in strict
+ mode, attempt to add a Money with a literal.
+ """
if isinstance(other, Money):
if self.currency == other.currency:
return Money(amount=other.amount - self.amount, currency=self.currency)
# Override comparison operators to also compare currency.
#
def __eq__(self, other):
+ """
+ Raises:
+ TypeError: in strict mode, an attempt to compare a Money with a
+ non-Money object.
+ """
if other is None:
return False
if isinstance(other, Money):
return not result
def __lt__(self, other):
+ """
+ TypeError: attempt to compare incompatible amounts or, if in strict
+ mode, attempt to compare a Money with a literal.
+ """
if isinstance(other, Money):
if self.currency == other.currency:
return self.amount < other.amount
return self.amount < Decimal(float(other))
def __gt__(self, other):
+ """
+ TypeError: attempt to compare incompatible amounts or, if in strict
+ mode, attempt to compare a Money with a literal.
+ """
if isinstance(other, Money):
if self.currency == other.currency:
return self.amount > other.amount
Args:
s: the string to parse
+
+ Raises:
+ ValueError: unable to parse a string
"""
chunks = Money._parse(s)
if chunks is not None:
return Money(chunks[0], chunks[1])
- raise Exception(f'Unable to parse money string "{s}"')
+ raise ValueError(f'Unable to parse money string "{s}"')
if __name__ == "__main__":
def load(
cls: type[PicklingFileBasedPersistent],
) -> Optional[PicklingFileBasedPersistent]:
+ """
+ Raises:
+ Exception: failure to load from file.
+ """
filename = cls.get_filename()
if cls.should_we_load_data(filename):
logger.debug("Attempting to load state from %s", filename)
@overrides
def save(self) -> bool:
+ """
+ Raises:
+ Exception: failure to save to file.
+ """
filename = self.get_filename()
if self.should_we_save_data(filename):
logger.debug("Trying to save state in %s", filename)
@classmethod
@overrides
def load(cls: type[JsonFileBasedPersistent]) -> Optional[JsonFileBasedPersistent]:
+ """
+ Raises:
+ Exception: failure to load from file.
+ """
filename = cls.get_filename()
if cls.should_we_load_data(filename):
logger.debug("Trying to load state from %s", filename)
@overrides
def save(self) -> bool:
+ """
+ Raises:
+ Exception: failure to save to file.
+ """
filename = self.get_filename()
if self.should_we_save_data(filename):
logger.debug("Trying to save state in %s", filename)
percentage: provides the multiplier as a percentage
percent_change: provides the multiplier as a percent change to
the base amount
+
+ Raises:
+ ValueError: if more than one of percentage, percent_change and
+ multiplier is provided
"""
count = 0
if multiplier is not None:
self.multiplier = 1.0 + percent_change / 100
count += 1
if count != 1:
- raise Exception(
+ raise ValueError(
"Exactly one of percentage, percent_change or multiplier is required."
)
If the Optional[Type] argument is None, however, raise an
exception.
+ Raises:
+ AssertionError: the parameter is, indeed, of NoneType.
+
>>> x: Optional[bool] = True
>>> unwrap_optional(x)
True