File tree Expand file tree Collapse file tree 5 files changed +45
-2
lines changed
Misc/NEWS.d/next/Tools-Demos Expand file tree Collapse file tree 5 files changed +45
-2
lines changed Original file line number Diff line number Diff line change 20
20
import io
21
21
import os
22
22
import logging
23
+ import pkgutil
23
24
import sys
24
25
25
26
# Pgen imports
@@ -143,6 +144,26 @@ def _newer(a, b):
143
144
return os .path .getmtime (a ) >= os .path .getmtime (b )
144
145
145
146
147
+ def load_packaged_grammar (package , grammar_source ):
148
+ """Normally, loads a pickled grammar by doing
149
+ pkgutil.get_data(package, pickled_grammar)
150
+ where *pickled_grammar* is computed from *grammar_source* by adding the
151
+ Python version and using a ``.pickle`` extension.
152
+
153
+ However, if *grammar_source* is an extant file, load_grammar(grammar_source)
154
+ is called instead. This facilities using a packaged grammar file when needed
155
+ but preserves load_grammar's automatic regeneration behavior when possible.
156
+
157
+ """
158
+ if os .path .isfile (grammar_source ):
159
+ return load_grammar (grammar_source )
160
+ pickled_name = _generate_pickle_name (os .path .basename (grammar_source ))
161
+ data = pkgutil .get_data (package , pickled_name )
162
+ g = grammar .Grammar ()
163
+ g .loads (data )
164
+ return g
165
+
166
+
146
167
def main (* args ):
147
168
"""Main program, when run as a script: produce grammar pickle files.
148
169
Original file line number Diff line number Diff line change @@ -108,6 +108,10 @@ def load(self, filename):
108
108
d = pickle .load (f )
109
109
self .__dict__ .update (d )
110
110
111
+ def loads (self , pkl ):
112
+ """Load the grammar tables from a pickle bytes object."""
113
+ self .__dict__ .update (pickle .loads (pkl ))
114
+
111
115
def copy (self ):
112
116
"""
113
117
Copy the grammar.
Original file line number Diff line number Diff line change @@ -29,12 +29,12 @@ def __init__(self, grammar):
29
29
setattr (self , name , symbol )
30
30
31
31
32
- python_grammar = driver .load_grammar ( _GRAMMAR_FILE )
32
+ python_grammar = driver .load_packaged_grammar ( "lib2to3" , _GRAMMAR_FILE )
33
33
34
34
python_symbols = Symbols (python_grammar )
35
35
36
36
python_grammar_no_print_statement = python_grammar .copy ()
37
37
del python_grammar_no_print_statement .keywords ["print" ]
38
38
39
- pattern_grammar = driver .load_grammar ( _PATTERN_GRAMMAR_FILE )
39
+ pattern_grammar = driver .load_packaged_grammar ( "lib2to3" , _PATTERN_GRAMMAR_FILE )
40
40
pattern_symbols = Symbols (pattern_grammar )
Original file line number Diff line number Diff line change 12
12
from test .support import verbose
13
13
14
14
# Python imports
15
+ import importlib
16
+ import operator
15
17
import os
18
+ import pickle
16
19
import shutil
17
20
import subprocess
18
21
import sys
@@ -99,6 +102,18 @@ def test_load_grammar_from_subprocess(self):
99
102
finally :
100
103
shutil .rmtree (tmpdir )
101
104
105
+ def test_load_packaged_grammar (self ):
106
+ modname = __name__ + '.load_test'
107
+ class MyLoader :
108
+ def get_data (self , where ):
109
+ return pickle .dumps ({'elephant' : 19 })
110
+ class MyModule :
111
+ __file__ = 'parsertestmodule'
112
+ __spec__ = importlib .util .spec_from_loader (modname , MyLoader ())
113
+ sys .modules [modname ] = MyModule ()
114
+ self .addCleanup (operator .delitem , sys .modules , modname )
115
+ g = pgen2_driver .load_packaged_grammar (modname , 'Grammar.txt' )
116
+ self .assertEqual (g .elephant , 19 )
102
117
103
118
104
119
class GrammarTest (support .TestCase ):
Original file line number Diff line number Diff line change
1
+ 2to3 and lib2to3 can now read pickled grammar files using pkgutil.get_data()
2
+ rather than probing the filesystem. This lets 2to3 and lib2to3 work when run
3
+ from a zipfile.
You can’t perform that action at this time.
0 commit comments