Skip to content

Commit 43e4049

Browse files
committed
Python 3.6+: use f-strings instead of str.format in most situations
This most often improves readability.
1 parent 6e7165c commit 43e4049

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+332
-343
lines changed

countlines.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,13 @@ def analyze(items, blanks=False, docstrings=False, comments=False):
3434
content = f.read()
3535
ns.append(loc(content, blanks, docstrings, comments))
3636
# report
37-
print("{}:".format(name))
37+
print(f"{name}:")
3838
for fn, n in sorted(zip(files, ns), key=itemgetter(1)):
39-
print(" {} {}".format(fn, n))
39+
print(f" {fn} {n}")
4040
grouptotal = sum(ns)
41-
print(" total for {} {}".format(name, grouptotal))
41+
print(f" total for {name} {grouptotal}")
4242
grandtotal += grouptotal
43-
print("grand total {}".format(grandtotal))
43+
print(f"grand total {grandtotal}")
4444

4545
def main():
4646
items = (("top level", ["."]),

doc/features.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2337,7 +2337,7 @@ def _(loop):
23372337
if s.lower() == 'q':
23382338
return # ...the implicit None. In a "while True:", "break" here.
23392339
else:
2340-
print("Hello, {}!".format(s))
2340+
print(f"Hello, {s}!")
23412341
return loop()
23422342
```
23432343
@@ -2395,13 +2395,13 @@ Multiple input iterables work somewhat like in Python's ``for``, except any sequ
23952395
@looped_over(zip((1, 2, 3), ('a', 'b', 'c')), acc=())
23962396
def p(loop, item, acc):
23972397
numb, lett = item
2398-
return loop(acc + ("{:d}{:s}".format(numb, lett),))
2398+
return loop(acc + (f"{numb:d}{lett}",))
23992399
assert p == ('1a', '2b', '3c')
24002400
24012401
@looped_over(enumerate(zip((1, 2, 3), ('a', 'b', 'c'))), acc=())
24022402
def q(loop, item, acc):
24032403
idx, (numb, lett) = item
2404-
return loop(acc + ("Item {:d}: {:d}{:s}".format(idx, numb, lett),))
2404+
return loop(acc + (f"Item {idx:d}: {numb:d}{lett}",))
24052405
assert q == ('Item 0: 1a', 'Item 1: 2b', 'Item 2: 3c')
24062406
```
24072407
@@ -2434,7 +2434,7 @@ Mutable sequence (Python ``list``):
24342434
@looped_over(zip((1, 2, 3), ('a', 'b', 'c')), acc=[])
24352435
def p(loop, item, acc):
24362436
numb, lett = item
2437-
newelt = "{:d}{:s}".format(numb, lett)
2437+
newelt = f"{numb:d}{lett}"
24382438
acc.append(newelt)
24392439
return loop()
24402440
assert p == ['1a', '2b', '3c']
@@ -2449,7 +2449,7 @@ from unpythonic import cons, nil, ll
24492449
@looped_over(zip((1, 2, 3), ('a', 'b', 'c')), acc=nil)
24502450
def p(loop, item, acc):
24512451
numb, lett = item
2452-
newelt = "{:d}{:s}".format(numb, lett)
2452+
newelt = f"{numb:d}{lett}"
24532453
return loop(cons(newelt, acc))
24542454
assert p == ll('1a', '2b', '3c')
24552455
```
@@ -2464,7 +2464,7 @@ To get the output as a tuple, we can add ``tuple`` to the decorator chain:
24642464
@looped_over(zip((1, 2, 3), ('a', 'b', 'c')), acc=nil)
24652465
def p(loop, item, acc):
24662466
numb, lett = item
2467-
newelt = "{:d}{:s}".format(numb, lett)
2467+
newelt = f"{numb:d}{lett}"
24682468
return loop(cons(newelt, acc))
24692469
assert p == ('1a', '2b', '3c')
24702470
```
@@ -3397,7 +3397,7 @@ from unpythonic import raisef, tryf
33973397
33983398
raise_instance = lambda: raisef(ValueError("all ok"))
33993399
test[tryf(lambda: raise_instance(),
3400-
(ValueError, lambda err: "got a ValueError: '{}'".format(err.args[0]))) == "got a ValueError: 'all ok'"]
3400+
(ValueError, lambda err: f"got a ValueError: '{err.args[0]}'")) == "got a ValueError: 'all ok'"]
34013401
```
34023402
34033403
The exception handler is a function. It may optionally accept one argument, the exception instance.

doc/macros.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1529,7 +1529,7 @@ This is mainly of interest as a point of [comparison with Racket](https://github
15291529
from unpythonic.syntax import macros, aif
15301530

15311531
aif[2*21,
1532-
print("it is {}".format(it)),
1532+
print(f"it is {it}"),
15331533
print("it is falsey")]
15341534
```
15351535

