Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
7ade6485
Commit
7ade6485
authored
Aug 26, 2007
by
Eric Smith
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
PEP 3101: Completed string.Formatter class. Reimplemented field_name to object transformation.
parent
2bf4d5ba
Changes
7
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
497 additions
and
197 deletions
+497
-197
Include/unicodeobject.h
Include/unicodeobject.h
+1
-2
Lib/string.py
Lib/string.py
+35
-7
Lib/test/test_string.py
Lib/test/test_string.py
+21
-2
Lib/test/test_unicode.py
Lib/test/test_unicode.py
+9
-0
Objects/stringlib/string_format.h
Objects/stringlib/string_format.h
+260
-165
Objects/unicodeobject.c
Objects/unicodeobject.c
+157
-8
Python/sysmodule.c
Python/sysmodule.c
+14
-13
No files found.
Include/unicodeobject.h
View file @
7ade6485
...
...
@@ -1440,8 +1440,7 @@ PyAPI_FUNC(Py_UNICODE*) Py_UNICODE_strchr(
PyObject
*
_unicodeformatter_iterator
(
PyObject
*
str
);
PyObject
*
_unicodeformatter_lookup
(
PyObject
*
field_name
,
PyObject
*
args
,
PyObject
*
kwargs
);
_unicodeformatter_field_name_split
(
PyObject
*
field_name
);
#ifdef __cplusplus
}
...
...
Lib/string.py
View file @
7ade6485
...
...
@@ -200,31 +200,59 @@ class Template(metaclass=_TemplateMetaclass):
# exposed here via the sys module. sys was chosen because it's always
# available and doesn't have to be dynamically loaded.
# The parser is implemented in sys._formatter_parser.
# The
"object lookup" is implemented in sys._formatter_lookup
# The
overall
parser is implemented in sys._formatter_parser.
# The
field name parser is implemented in sys._formatter_field_name_split
from sys import _formatter_parser, _formatter_
lookup
from sys import _formatter_parser, _formatter_
field_name_split
class Formatter:
def format(self, format_string, *args, **kwargs):
return self.vformat(format_string, args, kwargs)
def vformat(self, format_string, args, kwargs):
used_args = set()
result = []
for (is_markup, literal, field_name, format_spec, conversion) in
\
_formatter_parser(format_string):
if is_markup:
# find the object
index, name, obj = _formatter_lookup(field_name, args, kwargs)
# given the field_name, find the object it references
# split it into the first part, and and iterator that
# looks over the rest
first, rest = _formatter_field_name_split(field_name)
used_args.add(first)
obj = self.get_value(first, args, kwargs)
# loop through the rest of the field_name, doing
# getattr or getitem as needed
for is_attr, i in rest:
if is_attr:
obj = getattr(obj, i)
else:
obj = obj[i]
# do any conversion on the resulting object
if conversion == 'r':
obj = repr(obj)
elif conversion == 's':
obj = str(obj)
# format the object and append to the result
result.append(self.format_field(obj, format_spec))
else:
result.append(literal)
self.check_unused_args(used_args, args, kwargs)
return ''.join(result)
def get_value(self, key, args, kwargs):
pass
if isinstance(key, int):
return args[key]
else:
return kwargs[key]
def check_unused_args(self, used_args, args, kwargs):
pass
def format_field(self, value, format_spec):
pass
return format(value, format_spec)
Lib/test/test_string.py
View file @
7ade6485
...
...
@@ -19,8 +19,27 @@ class ModuleTest(unittest.TestCase):
fmt
=
string
.
Formatter
()
self
.
assertEqual
(
fmt
.
format
(
"foo"
),
"foo"
)
# Formatter not working you for lookups
#self.assertEqual(fmt.format("foo{0}", "bar"), "foobar")
self
.
assertEqual
(
fmt
.
format
(
"foo{0}"
,
"bar"
),
"foobar"
)
self
.
assertEqual
(
fmt
.
format
(
"foo{1}{0}-{1}"
,
"bar"
,
6
),
"foo6bar-6"
)
self
.
assertEqual
(
fmt
.
format
(
"-{arg!r}-"
,
arg
=
'test'
),
"-'test'-"
)
class
NamespaceFormatter
(
string
.
Formatter
):
def
__init__
(
self
,
namespace
=
{}):
string
.
Formatter
.
__init__
(
self
)
self
.
namespace
=
namespace
def
get_value
(
self
,
key
,
args
,
kwds
):
if
isinstance
(
key
,
str
):
try
:
# Check explicitly passed arguments first
return
kwds
[
key
]
except
KeyError
:
return
self
.
namespace
[
key
]
else
:
string
.
Formatter
.
get_value
(
key
,
args
,
kwds
)
fmt
=
NamespaceFormatter
({
'greeting'
:
'hello'
})
self
.
assertEqual
(
fmt
.
format
(
"{greeting}, world!"
),
'hello, world!'
)
def
test_maketrans
(
self
):
...
...
Lib/test/test_unicode.py
View file @
7ade6485
...
...
@@ -449,6 +449,10 @@ class UnicodeTest(
self
.
assertEqual
(
'}}{{'
.
format
(),
'}{'
)
self
.
assertEqual
(
'}}x{{'
.
format
(),
'}x{'
)
# weird field names
self
.
assertEqual
(
"{0[foo-bar]}"
.
format
({
'foo-bar'
:
'baz'
}),
'baz'
)
self
.
assertEqual
(
"{0[foo bar]}"
.
format
({
'foo bar'
:
'baz'
}),
'baz'
)
self
.
assertEqual
(
'{foo._x}'
.
format
(
foo
=
C
(
20
)),
'20'
)
self
.
assertEqual
(
'{1}{0}'
.
format
(
D
(
10
),
D
(
20
)),
'2010'
)
self
.
assertEqual
(
'{0._x.x}'
.
format
(
C
(
D
(
'abc'
))),
'abc'
)
...
...
@@ -539,7 +543,11 @@ class UnicodeTest(
self
.
assertRaises
(
ValueError
,
"}"
.
format
)
self
.
assertRaises
(
ValueError
,
"abc{0:{}"
.
format
)
self
.
assertRaises
(
ValueError
,
"{0"
.
format
)
self
.
assertRaises
(
ValueError
,
"{0.}"
.
format
)
self
.
assertRaises
(
ValueError
,
"{0[}"
.
format
)
self
.
assertRaises
(
ValueError
,
"{0]}"
.
format
)
self
.
assertRaises
(
ValueError
,
"{0.[]}"
.
format
)
self
.
assertRaises
(
ValueError
,
"{0..foo}"
.
format
,
0
)
self
.
assertRaises
(
ValueError
,
"{0[0}"
.
format
)
self
.
assertRaises
(
ValueError
,
"{0[0:foo}"
.
format
)
self
.
assertRaises
(
ValueError
,
"{c]}"
.
format
)
...
...
@@ -551,6 +559,7 @@ class UnicodeTest(
self
.
assertRaises
(
ValueError
,
"{0!rs}"
.
format
)
self
.
assertRaises
(
ValueError
,
"{!}"
.
format
)
self
.
assertRaises
(
ValueError
,
"{:}"
.
format
)
self
.
assertRaises
(
ValueError
,
"{:s}"
.
format
)
self
.
assertRaises
(
ValueError
,
"{}"
.
format
)
# can't have a replacement on the field name portion
...
...
Objects/stringlib/string_format.h
View file @
7ade6485
This diff is collapsed.
Click to expand it.
Objects/unicodeobject.c
View file @
7ade6485
...
...
@@ -9161,9 +9161,8 @@ typedef struct {
static
void
formatteriter_dealloc
(
formatteriterobject
*
it
)
{
_PyObject_GC_UNTRACK
(
it
);
Py_XDECREF
(
it
->
str
);
PyObject_GC_Del
(
it
);
Py_XDECREF
(
it
->
str
);
PyObject_FREE
(
it
);
}
/* returns a tuple:
...
...
@@ -9313,7 +9312,7 @@ _unicodeformatter_iterator(PyObject *str)
{
formatteriterobject
*
it
;
it
=
PyObject_
GC_
New
(
formatteriterobject
,
&
PyFormatterIter_Type
);
it
=
PyObject_New
(
formatteriterobject
,
&
PyFormatterIter_Type
);
if
(
it
==
NULL
)
return
NULL
;
...
...
@@ -9326,17 +9325,167 @@ _unicodeformatter_iterator(PyObject *str)
PyUnicode_AS_UNICODE
(
str
),
PyUnicode_GET_SIZE
(
str
));
_PyObject_GC_TRACK
(
it
);
return
(
PyObject
*
)
it
;
}
PyObject
*
_unicodeformatter_lookup
(
PyObject
*
field_name
,
PyObject
*
args
,
PyObject
*
kwargs
)
/********************* FieldName Iterator ************************/
/* this is used to implement string.Formatter.vparse(). it parses
the field name into attribute and item values. */
typedef
struct
{
PyObject_HEAD
/* we know this to be a unicode object, but since we just keep
it around to keep the object alive, having it as PyObject
is okay */
PyObject
*
str
;
FieldNameIterator
it_field
;
}
fieldnameiterobject
;
static
void
fieldnameiter_dealloc
(
fieldnameiterobject
*
it
)
{
Py_XDECREF
(
it
->
str
);
PyObject_FREE
(
it
);
}
/* returns a tuple:
(is_attr, value)
is_attr is true if we used attribute syntax (e.g., '.foo')
false if we used index syntax (e.g., '[foo]')
value is an integer or string
*/
static
PyObject
*
fieldnameiter_next
(
fieldnameiterobject
*
it
)
{
int
result
;
int
is_attr
;
Py_ssize_t
idx
;
SubString
name
;
result
=
FieldNameIterator_next
(
&
it
->
it_field
,
&
is_attr
,
&
idx
,
&
name
);
if
(
result
==
0
||
result
==
1
)
{
/* if 0, error has already been set, if 1, iterator is empty */
return
NULL
;
}
else
{
PyObject
*
result
=
NULL
;
PyObject
*
is_attr_obj
=
NULL
;
PyObject
*
obj
=
NULL
;
is_attr_obj
=
PyBool_FromLong
(
is_attr
);
if
(
is_attr_obj
==
NULL
)
goto
error
;
/* either an integer or a string */
if
(
idx
!=
-
1
)
obj
=
PyInt_FromSsize_t
(
idx
);
else
obj
=
STRINGLIB_NEW
(
name
.
ptr
,
name
.
end
-
name
.
ptr
);
if
(
obj
==
NULL
)
goto
error
;
/* return a tuple of values */
result
=
PyTuple_Pack
(
2
,
is_attr_obj
,
obj
);
if
(
result
==
NULL
)
goto
error
;
return
result
;
error:
Py_XDECREF
(
result
);
Py_XDECREF
(
is_attr_obj
);
Py_XDECREF
(
obj
);
return
NULL
;
}
return
NULL
;
}
static
PyMethodDef
fieldnameiter_methods
[]
=
{
{
NULL
,
NULL
}
/* sentinel */
};
static
PyTypeObject
PyFieldNameIter_Type
=
{
PyVarObject_HEAD_INIT
(
&
PyType_Type
,
0
)
"fieldnameiterator"
,
/* tp_name */
sizeof
(
fieldnameiterobject
),
/* tp_basicsize */
0
,
/* tp_itemsize */
/* methods */
(
destructor
)
fieldnameiter_dealloc
,
/* tp_dealloc */
0
,
/* tp_print */
0
,
/* tp_getattr */
0
,
/* tp_setattr */
0
,
/* tp_compare */
0
,
/* tp_repr */
0
,
/* tp_as_number */
0
,
/* tp_as_sequence */
0
,
/* tp_as_mapping */
0
,
/* tp_hash */
0
,
/* tp_call */
0
,
/* tp_str */
PyObject_GenericGetAttr
,
/* tp_getattro */
0
,
/* tp_setattro */
0
,
/* tp_as_buffer */
Py_TPFLAGS_DEFAULT
,
/* tp_flags */
0
,
/* tp_doc */
0
,
/* tp_traverse */
0
,
/* tp_clear */
0
,
/* tp_richcompare */
0
,
/* tp_weaklistoffset */
PyObject_SelfIter
,
/* tp_iter */
(
iternextfunc
)
fieldnameiter_next
,
/* tp_iternext */
fieldnameiter_methods
,
/* tp_methods */
0
};
PyObject
*
_unicodeformatter_field_name_split
(
PyObject
*
field_name
)
{
SubString
first
;
Py_ssize_t
first_idx
;
fieldnameiterobject
*
it
;
PyObject
*
first_obj
=
NULL
;
PyObject
*
it_obj
=
NULL
;
PyObject
*
result
;
it
=
PyObject_New
(
fieldnameiterobject
,
&
PyFieldNameIter_Type
);
if
(
it
==
NULL
)
goto
error
;
it
->
str
=
NULL
;
it_obj
=
(
PyObject
*
)
it
;
if
(
!
field_name_split
(
STRINGLIB_STR
(
field_name
),
STRINGLIB_LEN
(
field_name
),
&
first
,
&
first_idx
,
&
it
->
it_field
))
goto
error
;
/* first becomes an integer, if possible, else a string */
if
(
first_idx
!=
-
1
)
first_obj
=
PyInt_FromSsize_t
(
first_idx
);
else
/* convert "first" into a string object */
first_obj
=
STRINGLIB_NEW
(
first
.
ptr
,
first
.
end
-
first
.
ptr
);
if
(
first_obj
==
NULL
)
goto
error
;
/* take ownership, give the object to the iterator. this is
just to keep the field_name alive */
Py_INCREF
(
field_name
);
it
->
str
=
field_name
;
/* return a tuple of values */
result
=
PyTuple_Pack
(
2
,
first_obj
,
it_obj
);
if
(
result
==
NULL
)
goto
error
;
return
result
;
error:
Py_XDECREF
(
it_obj
);
Py_XDECREF
(
first_obj
);
return
NULL
;
}
/********************* Unicode Iterator **************************/
...
...
Python/sysmodule.c
View file @
7ade6485
...
...
@@ -683,28 +683,28 @@ sys_formatter_iterator(PyObject *self, PyObject *args)
return
_unicodeformatter_iterator
(
str
);
}
/* sys_formatter_lookup is used to implement string.Formatter.vformat.
it takes an PEP 3101 "field name", args, and kwargs, and returns a
tuple (index, name, object). see unicodeobject.c's
_unicodeformatter_lookup for details */
/* sys_formatter_field_name_split is used to implement
string.Formatter.vformat. it takes an PEP 3101 "field name", and
returns a tuple of (first, rest): "first", the part before the
first '.' or '['; and "rest", an iterator for the rest of the field
name. see unicodeobjects' _unicode_formatter_field_name_split for
details */
static
PyObject
*
sys_formatter_
lookup
(
PyObject
*
self
,
PyObject
*
args
)
sys_formatter_
field_name_split
(
PyObject
*
self
,
PyObject
*
args
)
{
PyObject
*
field_name
;
PyObject
*
arg_args
;
PyObject
*
kwargs
;
if
(
!
PyArg_ParseTuple
(
args
,
"O
OO:_formatter_lookup"
,
&
field_name
,
&
arg_args
,
&
kwargs
))
if
(
!
PyArg_ParseTuple
(
args
,
"O
:_formatter_field_name_split"
,
&
field_name
))
return
NULL
;
if
(
!
PyUnicode_Check
(
field_name
))
{
PyErr_SetString
(
PyExc_TypeError
,
"
_formatter_lookup
expects unicode object"
);
PyErr_SetString
(
PyExc_TypeError
,
"_formatter_field_name_split "
"expects unicode object"
);
return
NULL
;
}
return
_unicodeformatter_
lookup
(
field_name
,
arg_args
,
kwargs
);
return
_unicodeformatter_
field_name_split
(
field_name
);
}
...
...
@@ -773,7 +773,8 @@ static PyMethodDef sys_methods[] = {
{
"_current_frames"
,
sys_current_frames
,
METH_NOARGS
,
current_frames_doc
},
{
"_formatter_parser"
,
sys_formatter_iterator
,
METH_VARARGS
},
{
"_formatter_lookup"
,
sys_formatter_lookup
,
METH_VARARGS
},
{
"_formatter_field_name_split"
,
sys_formatter_field_name_split
,
METH_VARARGS
},
{
"displayhook"
,
sys_displayhook
,
METH_O
,
displayhook_doc
},
{
"exc_info"
,
sys_exc_info
,
METH_NOARGS
,
exc_info_doc
},
{
"excepthook"
,
sys_excepthook
,
METH_VARARGS
,
excepthook_doc
},
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment