Skip to content

Commit

Permalink
Merge pull request astropy#16676 from eerovaher/units-format_exponent…
Browse files Browse the repository at this point in the history
…ial_notation

Shuffle unit formatter `format_exponential_notation()` methods
  • Loading branch information
mhvk authored Jul 20, 2024
2 parents 517ca05 + 8a7d1b7 commit 31fd209
Show file tree
Hide file tree
Showing 6 changed files with 45 additions and 78 deletions.
19 changes: 17 additions & 2 deletions astropy/units/format/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class Base:
registry: ClassVar[dict[str, type[Base]]] = {}
_space: ClassVar[str] = " "
_scale_unit_separator: ClassVar[str] = " "
_times: ClassVar[str] = "*"
name: ClassVar[str] # Set by __init_subclass__ by the latest

def __new__(cls, *args, **kwargs):
Expand All @@ -43,7 +44,7 @@ def __init_subclass__(cls, **kwargs):

@classmethod
def format_exponential_notation(
cls, val: float | np.number, format_spec: str = "g"
cls, val: float | np.number, format_spec: str = ".8g"
) -> str:
"""
Formats a value in exponential notation.
Expand All @@ -61,7 +62,21 @@ def format_exponential_notation(
str
The value in exponential notation in a this class's format.
"""
return format(val, format_spec)
x = format(val, format_spec).split("e")
if len(x) != 2:
return cls._format_mantissa(x[0]) # no exponent
ex = x[1].lstrip("0+")
if not ex:
return cls._format_mantissa(x[0]) # exponent was zero
if ex.startswith("-"):
ex = "-" + ex[1:].lstrip("0")
ex = f"10{cls._format_superscript(ex)}"
m = cls._format_mantissa("" if x[0].rstrip("0") == "1." else x[0])
return f"{m}{cls._times}{ex}" if m else ex

@classmethod
def _format_mantissa(cls, m: str) -> str:
return m

@classmethod
def _format_superscript(cls, number: str) -> str:
Expand Down
18 changes: 3 additions & 15 deletions astropy/units/format/cds.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@
if TYPE_CHECKING:
from typing import ClassVar, Literal

import numpy as np

from astropy.extern.ply.lex import Lexer, LexToken
from astropy.units import UnitBase
from astropy.utils.parsing import ThreadSafeParser
Expand Down Expand Up @@ -310,22 +308,12 @@ def parse(cls, s: str, debug: bool = False) -> UnitBase:
raise ValueError("Syntax error")

@classmethod
def format_exponential_notation(
cls, val: float | np.number, format_spec: str = ".8g"
) -> str:
m, ex = utils.split_mantissa_exponent(val)
parts = []
if m not in ("", "1"):
parts.append(m)
if ex:
if not ex.startswith("-"):
ex = "+" + ex
parts.append(f"10{cls._format_superscript(ex)}")
return cls._times.join(parts)
def _format_mantissa(cls, m: str) -> str:
return "" if m == "1" else m

@classmethod
def _format_superscript(cls, number: str) -> str:
return number
return number if number.startswith("-") else "+" + number

@classmethod
def to_string(
Expand Down
24 changes: 1 addition & 23 deletions astropy/units/format/console.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,11 @@

from typing import TYPE_CHECKING

from . import base, utils
from . import base

if TYPE_CHECKING:
from typing import ClassVar, Literal

import numpy as np

from astropy.units import UnitBase


Expand All @@ -36,33 +34,13 @@ class Console(base.Base):
2.1798721*10^-18 m^2 kg / s^2
"""

_times: ClassVar[str] = "*"
_line: ClassVar[str] = "-"
_space: ClassVar[str] = " "

@classmethod
def _format_mantissa(cls, m: str) -> str:
return m

@classmethod
def _format_superscript(cls, number: str) -> str:
return f"^{number}"

@classmethod
def format_exponential_notation(
cls, val: float | np.number, format_spec: str = ".8g"
) -> str:
m, ex = utils.split_mantissa_exponent(val, format_spec)

parts = []
if m:
parts.append(cls._format_mantissa(m))

if ex:
parts.append(f"10{cls._format_superscript(ex)}")

return cls._times.join(parts)

@classmethod
def _format_fraction(
cls,
Expand Down
8 changes: 8 additions & 0 deletions astropy/units/format/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
from .base import Base

if TYPE_CHECKING:
import numpy as np

from astropy.units import NamedUnit, UnitBase


Expand Down Expand Up @@ -661,3 +663,9 @@ def _to_decomposed_alternative(cls, unit: UnitBase) -> str:
unit = copy(unit)
unit._scale = 1.0
return f"{cls.to_string(unit)} (with data multiplied by {scale})"

@classmethod
def format_exponential_notation(
cls, val: float | np.number, format_spec: str = "g"
) -> str:
return format(val, format_spec)
38 changes: 0 additions & 38 deletions astropy/units/format/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@
from numbers import Real
from typing import TypeVar

import numpy as np

from astropy.units import UnitBase

T = TypeVar("T")
Expand Down Expand Up @@ -56,42 +54,6 @@ def get_grouped_by_powers(
return positive, negative


def split_mantissa_exponent(
v: float | np.number, format_spec: str = ".8g"
) -> tuple[str, str]:
"""
Given a number, split it into its mantissa and base 10 exponent
parts, each as strings. If the exponent is too small, it may be
returned as the empty string.
Parameters
----------
v : number
format_spec : str, optional
Number representation formatting string
Returns
-------
mantissa, exponent : str
"""
x = format(v, format_spec).split("e")

if len(x) == 2:
ex = x[1].lstrip("0+")
if len(ex) > 0 and ex[0] == "-":
ex = "-" + ex[1:].lstrip("0")
else:
ex = ""

if ex == "" or (x[0] != "1." + "0" * (len(x[0]) - 2)):
m = x[0]
else:
m = ""

return m, ex


def decompose_to_known_units(
unit: UnitBase, func: Callable[[UnitBase], None]
) -> UnitBase:
Expand Down
16 changes: 16 additions & 0 deletions docs/changes/units/16676.api.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
The ``format_exponential_notation()`` method of the ``Base`` unit formatter has
changed.
Any unit formatters that inherit directly from ``Base`` but have not
implemented their own ``format_exponential_notation()`` and wish to retain
previous behavior should implement it as:

.. code-block:: python
def format_exponential_notation(cls, val, format_spec):
return format(val, format_spec)
Any formatters that inherit directly from ``Base`` and call
``super().format_exponential_notation(val, format_spec)`` should instead call
``format(val, format_spec)``
The specific unit formatters in ``astropy.units`` and custom formatters that
inherit from any of them are not affected.

0 comments on commit 31fd209

Please sign in to comment.