unpythonic/amb.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ def choice(**binding):
4848
lambda e: e.x)
4949
"""
5050
if len(binding) != 1:
51-
raise ValueError("Expected exactly one name=iterable pair, got {:d} with values {}".format(len(binding), binding))
51+
raise ValueError(f"Expected exactly one name=iterable pair, got {len(binding)} with values {binding}")
5252
for k, v in binding.items(): # just one but we don't know its name
5353
return Assignment(k, v)
5454

@@ -149,7 +149,7 @@ def begin(*exprs): # args eagerly evaluated by Python
149149
else:
150150
name, body = None, item
151151
if name and not name.isidentifier():
152-
raise ValueError("name must be valid identifier, got {}".format(repr(name)))
152+
raise ValueError(f"name must be valid identifier, got {repr(name)}")
153153
bodys.append(body)
154154

155155
freevars = names.copy() # names from the surrounding scopes
@@ -166,9 +166,9 @@ def begin(*exprs): # args eagerly evaluated by Python
166166
raise TypeError("Arity mismatch; callable body must allow arity 1, to take in the environment.")
167167
except UnknownArity: # pragma: no cover
168168
pass
169-
code = "monadify(bodys[{j:d}](e), {flag:s})".format(flag=unpack_flag, j=j)
169+
code = f"monadify(bodys[{j}](e), {unpack_flag})"
170170
else: # doesn't need the environment
171-
code = "monadify(bodys[{j:d}], {flag:s})".format(flag=unpack_flag, j=j)
171+
code = f"monadify(bodys[{j}], {unpack_flag})"
172172

173173
if begin_is_open:
174174
code += ")"
@@ -179,14 +179,14 @@ def begin(*exprs): # args eagerly evaluated by Python
179179
# even though we use an imperative stateful object to implement it)
180180
if not is_last:
181181
if name:
182-
code += "{bind:s}(lambda {n:s}:\nbegin(e.close_over({fvs}), e.assign('{n:s}', {n:s}), ".format(bind=bind, n=name, fvs=freevars)
182+
code += f"{bind}(lambda {name}:\nbegin(e.close_over({freevars}), e.assign('{name}', {name}), "
183183
begin_is_open = True
184184
else:
185185
if is_first:
186-
code += "{bind:s}(lambda _:\nbegin(e.close_over(set()), ".format(bind=bind)
186+
code += f"{bind}(lambda _:\nbegin(e.close_over(set()), "
187187
begin_is_open = True
188188
else:
189-
code += "{seq:s}(\n".format(seq=seq)
189+
code += f"{seq}(\n"
190190

191191
allcode += code
192192
allcode += ")" * (len(lines) - 1)
@@ -257,7 +257,7 @@ def then(self, f):
257257
"""
258258
cls = self.__class__
259259
if not isinstance(f, cls):
260-
raise TypeError("Expected a List monad, got {} with data {}".format(type(f), f))
260+
raise TypeError(f"Expected a List monad, got {type(f)} with value {repr(f)}")
261261
return self >> (lambda _: f)
262262

263263
@classmethod
@@ -303,13 +303,13 @@ def __eq__(self, other):
303303
def __add__(self, other):
304304
"""Concatenation of MonadicList, for convenience."""
305305
if not isinstance(other, MonadicList):
306-
raise TypeError("Expected a monadic list, got {} with value {}".format(type(other), repr(other)))
306+
raise TypeError(f"Expected a monadic list, got {type(other)} with value {repr(other)}")
307307
cls = self.__class__
308308
return cls.from_iterable(self.x + other.x)
309309

