Skip to content

Commit d5d70c4

Browse files
bumped version number to 0.0.6, resolved E format specifier not recognized
1 parent 41a888d commit d5d70c4

File tree

6 files changed

+96
-52
lines changed

6 files changed

+96
-52
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
All notable changes to the pyprintf project will be documented in this file.
44

5+
## [0.0.6] - 2025-04-18
6+
7+
* Resolved an issue where the `E` (exponential) format specifier was not recognized by the parser.
8+
59
## [0.0.5] - 2025-04-17
610

711
* Added support for uppercase `E` in scientific notation output for floating-point numbers through the `%E` format specifier (e.g., `1.234500E+02`), alongside the existing lowercase `e` format (`%e`).

README.md

Lines changed: 78 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -98,49 +98,84 @@ The `sprintf` function uses placeholders within the format string (the first arg
9898

9999
### Optional Formatting Elements
100100

101-
These elements can appear in a placeholder in a specific order between the `%` and the type specifier.
102-
103-
1. **Argument Index (Positional Specifier)**:
104-
* **Syntax:** A number (starting from 1) followed by a `$` (e.g., `%2$s`).
105-
* **Description:** Explicitly selects which argument to use for the current placeholder. If omitted, arguments are used sequentially in the order they are provided to `sprintf`.
106-
* **Example:** `sprintf("%2$s, %1$s!", "Hello", "World")` will output `"World, Hello!"`.
107-
108-
2. **Sign Indicator**:
109-
* **Syntax:** A `+` character (e.g., `%+d`).
110-
* **Description:** Forces numeric values (integers and floats) to always display a sign, either `+` for positive numbers or `-` for negative numbers. By default, only negative numbers show a sign.
111-
* **Example:** `sprintf("%+d", 5)` will output `"+5"`, and `sprintf("%+d", -5)` will output `"-5"`.
112-
113-
3. **Padding Specifier**:
114-
* **Syntax:** Either a `0` or a single quote `'` followed by any character (e.g., `%05d`, `%'*5s`).
115-
* **Description:** Specifies the character used for padding the output to reach the desired width.
116-
* Using `0` pads with leading zeros for numeric types.
117-
* Using `'` followed by a character pads with that specific character.
118-
* **Examples:**
119-
* `sprintf("%05d", 12)` will output `"00012"`.
120-
* `sprintf("%'*5s", "abc")` will output `"**abc"`.
121-
122-
4. **Alignment**:
123-
* **Syntax:** A `-` character (e.g., `%-10s`).
124-
* **Description:** Aligns the output to the left within the specified field width. If the `-` is omitted, the output is right-aligned by default.
125-
* **Example:** `sprintf("%-10s", "hello")` will output `"hello "`, and `sprintf("%10s", "hello")` will output `" hello"`.
126-
127-
5. **Width**:
128-
* **Syntax:** A positive integer (e.g., `%10s`, `%5j`).
129-
* **Description:** Specifies the minimum number of characters to output. If the value to be formatted is shorter than the width, it will be padded (using the padding character and alignment). For the `j` (JSON) type, this number defines the indentation level (number of spaces).
130-
* **Examples:**
131-
* `sprintf("%10s", "test")` will output `" test"`.
132-
* `sprintf("%5j", { a: 1 })` will output `"{\n "a": 1\n}"`.
133-
134-
6. **Precision**:
135-
* **Syntax:** A period `.` followed by a non-negative integer (e.g., `%.2f`, `%.5g`, `%.10s`).
136-
* **Description:** Controls the precision of the output depending on the type specifier:
137-
* For floating-point types (`e`, `f`): Specifies the number of digits to appear after the decimal point.
138-
* For the `g` type: Specifies the number of significant digits.
139-
* For the `s`, `t`, `T`, and `v` types: Specifies the maximum number of characters to output (truncates the string if it's longer).
140-
* **Examples:**
141-
* `sprintf("%.2f", 3.14159)` will output `"3.14"`.
142-
* `sprintf("%.5g", 123.45678)` will output `"123.46"`.
143-
* `sprintf("%.5s", "This is a long string")` will output `"This "`.
101+
The `sprintf` function supports a wide range of formatting options. Each placeholder can include optional modifiers to control how the corresponding value is displayed. Below are the supported options in the order they can appear in a format specifier:
102+
103+
**Argument Index (Positional Specifier)**
104+
105+
* **Syntax:** `%<index>$<specifier>` (e.g., `%2$s`)
106+
* **Description:** Specifies which argument to insert at this position, starting from `1`. Useful when you want to change the order of values.
107+
* **Default:** If omitted, arguments are used in the order they appear.
108+
* **Example:**
109+
110+
```python
111+
sprintf("%2$s, %1$s!", "Hello", "World") # will output "World, Hello!"
112+
```
113+
114+
**Sign Indicator**
115+
116+
* **Syntax:** `%+<specifier>` (e.g., `%+d`)
117+
* **Description:** Forces numeric output to always include a sign (`+` or `-`).
118+
* **Default:** Only negative numbers show a sign.
119+
* **Example:**
120+
121+
```python
122+
sprintf("%+d", 5) # will output "+5"
123+
sprintf("%+d", -5) # will output "-5"
124+
```
125+
126+
**Padding Specifier**
127+
128+
* Syntax: `%0<width><specifier>` or `%'<char><width><specifier>` (e.g., `%05d`, `%'*5s`)
129+
* Description: Defines the character used for padding.
130+
* `0` pads numeric types with leading zeros.
131+
* `'` followed by a character pads with that character.
132+
* Default padding is with spaces.
133+
* Examples:
134+
135+
```python
136+
sprintf("%05d", 12) # will output "00012"
137+
sprintf("%'*5s", "abc") # will output "**abc"
138+
```
139+
140+
**Alignment**
141+
142+
* **Syntax:** `%-<width><specifier>` (e.g., `%-10s`)
143+
* **Description:** Aligns the output within the field width.
144+
* `-` aligns left.
145+
* Default is right alignment.
146+
* **Example:**
147+
148+
```python
149+
sprintf("%-10s", "hello") # will output "hello "
150+
sprintf("%10s", "hello") # will output " hello"
151+
```
152+
153+
**Width**
154+
155+
* **Syntax:** `%<number><specifier>` (e.g., `%10s`, `%5j`)
156+
* **Description:** Sets the minimum width of the output. Pads if the actual output is shorter.
157+
* For the `j` (JSON) specifier, this defines the number of spaces used for indentation.
158+
* **Examples:**
159+
160+
```python
161+
sprintf("%10s", "test") # will output " test"
162+
sprintf("%5j", { a: 1 }) # will output "{\n \"a\": 1\n}"
163+
```
164+
165+
Precision
166+
167+
**Syntax:** `%.<number><specifier>` (e.g., `%.2f`, `%.5g`, `%.10s`)
168+
**Description:** Controls output precision, depending on the type:
169+
* `f`, `e`: Number of digits after the decimal point.
170+
* `g`: Total significant digits.
171+
* `s`, `t`, `T`, `v`: Max characters (string is truncated).
172+
**Examples:**
173+
174+
```python
175+
sprintf("%.2f", 3.14159) # will output "3.14"
176+
sprintf("%.5g", 123.45678) # will output "123.46"
177+
sprintf("%.5s", "This is long text") # will output "This "
178+
```
144179

145180
### Required Type Specifier
146181

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ maintainers = [
3636
name = "pyprintf"
3737
readme = "README.md"
3838
requires-python = ">=3.10"
39-
version = "0.0.5"
39+
version = "0.0.6"
4040

4141
[project.urls]
4242
"Bug Tracker" = "https://github.com/playfulsparkle/pyprintf/issues"

src/pyprintf/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,4 @@
99
from .core import sprintf, vsprintf, config
1010

1111
__all__ = ["sprintf", "vsprintf", "config"]
12-
__version__ = "0.0.5"
12+
__version__ = "0.0.6"

src/pyprintf/core.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@
2222
# Matches if type is NOT 'T' (type detection)
2323
"not_type": re.compile(r"[^T]"),
2424
# Matches numeric format specifiers
25-
"number": re.compile(r"[diefg]"),
25+
"number": re.compile(r"[dieEfg]"),
2626
# Matches numeric argument types requiring number validation
27-
"numeric_arg": re.compile(r"[bcdiefguxX]"),
27+
"numeric_arg": re.compile(r"[bcdieEfguxX]"),
2828
# Matches JSON object specifier
2929
"json_object": re.compile(r"[j]"),
3030
# Matches plain text between format specifiers
@@ -48,7 +48,7 @@
4848
\. # Dot separator
4949
(\d*) # Precision
5050
)?
51-
([b-gijostTuxX]) # Conversion type specifier
51+
([bcdieEfgjostTuxX]) # Conversion type specifier
5252
""",
5353
re.VERBOSE,
5454
),
@@ -529,7 +529,7 @@ def sprintf_format(
529529
elif placeholder.type == "j":
530530
indent = int(placeholder.width) if placeholder.width else None
531531
try:
532-
arg = json.dumps(arg, indent=indent if not indent else None)
532+
arg = json.dumps(arg, indent=indent)
533533
except:
534534
arg = "None"
535535

tests/test_sprintf.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ def test_format_a_json_array(self):
4545
def test_format_a_number_in_scientific_notation_lowercase(self):
4646
assert sprintf("%e", 2) == "2e+0"
4747

48+
def test_format_a_number_in_scientific_notation_uppercase(self):
49+
assert sprintf("%E", 2) == "2E+0"
50+
4851
def test_format_an_unsigned_decimal_integer(self):
4952
assert sprintf("%u", 2) == "2"
5053

@@ -252,10 +255,10 @@ def test_format_a_float_and_a_string_with_padding(self):
252255
assert sprintf("%f %s", -12.34, "xxx") == "-12.34 xxx"
253256

254257
def test_format_a_json_object_with_indentation(self):
255-
assert sprintf("%2j", {"foo": "bar"}) == json.dumps({"foo": "bar"})
258+
assert sprintf("%2j", {"foo": "bar"}) == json.dumps({"foo": "bar"}, indent=2)
256259

257260
def test_format_a_json_array_with_indentation(self):
258-
assert sprintf("%2j", ["foo", "bar"]) == '["foo", "bar"]'
261+
assert sprintf("%2j", ["foo", "bar"]) == '[\n "foo",\n "bar"\n]'
259262

260263

261264
class TestPrecision:
@@ -280,7 +283,9 @@ def test_format_a_float_with_specified_precision_using_lambda(self):
280283

281284
def test_format_a_json_object_with_indentation_using_lambda(self):
282285
cfg = config().allow_computed_value(True)
283-
assert cfg.sprintf("%2j", lambda: {"foo": "bar"}) == json.dumps({"foo": "bar"})
286+
assert cfg.sprintf("%2j", lambda: {"foo": "bar"}) == json.dumps(
287+
{"foo": "bar"}, indent=2
288+
)
284289

285290
def test_format_a_number_in_shortest_notation_lowercase_using_lambda(self):
286291
cfg = config().allow_computed_value(True)

0 commit comments

Comments
 (0)