| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -160,8 +160,37 @@ some storage device. In such cases, blocking reads are unacceptable. | |||
| 160 | 160 | Because it's so flexible, :class:`XMLPullParser` can be inconvenient to use for | |
| 161 | 161 | simpler use-cases. If you don't mind your application blocking on reading XML | |
| 162 | 162 | data but would still like to have incremental parsing capabilities, take a look | |
| 163 | - at :func:`iterparse`. It can be useful when you're reading a large XML document | ||
| 164 | - and don't want to hold it wholly in memory. | ||
| 163 | + at :func:`iterparse`. | ||
| 164 | + | ||
| 165 | + Note that both parsers build the tree incrementally: it is not freed | ||
| 166 | + incrementally, so every parsed element is kept until the whole document is | ||
| 167 | + read. To keep the memory usage low, get rid of the data which is not needed | ||
| 168 | + any more. | ||
| 169 | + | ||
| 170 | + If the processed elements are large, it is enough to clear them. | ||
| 171 | + This works wherever they are in the tree, | ||
| 172 | + but the emptied elements are left in it:: | ||
| 173 | + | ||
| 174 | + for event, elem in ET.iterparse(source): | ||
| 175 | + if elem.tag == 'record': | ||
| 176 | + process(elem) | ||
| 177 | + elem.clear() | ||
| 178 | + | ||
| 179 | + If an element has a large number of children, | ||
| 180 | + remove the processed children from it:: | ||
| 181 | + | ||
| 182 | + for event, elem in ET.iterparse(source, events=('start', 'end')): | ||
| 183 | + if event == 'start' and elem.tag == 'parent': | ||
| 184 | + parent = elem | ||
| 185 | + elif event == 'end' and elem.tag == 'child': | ||
| 186 | + process(elem) | ||
| 187 | + parent.remove(elem) | ||
| 188 | + | ||
| 189 | + These examples are not universal, | ||
| 190 | + they only give an idea for two common cases. | ||
| 191 | + If you do not need a tree at all, | ||
| 192 | + parse with :class:`XMLParser` and a custom target instead; | ||
| 193 | + it is not built then, and nothing has to be removed. | ||
| 165 | 194 | ||
| 166 | 195 | Where *immediate* feedback through events is wanted, calling method | |
| 167 | 196 | :meth:`XMLPullParser.flush` can help reduce delay; | |
@@ -643,6 +672,10 @@ Functions | |||
| 643 | 672 | for applications where blocking reads can't be made. For fully non-blocking | |
| 644 | 673 | parsing, see :class:`XMLPullParser`. | |
| 645 | 674 | ||
| 675 | + The tree is only built incrementally, it is not freed incrementally: | ||
| 676 | + every parsed element is kept until the whole document is read. | ||
| 677 | + See :ref:`elementtree-pull-parsing` for how to keep the memory usage low. | ||
| 678 | + | ||
| 646 | 679 | .. note:: | |
| 647 | 680 | ||
| 648 | 681 | :func:`iterparse` only guarantees that it has seen the ">" character of a | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -116,6 +116,14 @@ def test_bytes(self): | |||
| 116 | 116 | for s in [b"", b"Andr\xe8 Previn", b"abc", b" "*10000]: | |
| 117 | 117 | self.helper(s) | |
| 118 | 118 | ||
| 119 | + @support.cpython_only | ||
| 120 | + def test_bytes_singleton(self): | ||
| 121 | + for version in range(marshal.version + 1): | ||
| 122 | + for sample in [b"", b"x"]: | ||
| 123 | + new = marshal.loads(marshal.dumps(sample, version)) | ||
| 124 | + self.assertIs(new, sample) | ||
| 125 | + | ||
| 126 | + | ||
| 119 | 127 | class ExceptionTestCase(unittest.TestCase): | |
| 120 | 128 | def test_exceptions(self): | |
| 121 | 129 | new = marshal.loads(marshal.dumps(StopIteration)) | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,2 @@ | |||
| 1 | + :func:`marshal.load` and :func:`marshal.loads` can now get 1-byte string | ||
| 2 | + singletons. Patch by Victor Stinner. | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1388,16 +1388,12 @@ r_object(RFILE *p) | |||
| 1388 | 1388 | } | |
| 1389 | 1389 | break; | |
| 1390 | 1390 | } | |
| 1391 | - v = PyBytes_FromStringAndSize((char *)NULL, n); | ||
| 1392 | - if (v == NULL) | ||
| 1393 | - break; | ||
| 1394 | 1391 | ptr = r_string(n, p); | |
| 1395 | 1392 | if (ptr == NULL) { | |
| 1396 | - Py_DECREF(v); | ||
| 1397 | 1393 | break; | |
| 1398 | 1394 | } | |
| 1399 | - memcpy(PyBytes_AS_STRING(v), ptr, n); | ||
| 1400 | - retval = v; | ||
| 1395 | + // Get a singleton for 1-byte string | ||
| 1396 | + retval = PyBytes_FromStringAndSize(ptr, n); // can be NULL | ||
| 1401 | 1397 | R_REF(retval); | |
| 1402 | 1398 | break; | |
| 1403 | 1399 | } | |
| Back | FazBrowse Home | New Git URL |
0 commit comments