UnityManager 0.0.1a1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- UnityManager/__init__.py +41 -0
- UnityManager/_units.py +60 -0
- UnityManager/bytes.py +55 -0
- UnityManager/length.py +49 -0
- UnityManager/measure.py +49 -0
- games/__init__.py +11 -0
- games/_units.py +15 -0
- games/monetary.py +58 -0
- unitymanager-0.0.1a1.dist-info/METADATA +249 -0
- unitymanager-0.0.1a1.dist-info/RECORD +12 -0
- unitymanager-0.0.1a1.dist-info/WHEEL +4 -0
- unitymanager-0.0.1a1.dist-info/licenses/LICENSE +21 -0
UnityManager/__init__.py
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""Utilities for formatting common units.
|
|
2
|
+
|
|
3
|
+
The package exposes byte, length, capacity, mass and volume formatters at the
|
|
4
|
+
package level for convenient imports.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import re
|
|
10
|
+
import sys
|
|
11
|
+
|
|
12
|
+
from .bytes import format_bytes
|
|
13
|
+
from .length import format_length
|
|
14
|
+
from .measure import format_capacity, format_mass, format_volume
|
|
15
|
+
|
|
16
|
+
__version__ = "0.0.1-alpha1"
|
|
17
|
+
__author__ = "PlayGames-2020"
|
|
18
|
+
__summary__ = "Utilities for formatting common units."
|
|
19
|
+
|
|
20
|
+
_match = re.match(r"(\d+)\.(\d+)\.(\d+)(?:-(.+))?", __version__)
|
|
21
|
+
|
|
22
|
+
if _match: major, minor, patch, tag = _match.groups()
|
|
23
|
+
else: major, minor, patch, tag = 0, 0, 0, "unknown"
|
|
24
|
+
|
|
25
|
+
VERSION_INFO = (int(major), int(minor), int(patch), tag or "release")
|
|
26
|
+
|
|
27
|
+
NAME = __name__
|
|
28
|
+
|
|
29
|
+
_REQUIRED_PY = (3, 9)
|
|
30
|
+
if sys.version_info < (3, 9):
|
|
31
|
+
runtime = ".".join(str(v) for v in (_REQUIRED_PY))
|
|
32
|
+
info = f"{__name__} requires Python {runtime} or higher" \
|
|
33
|
+
f"(current: {sys.version.split()[0]})"
|
|
34
|
+
print(info)
|
|
35
|
+
raise RuntimeError(info)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
__all__ = [
|
|
39
|
+
"__version__", "VERSION_INFO", "NAME",
|
|
40
|
+
"format_volume", "format_mass", "format_capacity", "format_length", "format_bytes"
|
|
41
|
+
]
|
UnityManager/_units.py
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import List, Literal, Tuple, Union
|
|
4
|
+
|
|
5
|
+
_Mode = Union[str, Literal["n", "s", "d", "v", "lower", "upper", "title"]]
|
|
6
|
+
_TextMode = _Mode
|
|
7
|
+
_MeasureTextMode = _TextMode
|
|
8
|
+
_BytesTextMode = Union[str, Literal["s", "n", "d", "upper", "lower", "title", "byte", "bit"]]
|
|
9
|
+
|
|
10
|
+
_BYTES_TABLE: List[Tuple[str, str, Union[int, float], str]] = [
|
|
11
|
+
("zettabyte", "ZB", 1024**7, ""),
|
|
12
|
+
("exabyte", "EB", 1024**6, ""),
|
|
13
|
+
("petabyte", "PB", 1024**5, ""),
|
|
14
|
+
("terabyte", "TB", 1024**4, ""),
|
|
15
|
+
("gigabyte", "GB", 1024**3, ""),
|
|
16
|
+
("megabyte", "MB", 1024**2, ""),
|
|
17
|
+
("kilobyte", "KB", 1024, ""),
|
|
18
|
+
("byte", "B", 1, ""),
|
|
19
|
+
("bit", "b", 1 / 8, ""),
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
_LENGTH_TABLE: List[Tuple[str, str, float, str]] = [
|
|
23
|
+
("kilometre", "km", 1000.0, ""),
|
|
24
|
+
("hectometre", "hm", 100.0, ""),
|
|
25
|
+
("decametre", "dam", 10.0, ""),
|
|
26
|
+
("metre", "m", 1.0, ""),
|
|
27
|
+
("decimetre", "dm", 0.1, ""),
|
|
28
|
+
("centimetre", "cm", 0.01, ""),
|
|
29
|
+
("millimetre", "mm", 0.001, ""),
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
_CAPACITY_TABLE: List[Tuple[str, str, float, str]] = [
|
|
33
|
+
("kilolitre", "kl", 1000.0, ""),
|
|
34
|
+
("hectolitre", "hl", 100.0, ""),
|
|
35
|
+
("decalitre", "dal", 10.0, ""),
|
|
36
|
+
("litre", "l", 1.0, ""),
|
|
37
|
+
("decilitre", "dl", 0.1, ""),
|
|
38
|
+
("centilitre", "cl", 0.01, ""),
|
|
39
|
+
("millilitre", "ml", 0.001, ""),
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
_MASS_TABLE: List[Tuple[str, str, float, str]] = [
|
|
43
|
+
("kilogram", "kg", 1000.0, ""),
|
|
44
|
+
("hectogram", "hg", 100.0, ""),
|
|
45
|
+
("decagram", "dag", 10.0, ""),
|
|
46
|
+
("gram", "g", 1.0, ""),
|
|
47
|
+
("decigram", "dg", 0.1, ""),
|
|
48
|
+
("centigram", "cg", 0.01, ""),
|
|
49
|
+
("milligram", "mg", 0.001, ""),
|
|
50
|
+
]
|
|
51
|
+
|
|
52
|
+
_VOLUME_TABLE: List[Tuple[str, str, Union[int, float], str]] = [
|
|
53
|
+
("kilometre cubic", "km³", 1_000_000_000.0, ""),
|
|
54
|
+
("hectometre cubic", "hm³", 1_000_000.0, ""),
|
|
55
|
+
("decametre cubic", "dam³", 1_000.0, ""),
|
|
56
|
+
("metre cubic", "m³", 1.0, ""),
|
|
57
|
+
("decimetre cubic", "dm³", 0.001, ""),
|
|
58
|
+
("centimetre cubic", "cm³", 0.000_001, ""),
|
|
59
|
+
("millimetre cubic", "mm³", 0.000_000_001, ""),
|
|
60
|
+
]
|
UnityManager/bytes.py
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
""""""
|
|
2
|
+
|
|
3
|
+
from typing import Union, Any, List
|
|
4
|
+
from decimal import Decimal
|
|
5
|
+
|
|
6
|
+
from ._units import _BYTES_TABLE, _BytesTextMode
|
|
7
|
+
|
|
8
|
+
def format_bytes(n: Union[int, Any], mode: _BytesTextMode = "s") -> str:
|
|
9
|
+
"""Format a byte value using binary units.
|
|
10
|
+
|
|
11
|
+
Values are divided by powers of 1024 and rounded to two decimals. The
|
|
12
|
+
default mode, ``"s"``, displays the unit symbol. ``"n"`` displays the
|
|
13
|
+
unit name, ``"d"`` its description, and ``"byte"`` or ``"bit"`` adds a
|
|
14
|
+
conversion note. Case modifiers can be combined with these modes.
|
|
15
|
+
|
|
16
|
+
Non-numeric values are returned as text.
|
|
17
|
+
|
|
18
|
+
Examples:
|
|
19
|
+
>>> format_bytes(1024)
|
|
20
|
+
'1.00 KB'
|
|
21
|
+
>>> format_bytes(1024, "n")
|
|
22
|
+
'1.00 kilobyte'
|
|
23
|
+
"""
|
|
24
|
+
if not isinstance(n, (int, float, Decimal)): return str(n)
|
|
25
|
+
|
|
26
|
+
amount = Decimal(str(n))
|
|
27
|
+
abs_n = abs(amount)
|
|
28
|
+
unit_name: str
|
|
29
|
+
unit_symbol: str
|
|
30
|
+
unit_description: str
|
|
31
|
+
unit_name, unit_symbol, unit_description = "bit", "b", ""
|
|
32
|
+
for name, symbol, limit, description in _BYTES_TABLE:
|
|
33
|
+
_limit = Decimal(str(limit))
|
|
34
|
+
if abs_n >= limit:
|
|
35
|
+
amount = amount / _limit
|
|
36
|
+
unit_name, unit_symbol, unit_description = name, symbol, description
|
|
37
|
+
break
|
|
38
|
+
|
|
39
|
+
parts: List[str] = []
|
|
40
|
+
|
|
41
|
+
if "s" in mode: parts.append(unit_symbol)
|
|
42
|
+
if "n" in mode: parts.append(unit_name)
|
|
43
|
+
if "d" in mode: parts.append(unit_description)
|
|
44
|
+
if "upper" in mode: parts = [p.upper() for p in parts]
|
|
45
|
+
if "lower" in mode: parts = [p.lower() for p in parts]
|
|
46
|
+
if "title" in mode: parts = [p.title() for p in parts]
|
|
47
|
+
if "byte" in mode: parts.append(f"({n} bytes)")
|
|
48
|
+
if "bit" in mode: parts.append(f"({n / 8} bits)")
|
|
49
|
+
|
|
50
|
+
suffix = " ".join(parts)
|
|
51
|
+
return f"{amount:.2f}{f' {suffix}' if suffix else ''}"
|
|
52
|
+
|
|
53
|
+
__all__ = [
|
|
54
|
+
"format_bytes"
|
|
55
|
+
]
|
UnityManager/length.py
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""Format metric length quantities for display."""
|
|
2
|
+
from typing import Any, List, Literal, Union
|
|
3
|
+
from decimal import Decimal
|
|
4
|
+
|
|
5
|
+
from ._units import _LENGTH_TABLE, _TextMode
|
|
6
|
+
_LengthTextMode = _TextMode
|
|
7
|
+
|
|
8
|
+
def format_length(n: Union[int, Any], mode: _LengthTextMode = "s") -> str:
|
|
9
|
+
"""Format a length in metric units, from millimetres to kilometres.
|
|
10
|
+
|
|
11
|
+
The input is interpreted as metres. The largest suitable unit is selected
|
|
12
|
+
automatically and the result is rounded to two decimal places. Use
|
|
13
|
+
``"s"`` for the symbol, ``"n"`` for the name, ``"v"`` for the original
|
|
14
|
+
value, and combine these with ``"upper"``, ``"lower"`` or ``"title"``.
|
|
15
|
+
|
|
16
|
+
Non-numeric values are returned as text.
|
|
17
|
+
"""
|
|
18
|
+
if not isinstance(n, (int, float, Decimal)): return str(n)
|
|
19
|
+
|
|
20
|
+
abs_n = abs(Decimal(str(n)))
|
|
21
|
+
amount = Decimal(str(n))
|
|
22
|
+
name, symbol, description = "metre", "m", ""
|
|
23
|
+
|
|
24
|
+
for name_item, symbol_item, limit, desc_item in _LENGTH_TABLE:
|
|
25
|
+
if limit >= 1 and abs_n >= Decimal(str(limit)):
|
|
26
|
+
amount = Decimal(str(n)) / Decimal(str(limit))
|
|
27
|
+
name, symbol, description = name_item, symbol_item, desc_item
|
|
28
|
+
break
|
|
29
|
+
elif limit < 1 and abs_n >= Decimal(str(limit)):
|
|
30
|
+
amount = Decimal(str(n)) / Decimal(str(limit))
|
|
31
|
+
name, symbol, description = name_item, symbol_item, desc_item
|
|
32
|
+
break
|
|
33
|
+
|
|
34
|
+
parts: List[str] = []
|
|
35
|
+
if "n" in mode: parts.append(name)
|
|
36
|
+
if "s" in mode: parts.append(symbol)
|
|
37
|
+
if "d" in mode: parts.append(description)
|
|
38
|
+
if "v" in mode: parts.append(f"({float(n)} m)")
|
|
39
|
+
if "lower" in mode: parts = [p.lower() for p in parts]
|
|
40
|
+
if "upper" in mode: parts = [p.upper() for p in parts]
|
|
41
|
+
if "title" in mode: parts = [p.title() for p in parts]
|
|
42
|
+
|
|
43
|
+
suffix = " ".join(parts).strip()
|
|
44
|
+
return f"{amount:.2f}{f' {suffix}' if suffix else ''}"
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
__all__ = [
|
|
48
|
+
"format_length"
|
|
49
|
+
]
|
UnityManager/measure.py
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""Format capacity, mass and volume quantities for display."""
|
|
2
|
+
from typing import Any, List, Literal, Union, Tuple
|
|
3
|
+
from decimal import Decimal
|
|
4
|
+
|
|
5
|
+
from ._units import (
|
|
6
|
+
_CAPACITY_TABLE, _MASS_TABLE, _VOLUME_TABLE, _MeasureTextMode
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
def _generic_formatter(n: Union[int, Any], table: List[Tuple], default_unit: Tuple, base_symbol: str, mode: _MeasureTextMode = "s") -> str:
|
|
10
|
+
"""Format a numeric measurement using the supplied unit table."""
|
|
11
|
+
if not isinstance(n, (int, float, Decimal)): return str(n)
|
|
12
|
+
|
|
13
|
+
abs_n = abs(Decimal(str(n)))
|
|
14
|
+
amount = Decimal(str(n))
|
|
15
|
+
name, symbol, description = default_unit
|
|
16
|
+
|
|
17
|
+
for name_item, symbol_item, limit, desc_item in table:
|
|
18
|
+
if abs_n >= Decimal(str(limit)):
|
|
19
|
+
amount = Decimal(str(n)) / Decimal(str(limit))
|
|
20
|
+
name, symbol, description = name_item, symbol_item, desc_item
|
|
21
|
+
break
|
|
22
|
+
|
|
23
|
+
parts: List[str] = []
|
|
24
|
+
if "n" in mode: parts.append(name)
|
|
25
|
+
if "s" in mode: parts.append(symbol)
|
|
26
|
+
if "d" in mode: parts.append(description)
|
|
27
|
+
if "v" in mode: parts.append(f"({float(n)} {base_symbol})")
|
|
28
|
+
if "lower" in mode: parts = [p.lower() for p in parts]
|
|
29
|
+
if "upper" in mode: parts = [p.upper() for p in parts]
|
|
30
|
+
if "title" in mode: parts = [p.title() for p in parts]
|
|
31
|
+
|
|
32
|
+
suffix = " ".join(parts).strip()
|
|
33
|
+
return f"{amount:.2f}{f' {suffix}' if suffix else ''}"
|
|
34
|
+
|
|
35
|
+
def format_capacity(n: Union[int, Any], mode: _MeasureTextMode = "s") -> str:
|
|
36
|
+
"""Format a capacity expressed in litres."""
|
|
37
|
+
return _generic_formatter(n, _CAPACITY_TABLE, ("litre", "l", ""), "l", mode)
|
|
38
|
+
|
|
39
|
+
def format_mass(n: Union[int, Any], mode: _MeasureTextMode = "s") -> str:
|
|
40
|
+
"""Format a mass expressed in grams."""
|
|
41
|
+
return _generic_formatter(n, _MASS_TABLE, ("gram", "g", ""), "g", mode)
|
|
42
|
+
|
|
43
|
+
def format_volume(n: Union[int, Any], mode: _MeasureTextMode = "s") -> str:
|
|
44
|
+
"""Format a volume expressed in cubic metres."""
|
|
45
|
+
return _generic_formatter(n, _VOLUME_TABLE, ("metre cubic", "m³", ""), "m³", mode)
|
|
46
|
+
|
|
47
|
+
__all__ = [
|
|
48
|
+
"format_capacity", "format_mass", "format_volume"
|
|
49
|
+
]
|
games/__init__.py
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"""Game-specific formatting helpers.
|
|
2
|
+
|
|
3
|
+
The public API currently provides :func:`format_money`, which formats large
|
|
4
|
+
in-game currency values using compact suffixes such as ``K`` and ``M``.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from .monetary import format_money
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"format_money"
|
|
11
|
+
]
|
games/_units.py
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import List, Tuple, Union
|
|
4
|
+
from UnityManager._units import _TextMode
|
|
5
|
+
|
|
6
|
+
_MoneyTextMode = _TextMode
|
|
7
|
+
|
|
8
|
+
_MONEY_TABLE: List[Tuple[str, str, Union[int, float], str]] = [
|
|
9
|
+
("quadrillion", "Q", 10 ** 15, ""),
|
|
10
|
+
("trillion", "T", 10 ** 12, ""),
|
|
11
|
+
("billion", "B", 10 ** 9, ""),
|
|
12
|
+
("million", "M", 10 ** 6, ""),
|
|
13
|
+
("thousand", "K", 10 ** 3, ""),
|
|
14
|
+
("", "", 1, ""),
|
|
15
|
+
]
|
games/monetary.py
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""Formatting helpers for in-game monetary values."""
|
|
2
|
+
from typing import Any, List, Literal, Union
|
|
3
|
+
from decimal import Decimal
|
|
4
|
+
|
|
5
|
+
from ._units import _MONEY_TABLE, _MoneyTextMode
|
|
6
|
+
|
|
7
|
+
def format_money(n: Union[int, Any], mode: _MoneyTextMode = "s") -> str:
|
|
8
|
+
"""Format an in-game currency amount with a compact suffix.
|
|
9
|
+
|
|
10
|
+
Args:
|
|
11
|
+
n: Numeric amount in the base currency (gold by default). Non-numeric
|
|
12
|
+
values are returned unchanged as text.
|
|
13
|
+
mode: Controls the text appended to the formatted number. ``"s"``
|
|
14
|
+
adds the suffix symbol, ``"n"`` adds its name, ``"d"`` adds the
|
|
15
|
+
description, and ``"v"`` shows the original amount as gold.
|
|
16
|
+
Case modifiers ``"upper"``, ``"lower"`` and ``"title"`` can be
|
|
17
|
+
combined with the other modes.
|
|
18
|
+
|
|
19
|
+
Returns:
|
|
20
|
+
A string containing the amount rounded to two decimal places and the
|
|
21
|
+
requested currency text.
|
|
22
|
+
|
|
23
|
+
Examples:
|
|
24
|
+
>>> format_money(1500)
|
|
25
|
+
'1.50 K'
|
|
26
|
+
>>> format_money(2_000_000, "n")
|
|
27
|
+
'2.00 million'
|
|
28
|
+
>>> format_money(1500, "nsupper")
|
|
29
|
+
'1.50 THOUSAND K'
|
|
30
|
+
"""
|
|
31
|
+
if not isinstance(n, (int, float, Decimal)): return str(n)
|
|
32
|
+
|
|
33
|
+
abs_n = abs(Decimal(str(n)))
|
|
34
|
+
amount = Decimal(str(n))
|
|
35
|
+
name, symbol, description = "", "", ""
|
|
36
|
+
|
|
37
|
+
for name_item, symbol_item, limit, desc_item in _MONEY_TABLE:
|
|
38
|
+
if abs_n >= Decimal(str(limit)):
|
|
39
|
+
amount = Decimal(str(n)) / Decimal(str(limit))
|
|
40
|
+
name, symbol, description = name_item, symbol_item, desc_item
|
|
41
|
+
break
|
|
42
|
+
|
|
43
|
+
parts: List[str] = []
|
|
44
|
+
|
|
45
|
+
if "n" in mode: parts.append(name)
|
|
46
|
+
if "s" in mode: parts.append(symbol)
|
|
47
|
+
if "d" in mode: parts.append(description)
|
|
48
|
+
if "v" in mode: parts.append(f"({n} gold)")
|
|
49
|
+
if "lower" in mode: parts = [p.lower() for p in parts]
|
|
50
|
+
if "upper" in mode: parts = [p.upper() for p in parts]
|
|
51
|
+
if "title" in mode: parts = [p.title() for p in parts]
|
|
52
|
+
|
|
53
|
+
suffix = " ".join(part for part in parts if part)
|
|
54
|
+
return f"{amount:.2f}{f' {suffix}' if suffix else ''}"
|
|
55
|
+
|
|
56
|
+
__all__ = [
|
|
57
|
+
"format_money"
|
|
58
|
+
]
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: UnityManager
|
|
3
|
+
Version: 0.0.1a1
|
|
4
|
+
Summary: Utilities for formatting common units.
|
|
5
|
+
Project-URL: Homepage, https://github.com/PlayGames-2020/UnityManager
|
|
6
|
+
Project-URL: Repository, https://github.com/PlayGames-2020/UnityManager.git
|
|
7
|
+
Project-URL: Documentation, https://github.com/PlayGames-2020/UnityManager/blob/main/README.md
|
|
8
|
+
Project-URL: Authors, https://github.com/PlayGames-2020
|
|
9
|
+
Author-email: PlayGames-2020 <playgames16.01.2020@gmail.com>
|
|
10
|
+
License: MIT License
|
|
11
|
+
|
|
12
|
+
Copyright (c) 2026 PlayGames-2020
|
|
13
|
+
|
|
14
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
15
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
16
|
+
in the Software without restriction, including without limitation the rights
|
|
17
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
18
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
19
|
+
furnished to do so, subject to the following conditions:
|
|
20
|
+
|
|
21
|
+
The above copyright notice and this permission notice shall be included in all
|
|
22
|
+
copies or substantial portions of the Software.
|
|
23
|
+
|
|
24
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
25
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
26
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
27
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
28
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
29
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
30
|
+
SOFTWARE.
|
|
31
|
+
License-File: LICENSE
|
|
32
|
+
Keywords: bytes,formatting,games,length,mass,money,units,volume
|
|
33
|
+
Classifier: Development Status :: 3 - Alpha
|
|
34
|
+
Classifier: Intended Audience :: Developers
|
|
35
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
36
|
+
Classifier: Operating System :: OS Independent
|
|
37
|
+
Classifier: Programming Language :: Python :: 3
|
|
38
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
39
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
40
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
41
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
42
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
43
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
44
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
45
|
+
Requires-Python: >=3.9
|
|
46
|
+
Provides-Extra: dev
|
|
47
|
+
Requires-Dist: pytest>=8.4.2; extra == 'dev'
|
|
48
|
+
Description-Content-Type: text/markdown
|
|
49
|
+
|
|
50
|
+
# UnityManager
|
|
51
|
+
|
|
52
|
+
Utilities for formatting common units without runtime dependencies.
|
|
53
|
+
|
|
54
|
+
> **Status:** alpha (`0.0.1-alpha`). The API is still subject to change.
|
|
55
|
+
|
|
56
|
+
## Requirements
|
|
57
|
+
|
|
58
|
+
- Python **3.9 or later**
|
|
59
|
+
- No runtime dependencies
|
|
60
|
+
|
|
61
|
+
## Installation
|
|
62
|
+
|
|
63
|
+
### GitHub
|
|
64
|
+
|
|
65
|
+
``` bash
|
|
66
|
+
pip install git+https://github.com/PlayGames-2020/UnityManager.git
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
or
|
|
70
|
+
|
|
71
|
+
``` bash
|
|
72
|
+
pip install git+https://github.com/PlayGames-2020/UnityManager.git@master
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### PyPI
|
|
76
|
+
|
|
77
|
+
``` bash
|
|
78
|
+
pip install UnityManager
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
To install the development dependencies:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
pip install "unitymanager[dev]"
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Quick start
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
from UnityManager import (
|
|
91
|
+
format_bytes,
|
|
92
|
+
format_capacity,
|
|
93
|
+
format_length,
|
|
94
|
+
format_mass,
|
|
95
|
+
format_volume,
|
|
96
|
+
)
|
|
97
|
+
from games import format_money
|
|
98
|
+
|
|
99
|
+
print(format_bytes(1024)) # 1.00 KB
|
|
100
|
+
print(format_length(1500)) # 1.50 km
|
|
101
|
+
print(format_capacity(2.5)) # 2.50 l
|
|
102
|
+
print(format_mass(2500)) # 2.50 kg
|
|
103
|
+
print(format_volume(1)) # 1.00 m³
|
|
104
|
+
print(format_money(1500)) # 1.50 K
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Each formatter accepts a text mode. The default mode `"s"` displays the unit symbol. Use `"n"` for the unit name, combine modes such as `"ns"`, or add `"upper"`, `"lower"`, `"title"` and `"v"` as needed.
|
|
108
|
+
|
|
109
|
+
## Games package
|
|
110
|
+
|
|
111
|
+
The optional game-oriented API is available from the `games` package:
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
from games import format_money
|
|
115
|
+
|
|
116
|
+
format_money(999) # "999.00"
|
|
117
|
+
format_money(1_500) # "1.50 K"
|
|
118
|
+
format_money(2_000_000) # "2.00 M"
|
|
119
|
+
format_money(1_500, "n") # "1.50 thousand"
|
|
120
|
+
format_money(1_500, "ns") # "1.50 thousand K"
|
|
121
|
+
format_money(1_500, "v") # "1.50 (1500 gold)"
|
|
122
|
+
format_money(1_500, "nsupper") # "1.50 THOUSAND K"
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### `format_money(value, mode="s")`
|
|
126
|
+
|
|
127
|
+
Formats a numeric amount in the base game currency, assumed to be gold. Values
|
|
128
|
+
are rounded to two decimal places and use the largest applicable suffix:
|
|
129
|
+
|
|
130
|
+
| Range | Name | Symbol |
|
|
131
|
+
| ---: | --- | :--- |
|
|
132
|
+
| 1,000 | thousand | `K` |
|
|
133
|
+
| 1,000,000 | million | `M` |
|
|
134
|
+
| 1,000,000,000 | billion | `B` |
|
|
135
|
+
| 1,000,000,000,000 | trillion | `T` |
|
|
136
|
+
| 1,000,000,000,000,000 | quadrillion | `Q` |
|
|
137
|
+
|
|
138
|
+
Supported mode components:
|
|
139
|
+
|
|
140
|
+
- `s`: append the compact symbol.
|
|
141
|
+
- `n`: append the full unit name.
|
|
142
|
+
- `d`: append the unit description (reserved for future descriptions).
|
|
143
|
+
- `v`: append the original value as gold.
|
|
144
|
+
- `upper`, `lower`, `title`: change the case of the appended text.
|
|
145
|
+
|
|
146
|
+
Modes can be combined, for example `"nsupper"`. Non-numeric values are returned
|
|
147
|
+
as text instead of raising an exception.
|
|
148
|
+
|
|
149
|
+
The formatter is intentionally currency-neutral in its arithmetic: it only
|
|
150
|
+
compacts the amount. The displayed base-currency label is currently `gold` and
|
|
151
|
+
can be extended in a future API version if games need coins, gems, credits or
|
|
152
|
+
other currencies.
|
|
153
|
+
|
|
154
|
+
## UnityManager API
|
|
155
|
+
|
|
156
|
+
All public formatters return a string rounded to two decimal places. Numeric
|
|
157
|
+
inputs use the base unit described below; non-numeric inputs are returned using
|
|
158
|
+
`str(value)`.
|
|
159
|
+
|
|
160
|
+
### `format_bytes(value, mode="s")`
|
|
161
|
+
|
|
162
|
+
Formats binary quantities using powers of 1024. The base input is bytes and the
|
|
163
|
+
available symbols include `B`, `KB`, `MB`, `GB`, `TB`, `PB`, `EB` and `ZB`.
|
|
164
|
+
The mode `"byte"` adds the original value in bytes, while `"bit"` adds its
|
|
165
|
+
corresponding bit value.
|
|
166
|
+
|
|
167
|
+
```python
|
|
168
|
+
format_bytes(1024) # "1.00 KB"
|
|
169
|
+
format_bytes(1024, "n") # "1.00 kilobyte"
|
|
170
|
+
format_bytes(2048, "sbyte") # "2.00 KB (2048 bytes)"
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### `format_length(value, mode="s")`
|
|
174
|
+
|
|
175
|
+
Formats a value expressed in metres using metric units from millimetres to
|
|
176
|
+
kilometres.
|
|
177
|
+
|
|
178
|
+
```python
|
|
179
|
+
format_length(1_500) # "1.50 km"
|
|
180
|
+
format_length(1, "n") # "1.00 metre"
|
|
181
|
+
format_length(1, "nv") # "1.00 metre (1.0 m)"
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### `format_capacity(value, mode="s")`
|
|
185
|
+
|
|
186
|
+
Formats a value expressed in litres, from millilitres to kilolitres.
|
|
187
|
+
|
|
188
|
+
```python
|
|
189
|
+
format_capacity(2.5) # "2.50 l"
|
|
190
|
+
format_capacity(1_000, "n") # "1.00 kilolitre"
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### `format_mass(value, mode="s")`
|
|
194
|
+
|
|
195
|
+
Formats a value expressed in grams, from milligrams to kilograms.
|
|
196
|
+
|
|
197
|
+
```python
|
|
198
|
+
format_mass(2_500) # "2.50 kg"
|
|
199
|
+
format_mass(1, "n") # "1.00 gram"
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### `format_volume(value, mode="s")`
|
|
203
|
+
|
|
204
|
+
Formats a value expressed in cubic metres, from cubic millimetres to cubic
|
|
205
|
+
kilometres.
|
|
206
|
+
|
|
207
|
+
```python
|
|
208
|
+
format_volume(1) # "1.00 m³"
|
|
209
|
+
format_volume(0.000001) # "1.00 cm³"
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Text modes
|
|
213
|
+
|
|
214
|
+
The general formatters support these mode components:
|
|
215
|
+
|
|
216
|
+
- `s`: append the unit symbol (the default).
|
|
217
|
+
- `n`: append the full unit name.
|
|
218
|
+
- `d`: append the unit description, when available.
|
|
219
|
+
- `v`: append the original value in the base unit.
|
|
220
|
+
- `upper`, `lower`, `title`: change the case of the appended text.
|
|
221
|
+
|
|
222
|
+
Modes can be combined as a string, for example `"nsupper"`.
|
|
223
|
+
|
|
224
|
+
## Supported formatters
|
|
225
|
+
|
|
226
|
+
- `format_bytes`: binary byte units (`B`, `KB`, `MB`, and so on).
|
|
227
|
+
- `format_length`: metric lengths from millimetres to kilometres.
|
|
228
|
+
- `format_capacity`: metric capacities from millilitres to kilolitres.
|
|
229
|
+
- `format_mass`: metric masses from milligrams to kilograms.
|
|
230
|
+
- `format_volume`: cubic metric units from cubic millimetres to cubic kilometres.
|
|
231
|
+
- `games.format_money`: compact game currency values (`K`, `M`, `B`, `T`, `Q`).
|
|
232
|
+
|
|
233
|
+
## Development and testing
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
git clone https://github.com/PlayGames-2020/UnityManager.git
|
|
237
|
+
cd UnityManager
|
|
238
|
+
pip install -e ".[dev]"
|
|
239
|
+
python -m pytest
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
## License
|
|
243
|
+
|
|
244
|
+
Distributed under the [MIT License](LICENSE).
|
|
245
|
+
|
|
246
|
+
## Links
|
|
247
|
+
|
|
248
|
+
- [Repository](https://github.com/PlayGames-2020/UnityManager)
|
|
249
|
+
- [Documentation](https://github.com/PlayGames-2020/UnityManager/blob/main/README.md)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
UnityManager/__init__.py,sha256=yGRnZMu8ccizXL8TVSKvu0iFIs_KLnALSgo44XKZOGM,1175
|
|
2
|
+
UnityManager/_units.py,sha256=3Bv4iPU7vnT8c5lvMxxhGwvdQBmeLDBqzJ6xbzqIhdg,1980
|
|
3
|
+
UnityManager/bytes.py,sha256=oSGeFyrBcJ6M_5KmeOMuDDJke9xe80ScHaXG9GaxWG0,1850
|
|
4
|
+
UnityManager/length.py,sha256=IMkX0DXop12Js6-GT3isbne7IPHLj5PVniP7jt1tAJo,1924
|
|
5
|
+
UnityManager/measure.py,sha256=IYjF_wVCSNYWy1EORjzQfrVi8I3hn1ByEEQ6h5EZppQ,2098
|
|
6
|
+
games/__init__.py,sha256=T_D3bbhYzGxXAF4EKoEoggXklKIhKBJcDWzIBoQprqU,269
|
|
7
|
+
games/_units.py,sha256=VvnaXZKetTYqt5RO42s__MH9Du9uQCvApXcN-lc64a8,428
|
|
8
|
+
games/monetary.py,sha256=GtRM3ZkoSSfKz13wZxs6xeIew4h8PId8W4NcgGHoLgw,2137
|
|
9
|
+
unitymanager-0.0.1a1.dist-info/METADATA,sha256=iAvV2ogade5KqGHZEpEO7m0fC6dTulza2m6hQdFekjQ,8091
|
|
10
|
+
unitymanager-0.0.1a1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
11
|
+
unitymanager-0.0.1a1.dist-info/licenses/LICENSE,sha256=KJecc8txDD4yvhnS_h5Hm9byqN6NgUFYiTpa0jd9eYA,1092
|
|
12
|
+
unitymanager-0.0.1a1.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 PlayGames-2020
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|