310310
def __repr__(self): # pragma: no cover
311311
clsname = self.__class__.__name__
312-
return "{}{}".format(clsname, self.x)
312+
return f"{clsname}{self.x}"
313313

314314
@classmethod
315315
def from_iterable(cls, iterable):
@@ -355,7 +355,7 @@ def join(self):
355355
"""
356356
cls = self.__class__
357357
if not all(isinstance(elt, cls) for elt in self.x):
358-
raise TypeError("Expected a nested List monad, got {}".format(self.x))
358+
raise TypeError(f"Expected a nested List monad, got {type(self.x)} with value {self.x}")
359359
# list of lists - concat them
360360
return cls.from_iterable(elt for sublist in self.x for elt in sublist)
361361

unpythonic/arity.py

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -433,9 +433,7 @@ def f(a):
433433
# gather excess positional arguments
434434
if len(args) > nposparams:
435435
if varpos is None:
436-
raise TypeError("{}() takes {} positional arguments but {} were given".format(f.__name__,
437-
nposparams,
438-
len(args)))
436+
raise TypeError(f"{f.__name__}() takes {nposparams} positional arguments but {len(args)} were given")
439437
slots[varpos] = args[nposparams:]
440438

441439
# fill from keyword arguments
@@ -445,13 +443,11 @@ def f(a):
445443
if slots[slot] is unassigned:
446444
slots[slot] = value
447445
else:
448-
raise TypeError("{}() got multiple values for argument '{}'".format(f.__name__,
449-
identifier))
446+
raise TypeError(f"{f.__name__}() got multiple values for argument '{identifier}'")
450447
elif varkw is not None: # gather excess keyword arguments
451448
vkdict[identifier] = value
452449
else:
453-
raise TypeError("{}() got an unexpected keyword argument '{}'".format(f.__name__,
454-
identifier))
450+
raise TypeError(f"{f.__name__}() got an unexpected keyword argument '{identifier}'")
455451

456452
# fill missing with defaults from function definition
457453
failures = []
@@ -465,16 +461,13 @@ def f(a):
465461
if failures:
466462
if len(failures) == 1:
467463
n1 = failures[0]
468-
raise TypeError("{}() missing required positional argument: '{}'".format(f.__name__, n1))
464+
raise TypeError(f"{f.__name__}() missing required positional argument: '{n1}'")
469465
if len(failures) == 2:
470466
n1, n2 = failures
471-
raise TypeError("{}() missing 2 required positional arguments: '{}' and '{}'".format(f.__name__, n1, n2))
472-
wrapped = ["'{}'".format(x) for x in failures]
467+
raise TypeError(f"{f.__name__}() missing 2 required positional arguments: '{n1}' and '{n2}'")
468+
wrapped = [f"'{x}'" for x in failures]
473469
others = ", ".join(wrapped[:-1])
474-
msg = "{}() missing {} required positional arguments: {}, and '{}'".format(f.__name__,
475-
len(failures),
476-
others,
477-
failures[-1])
470+
msg = f"{f.__name__}() missing {len(failures)} required positional arguments: {others}, and '{failures[-1]}'"
478471
raise TypeError(msg)
479472

480473
# build the result

unpythonic/assignonce.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,13 @@ def __setattr__(self, name, value):
2727
if name in self._reserved_names or name not in self:
2828
return super().__setattr__(name, value)
2929
else:
30-
raise AttributeError("name {} is already defined".format(repr(name)))
30+
raise AttributeError(f"name {repr(name)} is already defined")
3131

3232
def set(self, name, value):
3333
"""Rebind an existing name to a new value."""
3434
env = self._env
3535
if name not in env:
36-
raise AttributeError("name {} is not defined".format(repr(name)))
36+
raise AttributeError(f"name {repr(name)} is not defined")
3737
# important part: bypass our own __setattr__, which would refuse the update.
3838
super().__setattr__(name, value)
3939
return value

unpythonic/collections.py

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ def f(b):
186186
def __init__(self, x=None):
187187
self.x = x
188188
def __repr__(self): # pragma: no cover
189-
return "box({})".format(repr(self.x))
189+
return f"box({repr(self.x)})"
190190
def __contains__(self, x):
191191
return self.x == x
192192
def __iter__(self):
@@ -237,7 +237,7 @@ def __init__(self, x=None):
237237
self._default = x
238238
def __repr__(self): # pragma: no cover
239239
"""**WARNING**: the repr shows only the content seen by the current thread."""
240-
return "ThreadLocalBox({})".format(repr(self.get()))
240+
return f"ThreadLocalBox({repr(self.get())})"
241241
def __contains__(self, x):
242242
return self.get() == x
243243
def __iter__(self):
@@ -280,7 +280,7 @@ class Some:
280280
def __init__(self, x=None):
281281
self.x = x
282282
def __repr__(self): # pragma: no cover
283-
return "Some({})".format(repr(self.x))
283+
return f"Some({repr(self.x)})"
284284
def __contains__(self, x):
285285
return self.x == x
286286
def __iter__(self):
@@ -304,7 +304,7 @@ def unbox(b):
304304
If `b` is not a `box` (or `ThreadLocalBox` or `Some`), raises `TypeError`.
305305
"""
306306
if not isinstance(b, (box, Some)):
307-
raise TypeError("Expected box, got {} with value {}".format(type(b), repr(b)))
307+
raise TypeError(f"Expected box, got {type(b)} with value {repr(b)}")
308308
return b.get()
309309

