Skip to content

Commit

Permalink
Reformulated exceptions.
Browse files Browse the repository at this point in the history
  • Loading branch information
Ken Kundert authored and Ken Kundert committed Nov 17, 2018
1 parent 3c4f00c commit 550a907
Show file tree
Hide file tree
Showing 8 changed files with 512 additions and 119 deletions.
1 change: 1 addition & 0 deletions clean
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ rm -rf generated_settings
rm -rf .cache

# the rest is common to all python directories
rm -f *.pyc *.pyo
rm -f .test*.sum expected result install.out .*.log
rm -rf build *.egg-info dist __pycache__ .eggs **/{__pycache__,*.pyc,*.pyo}
rm -rf .coverage .coverage-html htmlcov
Expand Down
16 changes: 16 additions & 0 deletions doc/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,19 @@ Constants and Unit Systems
.. autofunction:: quantiphy.add_constant

.. autofunction:: quantiphy.set_unit_system


Exceptions
==========

.. autoclass:: quantiphy.QuantiPhyError
.. autoclass:: quantiphy.ExpectedQuantity
.. autoclass:: quantiphy.IncompatibleUnits
.. autoclass:: quantiphy.InvalidNumber
.. autoclass:: quantiphy.InvalidRecognizer
.. autoclass:: quantiphy.MissingName
.. autoclass:: quantiphy.UnknownConversion
.. autoclass:: quantiphy.UnknownFormatKey
.. autoclass:: quantiphy.UnknownPreference
.. autoclass:: quantiphy.UnknownScaleFactor
.. autoclass:: quantiphy.UnknownUnitSystem
4 changes: 2 additions & 2 deletions doc/examples.rst
Original file line number Diff line number Diff line change
Expand Up @@ -566,7 +566,7 @@ to date.
levels = 4 -- quantizer output levels
Tstop = 1/Fin "s" -- simulation stop time
Tstart = -0.5/Fin "s" -- simulation start time (points with t<0 are discarded)
vin_file = 'vin.data' -- output data file for vin
vin_file = 'vin.wave' -- output data file for vin
vout_file = 'vout.wave' -- output data file for vout
dout_file = 'dout.wave' -- output data file for dout
Expand All @@ -584,7 +584,7 @@ to date.
self.gain = gain
def update(self, vin):
self.state += vin
self.state += self.gain*vin
return self.state
Expand Down
151 changes: 124 additions & 27 deletions doc/user.rst
Original file line number Diff line number Diff line change
Expand Up @@ -624,6 +624,19 @@ a quantity and then uses the sum to create a new Quantity. For example:
>>> print(total)
$13.68
When adding quantities, the units of the quantity should match. You can enforce
this by adding *check_units=True*. If the dimension of your quantities match but
not the units, you can often use :meth:`quantiphy.Quantity.scale` to get the
units right::

.. code-block:: python
>>> m1 = Quantity('1kg')
>>> m2 = Quantity('1lb')
>>> m3 = m1.add(m2.scale('g'), check_units=True)
>>> print(m3)
1.4536 kg
Accessing Quantity Values
.........................
Expand Down Expand Up @@ -1859,43 +1872,127 @@ using :meth:`quantiphy.Quantity.is_infinite()` or
Exceptions
----------

A *ValueError* is raised if :class:`quantiphy.Quantity` is passed a string it
cannot convert into a number:
The way exceptions are defined in *QuantiPhy* has changed. Initially, the
standard Python exceptions were used to indicate errors. For example,
a *ValueError* was raised by :class:`quantiphy.Quantity` if it were passed
a string it cannot convert into a number. Now, a variety of *QuantiPhy*
specific exceptions are used to indicate specific errors. However, these
exceptions subclass the corresponding Python error for compatibility with
existing code. It is recommended that new code catch the *QuantiPhy* specific
exceptions rather than the generic Python exceptions as their use may be
deprecated in the future.

.. code-block:: python
*QuantiPhy* employs the following exceptions:

>>> try:
... q = Quantity('g')
... except ValueError as e:
... print(e)
g: not a valid number.
:class:`quantiphy.ExpectedQuantity`:
Subclass of :class:`quantiphy.QuantiPhyError` and *ValueError*. Used by
:func:`quantiphy.add_constant()`.

A *KeyError* is raised if a unit conversion is requested but no suitable unit
converter is available.
Raised when the value is either not an instance of
:class:`quantiphy.Quantity` or a string that can be converted to a quantity.

.. code-block:: python
:class:`quantiphy.IncompatibleUnits`:
Subclass of :class:`quantiphy.QuantiPhyError` and *TypeError*. Used by
:meth:`quantiphy.Quantity.add()`.

