format-utils 1.0.0__tar.gz
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.
- format_utils-1.0.0/PKG-INFO +15 -0
- format_utils-1.0.0/README.md +57 -0
- format_utils-1.0.0/format_utils.egg-info/PKG-INFO +15 -0
- format_utils-1.0.0/format_utils.egg-info/SOURCES.txt +12 -0
- format_utils-1.0.0/format_utils.egg-info/dependency_links.txt +1 -0
- format_utils-1.0.0/format_utils.egg-info/top_level.txt +1 -0
- format_utils-1.0.0/formatter/__init__.py +13 -0
- format_utils-1.0.0/formatter/bytes.py +14 -0
- format_utils-1.0.0/formatter/numbers.py +18 -0
- format_utils-1.0.0/formatter/strings.py +22 -0
- format_utils-1.0.0/formatter/time.py +19 -0
- format_utils-1.0.0/setup.cfg +4 -0
- format_utils-1.0.0/setup.py +17 -0
- format_utils-1.0.0/tests/test_formatting_lib.py +48 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: format-utils
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: A Python library for formatting numbers, strings, time, and bytes.
|
|
5
|
+
Author: lelewithheart
|
|
6
|
+
License: MIT
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Requires-Python: >=3.6
|
|
11
|
+
Dynamic: author
|
|
12
|
+
Dynamic: classifier
|
|
13
|
+
Dynamic: license
|
|
14
|
+
Dynamic: requires-python
|
|
15
|
+
Dynamic: summary
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Formatting Library
|
|
2
|
+
|
|
3
|
+
A Python library for formatting numbers, strings, time, and bytes. Includes utility functions for common formatting tasks.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Simply copy the `formatter` folder into your project. No external dependencies required.
|
|
8
|
+
|
|
9
|
+
## Usage
|
|
10
|
+
|
|
11
|
+
Import the desired functions from the `formatter` package:
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
from formatter import format_number, truncate, slugify, format_seconds, format_timestamp, format_bytes
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### Functions
|
|
18
|
+
|
|
19
|
+
#### Numbers
|
|
20
|
+
- `format_number(n: float, sep: str = ",") -> str`
|
|
21
|
+
- Formats a number with thousands separators.
|
|
22
|
+
- Example: `format_number(1234567)` → `'1,234,567'`
|
|
23
|
+
- Example: `format_number(1234567.89)` → `'1,234,567.89'`
|
|
24
|
+
|
|
25
|
+
#### Strings
|
|
26
|
+
- `truncate(text: str, length: int, suffix: str = "...") -> str`
|
|
27
|
+
- Truncates a string to a maximum length, appending a suffix if needed.
|
|
28
|
+
- Example: `truncate("Hello World", 5)` → `'He...'`
|
|
29
|
+
- `slugify(text: str) -> str`
|
|
30
|
+
- Converts text into a URL-friendly slug.
|
|
31
|
+
- Example: `slugify("Hello World!")` → `'hello-world'`
|
|
32
|
+
|
|
33
|
+
#### Time
|
|
34
|
+
- `format_seconds(seconds: float) -> str`
|
|
35
|
+
- Converts seconds into a human-readable duration, always showing hours, minutes, and seconds.
|
|
36
|
+
- Example: `format_seconds(3661)` → `'1h 1m 1s'`
|
|
37
|
+
- Example: `format_seconds(60)` → `'0h 1m 0s'`
|
|
38
|
+
- `format_timestamp(dt) -> str`
|
|
39
|
+
- Formats a datetime object into a standard string.
|
|
40
|
+
- Example: `format_timestamp(datetime(2026, 2, 7, 0, 13))` → `'2026-02-07 00:13'`
|
|
41
|
+
|
|
42
|
+
#### Bytes
|
|
43
|
+
- `format_bytes(n: int, decimals: int = 2) -> str`
|
|
44
|
+
- Converts a byte count into a human-readable string.
|
|
45
|
+
- Example: `format_bytes(1536000)` → `'1.46 MB'`
|
|
46
|
+
|
|
47
|
+
## Testing
|
|
48
|
+
|
|
49
|
+
Run the test suite with:
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
python -m tests.test_formatting_lib
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## License
|
|
56
|
+
|
|
57
|
+
MIT License
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: format-utils
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: A Python library for formatting numbers, strings, time, and bytes.
|
|
5
|
+
Author: lelewithheart
|
|
6
|
+
License: MIT
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Requires-Python: >=3.6
|
|
11
|
+
Dynamic: author
|
|
12
|
+
Dynamic: classifier
|
|
13
|
+
Dynamic: license
|
|
14
|
+
Dynamic: requires-python
|
|
15
|
+
Dynamic: summary
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
setup.py
|
|
3
|
+
format_utils.egg-info/PKG-INFO
|
|
4
|
+
format_utils.egg-info/SOURCES.txt
|
|
5
|
+
format_utils.egg-info/dependency_links.txt
|
|
6
|
+
format_utils.egg-info/top_level.txt
|
|
7
|
+
formatter/__init__.py
|
|
8
|
+
formatter/bytes.py
|
|
9
|
+
formatter/numbers.py
|
|
10
|
+
formatter/strings.py
|
|
11
|
+
formatter/time.py
|
|
12
|
+
tests/test_formatting_lib.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
formatter
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from .bytes import format_bytes
|
|
2
|
+
from .time import format_seconds, format_timestamp
|
|
3
|
+
from .numbers import format_number
|
|
4
|
+
from .strings import slugify, truncate
|
|
5
|
+
|
|
6
|
+
__all__ = [
|
|
7
|
+
"format_bytes",
|
|
8
|
+
"format_seconds",
|
|
9
|
+
"format_timestamp",
|
|
10
|
+
"format_number",
|
|
11
|
+
"slugify",
|
|
12
|
+
"truncate",
|
|
13
|
+
]
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
def format_bytes(n: int, decimals: int = 2) -> str:
|
|
2
|
+
"""
|
|
3
|
+
Convert a byte count into a human-readable string.
|
|
4
|
+
Example: 1536000 -> "1.54 MB"
|
|
5
|
+
"""
|
|
6
|
+
if n < 0:
|
|
7
|
+
raise ValueError("Byte count cannot be negative")
|
|
8
|
+
units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB']
|
|
9
|
+
i = 0
|
|
10
|
+
value = float(n)
|
|
11
|
+
while value >= 1024 and i < len(units) - 1:
|
|
12
|
+
value /= 1024
|
|
13
|
+
i += 1
|
|
14
|
+
return f"{value:.{decimals}f} {units[i]}"
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
def format_number(n: float, sep: str = ",") -> str:
|
|
2
|
+
"""
|
|
3
|
+
Format a number with thousands separators.
|
|
4
|
+
Example: 1234567 -> "1,234,567"
|
|
5
|
+
"""
|
|
6
|
+
num_str = str(n)
|
|
7
|
+
if '.' in num_str:
|
|
8
|
+
integer, decimal = num_str.split('.')
|
|
9
|
+
else:
|
|
10
|
+
integer, decimal = num_str, None
|
|
11
|
+
parts = []
|
|
12
|
+
while integer:
|
|
13
|
+
parts.append(integer[-3:])
|
|
14
|
+
integer = integer[:-3]
|
|
15
|
+
result = sep.join(reversed(parts))
|
|
16
|
+
if decimal:
|
|
17
|
+
result += '.' + decimal
|
|
18
|
+
return result
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
def slugify(text: str) -> str:
|
|
2
|
+
"""
|
|
3
|
+
Convert text into a URL-friendly slug.
|
|
4
|
+
Example: "Hello World!" -> "hello-world"
|
|
5
|
+
"""
|
|
6
|
+
import re
|
|
7
|
+
text = text.lower()
|
|
8
|
+
text = re.sub(r'[^a-z0-9]+', '-', text)
|
|
9
|
+
text = text.strip('-')
|
|
10
|
+
return text
|
|
11
|
+
|
|
12
|
+
def truncate(text: str, length: int, suffix: str = "...") -> str:
|
|
13
|
+
"""
|
|
14
|
+
Truncate a string to a maximum length.
|
|
15
|
+
Example: truncate("Hello World", 5) -> "He..."
|
|
16
|
+
"""
|
|
17
|
+
if len(text) <= length:
|
|
18
|
+
return text
|
|
19
|
+
if length <= len(suffix):
|
|
20
|
+
return suffix[:length]
|
|
21
|
+
truncated = text[:length - len(suffix)] + suffix
|
|
22
|
+
return truncated[:length]
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import math;
|
|
2
|
+
|
|
3
|
+
def format_seconds(seconds: float) -> str:
|
|
4
|
+
"""
|
|
5
|
+
Convert seconds into a human-readable duration.
|
|
6
|
+
Example: 3661 -> "1h 1m 1s"
|
|
7
|
+
"""
|
|
8
|
+
hours = math.floor(seconds // 3600)
|
|
9
|
+
minutes = math.floor((seconds % 3600) // 60)
|
|
10
|
+
secs = math.floor(seconds % 60)
|
|
11
|
+
return f"{hours}h {minutes}m {secs}s"
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def format_timestamp(dt) -> str:
|
|
15
|
+
"""
|
|
16
|
+
Format a datetime object into a standard string.
|
|
17
|
+
Example: datetime(2026, 2, 7, 0, 13) -> "2026-02-07 00:13"
|
|
18
|
+
"""
|
|
19
|
+
return dt.strftime('%Y-%m-%d %H:%M')
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from setuptools import setup, find_packages
|
|
2
|
+
|
|
3
|
+
setup(
|
|
4
|
+
name="format-utils",
|
|
5
|
+
version="1.0.0",
|
|
6
|
+
description="A Python library for formatting numbers, strings, time, and bytes.",
|
|
7
|
+
author="lelewithheart",
|
|
8
|
+
packages=find_packages(),
|
|
9
|
+
include_package_data=True,
|
|
10
|
+
python_requires='>=3.6',
|
|
11
|
+
license="MIT",
|
|
12
|
+
classifiers=[
|
|
13
|
+
"Programming Language :: Python :: 3",
|
|
14
|
+
"License :: OSI Approved :: MIT License",
|
|
15
|
+
"Operating System :: OS Independent",
|
|
16
|
+
],
|
|
17
|
+
)
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
import sys
|
|
3
|
+
import os
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
|
|
6
|
+
# Ensure parent directory is in sys.path for package imports
|
|
7
|
+
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
|
|
8
|
+
|
|
9
|
+
from formatter import numbers, strings, time, bytes
|
|
10
|
+
|
|
11
|
+
class TestFormattingLib(unittest.TestCase):
|
|
12
|
+
def test_format_number(self):
|
|
13
|
+
self.assertEqual(numbers.format_number(1234567), "1,234,567")
|
|
14
|
+
self.assertEqual(numbers.format_number(1234567.89), "1,234,567.89")
|
|
15
|
+
self.assertEqual(numbers.format_number(1000), "1,000")
|
|
16
|
+
self.assertEqual(numbers.format_number(0), "0")
|
|
17
|
+
self.assertEqual(numbers.format_number(1234567, sep="."), "1.234.567")
|
|
18
|
+
|
|
19
|
+
def test_truncate(self):
|
|
20
|
+
self.assertEqual(strings.truncate("Hello World", 5), "He...")
|
|
21
|
+
self.assertEqual(strings.truncate("Hello", 10), "Hello")
|
|
22
|
+
self.assertEqual(strings.truncate("Hello World", 8, "--"), "Hello --")
|
|
23
|
+
self.assertEqual(strings.truncate("Hello World", 2), "..")
|
|
24
|
+
|
|
25
|
+
def test_slugify(self):
|
|
26
|
+
self.assertEqual(strings.slugify("Hello World!"), "hello-world")
|
|
27
|
+
self.assertEqual(strings.slugify("Python_is Great"), "python-is-great")
|
|
28
|
+
self.assertEqual(strings.slugify("123 456"), "123-456")
|
|
29
|
+
self.assertEqual(strings.slugify("--Hello--"), "hello")
|
|
30
|
+
|
|
31
|
+
def test_format_seconds(self):
|
|
32
|
+
self.assertEqual(time.format_seconds(3661), "1h 1m 1s")
|
|
33
|
+
self.assertEqual(time.format_seconds(60), "0h 1m 0s")
|
|
34
|
+
self.assertEqual(time.format_seconds(59), "0h 0m 59s")
|
|
35
|
+
self.assertEqual(time.format_seconds(0), "0h 0m 0s")
|
|
36
|
+
|
|
37
|
+
def test_format_timestamp(self):
|
|
38
|
+
dt = datetime(2026, 2, 7, 0, 13)
|
|
39
|
+
self.assertEqual(time.format_timestamp(dt), "2026-02-07 00:13")
|
|
40
|
+
|
|
41
|
+
def test_format_bytes(self):
|
|
42
|
+
self.assertEqual(bytes.format_bytes(1536000), "1.46 MB")
|
|
43
|
+
self.assertEqual(bytes.format_bytes(1024), "1.00 KB")
|
|
44
|
+
self.assertEqual(bytes.format_bytes(0), "0.00 B")
|
|
45
|
+
self.assertEqual(bytes.format_bytes(1048576, 1), "1.0 MB")
|
|
46
|
+
|
|
47
|
+
if __name__ == "__main__":
|
|
48
|
+
unittest.main()
|