310310
class Shim:
@@ -353,7 +353,7 @@ class Shim:
353353
"""
354354
def __init__(self, thebox, fallback=None):
355355
if not isinstance(thebox, box):
356-
raise TypeError("Expected box, got {} with value {}".format(type(thebox), repr(thebox)))
356+
raise TypeError(f"Expected box, got {type(thebox)} with value {repr(thebox)}")
357357
self._shim_box = thebox
358358
self._shim_fallback = fallback
359359
def __getattr__(self, k):
@@ -456,7 +456,7 @@ def __init__(self, *ms, **bindings):
456456

457457
@wraps(dict.__repr__)
458458
def __repr__(self): # pragma: no cover
459-
return "frozendict({})".format(self._data.__repr__())
459+
return f"frozendict({self._data.__repr__()})"
460460

461461
def __hash__(self):
462462
return hash(frozenset(self.items()))
@@ -547,7 +547,7 @@ def _lowlevel_repr(self): # pragma: no cover
547547
def __str__(self): # pragma: no cover
548548
return str(self._lowlevel_repr())
549549
def __repr__(self): # pragma: no cover
550-
return "{:s}({!r})".format(self.__class__.__name__, self._lowlevel_repr())
550+
return f"{self.__class__.__name__}({self._lowlevel_repr()!r})"
551551

552552
def __eq__(self, other):
553553
if other is self:
@@ -643,7 +643,7 @@ def __getitem__(self, k):
643643
return ctor(self.seq, k)
644644
return ctor(self, k)
645645
elif isinstance(k, tuple):
646-
raise TypeError("multidimensional subscripting not supported; got {}".format(repr(k)))
646+
raise TypeError(f"multidimensional subscripting not supported; got {repr(k)}")
647647
else:
648648
data, r = self._update_cache()
649649
n = len(r)
@@ -709,7 +709,7 @@ def __setitem__(self, k, v):
709709
for j, item in zip(r[k], vs):
710710
data[j] = item
711711
elif isinstance(k, tuple):
712-
raise TypeError("multidimensional subscripting not supported; got {}".format(repr(k)))
712+
raise TypeError(f"multidimensional subscripting not supported; got {repr(k)}")
713713
else:
714714
n = len(r)
715715
if k >= n or k < -n:
@@ -736,7 +736,7 @@ class ShadowedSequence(Sequence, _StrReprEqMixin):
736736
"""
737737
def __init__(self, seq, ix=None, v=None):
738738
if ix is not None and not isinstance(ix, (slice, int)):
739-
raise TypeError("ix: expected slice or int, got {} with value {}".format(type(ix), ix))
739+
raise TypeError(f"ix: expected slice or int, got {type(ix)} with value {ix}")
740740
self.seq = seq
741741
self.ix = ix
742742
self.v = v
@@ -767,7 +767,7 @@ def __getitem__(self, k):
767767
ctor = tuple if hasattr(cls, "_make") else cls # slice of namedtuple -> tuple
768768
return ctor(self._getone(j) for j in range(n)[k])
769769
elif isinstance(k, tuple):
770-
raise TypeError("multidimensional subscripting not supported; got {}".format(repr(k)))
770+
raise TypeError(f"multidimensional subscripting not supported; got {repr(k)}")
771771
else:
772772
if k >= n or k < -n:
773773
raise IndexError("ShadowedSequence index out of range")
@@ -782,7 +782,7 @@ def _getone(self, k):
782782
# we already know k is in ix, so skip validation for speed.
783783
i = _index_in_slice(k, ix, n, _validate=False)
784784
if i >= len(self.v):
785-
raise IndexError("Replacement sequence too short; attempted to access index {} with len {} (items: {})".format(i, len(self.v), self.v))
785+
raise IndexError(f"Replacement sequence too short; attempted to access index {i} with len {len(self.v)} (items: {self.v})")
786786
return self.v[i]
787787
return self.seq[k] # not in slice
788788

