Skip to content

Commit 5355fe4

Browse files
authored
Merge pull request #3 from ericvsmith/pprint
Initial version of !p with f-strings.
2 parents 7fc13b2 + bbf612c commit 5355fe4

File tree

13 files changed

+43
-13
lines changed

13 files changed

+43
-13
lines changed

Include/ceval.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -125,13 +125,14 @@ PyAPI_FUNC(void) PyEval_ReleaseThread(PyThreadState *tstate);
125125
}
126126

127127
/* Masks and values used by FORMAT_VALUE opcode. */
128-
#define FVC_MASK 0x3
128+
#define FVC_MASK 0x7
129129
#define FVC_NONE 0x0
130130
#define FVC_STR 0x1
131131
#define FVC_REPR 0x2
132132
#define FVC_ASCII 0x3
133-
#define FVS_MASK 0x4
134-
#define FVS_HAVE_SPEC 0x4
133+
#define FVC_PRETTY 0x4
134+
#define FVS_MASK 0x8
135+
#define FVS_HAVE_SPEC 0x8
135136

136137
#ifndef Py_LIMITED_API
137138
# define Py_CPYTHON_CEVAL_H

Include/object.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,7 @@ PyAPI_FUNC(void) PyType_Modified(PyTypeObject *);
466466
PyAPI_FUNC(PyObject *) PyObject_Repr(PyObject *);
467467
PyAPI_FUNC(PyObject *) PyObject_Str(PyObject *);
468468
PyAPI_FUNC(PyObject *) PyObject_ASCII(PyObject *);
469+
PyAPI_FUNC(PyObject *) PyObject_Pretty(PyObject *);
469470
PyAPI_FUNC(PyObject *) PyObject_Bytes(PyObject *);
470471
PyAPI_FUNC(PyObject *) PyObject_RichCompare(PyObject *, PyObject *, int);
471472
PyAPI_FUNC(int) PyObject_RichCompareBool(PyObject *, PyObject *, int);

Lib/test/test_fstring.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1369,7 +1369,7 @@ def test_conversions(self):
13691369
for conv_identifier in 'g', 'A', 'G', 'ä', 'ɐ':
13701370
self.assertAllRaise(SyntaxError,
13711371
"f-string: invalid conversion character %r: "
1372-
"expected 's', 'r', or 'a'" % conv_identifier,
1372+
"expected 's', 'r', 'a', or 'p'" % conv_identifier,
13731373
["f'{3!" + conv_identifier + "}'"])
13741374

13751375
for conv_non_identifier in '3', '!':
@@ -1385,7 +1385,7 @@ def test_conversions(self):
13851385

13861386
self.assertAllRaise(SyntaxError,
13871387
"f-string: invalid conversion character 'ss': "
1388-
"expected 's', 'r', or 'a'",
1388+
"expected 's', 'r', 'a', or 'p'",
13891389
["f'{3!ss}'",
13901390
"f'{3!ss:}'",
13911391
"f'{3!ss:s}'",

Lib/test/test_print.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,9 @@ def test_bad_pprinter(self):
239239
with self.assertRaises(AttributeError):
240240
print('one', PPrintable(), 2, file=self.file, pretty=object())
241241

242+
def test_fstring(self):
243+
self.assertEqual(f'{PPrintable()!p}', "PPrintable('I feel pretty')")
244+
242245

243246
if __name__ == "__main__":
244247
unittest.main()

Lib/test/test_tstring.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ def test_syntax_errors(self):
216216
("t'{x!}'", "t-string: missing conversion character"),
217217
("t'{x=!}'", "t-string: missing conversion character"),
218218
("t'{x!z}'", "t-string: invalid conversion character 'z': "
219-
"expected 's', 'r', or 'a'"),
219+
"expected 's', 'r', 'a', or 'p'"),
220220
("t'{lambda:1}'", "t-string: lambda expressions are not allowed "
221221
"without parentheses"),
222222
("t'{x:{;}}'", "t-string: expecting a valid expression after '{'"),

Objects/object.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -862,6 +862,25 @@ PyObject_ASCII(PyObject *v)
862862
return res;
863863
}
864864

865+
PyObject *
866+
PyObject_Pretty(PyObject *v)
867+
{
868+
/* Call `pprint.pformat` */
869+
PyObject *printer = PyImport_ImportModuleAttrString("pprint", "pformat");
870+
if (!printer) {
871+
return NULL;
872+
}
873+
874+
PyObject *prettified = PyObject_CallOneArg(printer, v);
875+
Py_DECREF(printer);
876+
877+
if (!prettified) {
878+
return NULL;
879+
}
880+
881+
return prettified;
882+
}
883+
865884
PyObject *
866885
PyObject_Bytes(PyObject *v)
867886
{

Objects/stringlib/unicode_format.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -760,7 +760,7 @@ MarkupIterator_next(MarkupIterator *self, SubString *literal,
760760
}
761761

762762

763-
/* do the !r or !s conversion on obj */
763+
/* do the !r, !s, !a, or !p conversion on obj */
764764
static PyObject *
765765
do_conversion(PyObject *obj, Py_UCS4 conversion)
766766
{
@@ -773,6 +773,8 @@ do_conversion(PyObject *obj, Py_UCS4 conversion)
773773
return PyObject_Str(obj);
774774
case 'a':
775775
return PyObject_ASCII(obj);
776+
case 'p':
777+
return PyObject_Pretty(obj);
776778
default:
777779
if (conversion > 32 && conversion < 127) {
778780
/* It's the ASCII subrange; casting to char is safe

PC/python3dll.c

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Parser/action_helpers.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1001,9 +1001,9 @@ _PyPegen_check_fstring_conversion(Parser *p, Token* conv_token, expr_ty conv)
10011001

10021002
Py_UCS4 first = PyUnicode_READ_CHAR(conv->v.Name.id, 0);
10031003
if (PyUnicode_GET_LENGTH(conv->v.Name.id) > 1 ||
1004-
!(first == 's' || first == 'r' || first == 'a')) {
1004+
!(first == 's' || first == 'r' || first == 'a' || first == 'p')) {
10051005
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(conv,
1006-
"%c-string: invalid conversion character %R: expected 's', 'r', or 'a'",
1006+
"%c-string: invalid conversion character %R: expected 's', 'r', 'a', or 'p'",
10071007
TOK_GET_STRING_PREFIX(p->tok),
10081008
conv->v.Name.id);
10091009
return NULL;

Python/bytecodes.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5135,7 +5135,7 @@ dummy_func(
51355135

51365136
inst(CONVERT_VALUE, (value -- result)) {
51375137
conversion_func conv_fn;
5138-
assert(oparg >= FVC_STR && oparg <= FVC_ASCII);
5138+
assert(oparg >= FVC_STR && oparg <= FVC_PRETTY);
51395139
conv_fn = _PyEval_ConversionFuncs[oparg];
51405140
PyObject *result_o = conv_fn(PyStackRef_AsPyObjectBorrow(value));
51415141
PyStackRef_CLOSE(value);

0 commit comments

Comments
 (0)