>>> q = Quantity('93 Mmi', scale='pc')
Traceback (most recent call last):
...
KeyError: "Unable to convert between 'pc' and 'mi'."
Raised when the units of contribution do not match those of underlying
quantity.

A *KeyError* is also raised if you specify an unknown preference.
:class:`quantiphy.InvalidNumber`:
Subclass of :class:`quantiphy.QuantiPhyError`, *ValueError*, and
*TypeError*. Used by :class:`quantiphy.Quantity()`.

.. code-block:: python
Raised if the value given could not be converted to a number.

:class:`quantiphy.InvalidRecognizer`:
Subclass of :class:`quantiphy.QuantiPhyError` and *KeyError*. Used by
:class:`quantiphy.Quantity()`.

The *assign_rec* preference is expected to be a regular expression that
defines one or more named fields, one of which must be *val*. This exception
is raised when the current value of *assign_rec* does not satisfy this
requirement.

:class:`quantiphy.MissingName`:
Subclass of :class:`quantiphy.QuantiPhyError` and *NameError*. Used by
:func:`quantiphy.add_constant()`.

Raised when *alias* was not specified and no name was available from
*value*.

:class:`quantiphy.UnknownConversion`:
Subclass of :class:`quantiphy.QuantiPhyError` and *KeyError*.

Used by :meth:`quantiphy.UnitConversion.convert()`.

Raised when the given units are not supported by the underlying class.

Used by :class:`quantiphy.Quantity()`,
:meth:`quantiphy.Quantity.scale()`,
:meth:`quantiphy.Quantity.render()`,
:meth:`quantiphy.Quantity.fixed()`, and
:meth:`quantiphy.Quantity.format()`.

>>> Quantity.set_prefs(precision=6)
Traceback (most recent call last):
...
KeyError: 'precision'
Raised when a unit conversion was requested and there is no corresponding
unit converter.

:class:`quantiphy.UnknownFormatKey`:
Subclass of :class:`quantiphy.QuantiPhyError` and *KeyError*. Used by
:meth:`quantiphy.Quantity.render()`, :meth:`quantiphy.Quantity.fixed()`, and
:meth:`quantiphy.Quantity.format()`.

A *NameError* is raised if a constant is created without a name or if you try to
set or get a preference that is not supported.
The *label_fmt* and *label_fmt_full* are expected to be format strings that
may interpolate certain named arguments. The valid named arguments are *n*
for name, *v* for value, and *d* for description. This exception is raised
when some other name is used for an interpolated argument.

:class:`quantiphy.UnknownPreference`:
Subclass of :class:`quantiphy.QuantiPhyError` and *KeyError*. Used by
:meth:`quantiphy.Quantity.set_prefs()`,
:meth:`quantiphy.Quantity.get_pref()`, and
:meth:`quantiphy.Quantity.prefs()`.

Raised when the name given for a preference is unknown.

:class:`quantiphy.UnknownScaleFactor`:
Subclass of :class:`quantiphy.QuantiPhyError` and *ValueError*. Used by
:class:`quantiphy.Quantity()`, :meth:`quantiphy.Quantity.set_prefs()`, or
:meth:`quantiphy.Quantity.prefs()`.

The *input_sf* preference gives the list of scale factors that should be
accepted. This exception is raised if *input_sf* contains an unknown scale
factor.

:class:`quantiphy.UnknownUnitSystem`:
Subclass of :class:`quantiphy.QuantiPhyError` and *KeyError*. Used by
:func:`quantiphy.set_unit_system()`.

Raised when the name given does not correspond to a known unit system.

*QuantiPhy* defines a common base exception, :class:`quantiphy.QuantiPhyError`,
that all specific exceptions derive from. This allows you to simplify your
exception handling if you are not interested in distinguishing between the
specific errors:

.. code-block:: python
>>> q = add_constant(Quantity('1ns'))
Traceback (most recent call last):
...
NameError: No name specified.
>>> from quantiphy import Quantity, QuantiPhyError
>>> try:
... q = Quantity('tweed')
... except QuantiPhyError as e:
... print(str(e))
tweed: not a valid number.
The alternative would be to catch each error individually:

>>> from quantiphy import (
... Quantity, InvalidNumber, UnknownScaleFactor,
... UnknownConversion, InvalidRecognizer
... )

>>> try:
... q = Quantity('tweed')
... except (InvalidNumber, UnknownScaleFactor, UnknownConversion, InvalidRecognizer) as e:
... print(str(e))
tweed: not a valid number.
Loading

0 comments on commit 550a907

Please sign in to comment.