@@ -801,9 +801,9 @@ def in_slice(i, s, l=None):
801801
ValueError. (A negative ``s.step`` by itself does not need ``l``.)
802802
"""
803803
if not isinstance(s, (slice, int)):
804-
raise TypeError("s must be slice or int, got {} with value {}".format(type(s), s))
804+
raise TypeError(f"s must be slice or int, got {type(s)} with value {s}")
805805
if not isinstance(i, int):
806-
raise TypeError("i must be int, got {} with value {}".format(type(i), i))
806+
raise TypeError(f"i must be int, got {type(i)} with value {i}")
807807
wrap = _make_negidx_converter(l)
808808
i = wrap(i)
809809
if isinstance(s, int):
@@ -837,9 +837,9 @@ def _index_in_slice(i, s, n=None, _validate=True): # n: length of sequence bein
837837
def _make_negidx_converter(n): # n: length of sequence being indexed
838838
if n is not None:
839839
if not isinstance(n, int):
840-
raise TypeError("n must be int, got {} with value {}".format(type(n), n))
840+
raise TypeError(f"n must be int, got {type(n)} with value {n}")
841841
if n <= 0:
842-
raise ValueError("n must be an int >= 1, got {}".format(n))
842+
raise ValueError(f"n must be an int >= 1, got {n}")
843843
def apply_conversion(k):
844844
return k % n
845845
else:
@@ -852,12 +852,12 @@ def convert(k):
852852
# layers protect against having to check here, but since the
853853
# `convert` function is returned to the caller, let's be
854854
# careful.
855-
raise TypeError("k must be int, got {} with value {}".format(type(k), k)) # pragma: no cover
855+
raise TypeError(f"k must be int, got {type(k)} with value {k}") # pragma: no cover
856856
# Almost standard semantics for negative indices. Usually -n < k < n,
857857
# but here we must allow for conversion of the end position, for
858858
# which the last valid value is one past the end.
859859
if n is not None and not -n <= k <= n:
860-
raise IndexError("Should have -n <= k <= n, but n = {}, and k = {}".format(n, k))
860+
raise IndexError(f"Should have -n <= k <= n, but n = {n}, and k = {k}")
861861
return apply_conversion(k) if k < 0 else k
862862
return convert
863863

@@ -868,7 +868,7 @@ def _canonize_slice(s, n=None, wrap=None): # convert negatives, inject defaults
868868
# used elsewhere. (And, it's already possible that some internal caller
869869
# incorrectly uses the no-check mode of the internal implementation function
870870
# `_index_in_slice`.)
871-
raise TypeError("s must be slice, got {} with value {}".format(type(s), s)) # pragma: no cover
871+
raise TypeError(f"s must be slice, got {type(s)} with value {s}") # pragma: no cover
872872

873873
step = s.step if s.step is not None else +1 # no "s.step or +1"; someone may try step=0
874874
if step == 0:

0 commit comments

Comments
 (0)