From 192d922697726dc59c7af1480a04e9fcd022cffc Mon Sep 17 00:00:00 2001 From: David Beazley Date: Thu, 7 May 2015 15:53:44 -0500 Subject: [PATCH 1/2] Fixed issue 63 --- CHANGES | 6 ++++++ ply/lex.py | 41 ++++++++++++++++++++++------------------- ply/yacc.py | 30 +++++++++++++++++++----------- 3 files changed, 47 insertions(+), 30 deletions(-) diff --git a/CHANGES b/CHANGES index fdda63fccbecd1fea842a517b12439a6706c8c16..91800a4d35d096be013fdb22436bb3cd24b695d9 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,11 @@ +Version 3.7 +--------------------- +05/07/15: beazley + Fixed regression in handling of table modules if specified as module + objects. See https://github.com/dabeaz/ply/issues/63 + Version 3.6 --------------------- 04/25/15: beazley If PLY is unable to create the 'parser.out' or 'parsetab.py' files due to permission issues, it now just issues a warning message and diff --git a/ply/lex.py b/ply/lex.py index 8ba2051d4a75af219118023ca3551afc5931dd4b..ed1e2ed9d965500afa405791cdd5d4e1f5ca7775 100644 --- a/ply/lex.py +++ b/ply/lex.py @@ -169,11 +169,14 @@ class Lexer: return c # ------------------------------------------------------------ # writetab() - Write lexer information to a table file # ------------------------------------------------------------ - def writetab(self, basetabmodule, outputdir=''): + def writetab(self, lextab, outputdir=''): + if isinstance(lextab, types.ModuleType): + raise IOError("Won't overwrite existing lextab module") + basetabmodule = lextab.split('.')[-1] filename = os.path.join(outputdir, basetabmodule) + '.py' with open(filename, 'w') as tf: tf.write('# %s.py. This file automatically created by PLY (version %s). Don\'t edit!\n' % (basetabmodule, __version__)) tf.write('_tabversion = %s\n' % repr(__tabversion__)) tf.write('_lextokens = %s\n' % repr(self.lextokens)) @@ -883,33 +886,17 @@ def lex(module=None, object=None, debug=False, optimize=False, lextab='lextab', if '__file__' not in ldict: ldict['__file__'] = sys.modules[ldict['__module__']].__file__ else: ldict = get_caller_module_dict(2) - if outputdir is None: - # If no output directory is set, the location of the output files - # is determined according to the following rules: - # - If lextab specifies a package, files go into that package directory - # - Otherwise, files go in the same directory as the specifying module - if '.' not in lextab: - srcfile = ldict['__file__'] - else: - parts = lextab.split('.') - pkgname = '.'.join(parts[:-1]) - exec('import %s' % pkgname) - srcfile = getattr(sys.modules[pkgname], '__file__', '') - outputdir = os.path.dirname(srcfile) - # Determine if the module is package of a package or not. # If so, fix the tabmodule setting so that tables load correctly pkg = ldict.get('__package__') - if pkg: + if pkg and isinstance(lextab, str): if '.' not in lextab: lextab = pkg + '.' + lextab - baselextab = lextab.split('.')[-1] - # Collect parser information from the dictionary linfo = LexerReflect(ldict, log=errorlog, reflags=reflags) linfo.get_all() if not optimize: if linfo.validate_all(): @@ -1027,12 +1014,28 @@ def lex(module=None, object=None, debug=False, optimize=False, lextab='lextab', input = lexobj.input lexer = lexobj # If in optimize mode, we write the lextab if lextab and optimize: + if outputdir is None: + # If no output directory is set, the location of the output files + # is determined according to the following rules: + # - If lextab specifies a package, files go into that package directory + # - Otherwise, files go in the same directory as the specifying module + if isinstance(lextab, types.ModuleType): + srcfile = lextab.__file__ + else: + if '.' not in lextab: + srcfile = ldict['__file__'] + else: + parts = lextab.split('.') + pkgname = '.'.join(parts[:-1]) + exec('import %s' % pkgname) + srcfile = getattr(sys.modules[pkgname], '__file__', '') + outputdir = os.path.dirname(srcfile) try: - lexobj.writetab(baselextab, outputdir) + lexobj.writetab(lextab, outputdir) except IOError as e: errorlog.warning("Couldn't write lextab module %r. %s" % (lextab, e)) return lexobj diff --git a/ply/yacc.py b/ply/yacc.py index f18e3ebbe596dd8eb833db9065cffe90d045c9f5..e0b4fafc9e2dca050b4d7311324b6b16aa9bd3bf 100644 --- a/ply/yacc.py +++ b/ply/yacc.py @@ -2690,11 +2690,15 @@ class LRGeneratedTable(LRTable): # write() # # This function writes the LR parsing tables to a file # ----------------------------------------------------------------------------- - def write_table(self, basemodulename, outputdir='', signature=''): + def write_table(self, tabmodule, outputdir='', signature=''): + if isinstance(tabmodule, types.ModuleType): + raise IOError("Won't overwrite existing tabmodule") + + basemodulename = tabmodule.split('.')[-1] filename = os.path.join(outputdir, basemodulename) + '.py' try: f = open(filename, 'w') f.write(''' @@ -3202,26 +3206,30 @@ def yacc(method='LALR', debug=yaccdebug, module=None, tabmodule=tab_module, star if outputdir is None: # If no output directory is set, the location of the output files # is determined according to the following rules: # - If tabmodule specifies a package, files go into that package directory # - Otherwise, files go in the same directory as the specifying module - if '.' not in tabmodule: - srcfile = pdict['__file__'] + if isinstance(tabmodule, types.ModuleType): + srcfile = tabmodule.__file__ else: - parts = tabmodule.split('.') - pkgname = '.'.join(parts[:-1]) - exec('import %s' % pkgname) - srcfile = getattr(sys.modules[pkgname], '__file__', '') + if '.' not in tabmodule: + srcfile = pdict['__file__'] + else: + parts = tabmodule.split('.') + pkgname = '.'.join(parts[:-1]) + exec('import %s' % pkgname) + srcfile = getattr(sys.modules[pkgname], '__file__', '') outputdir = os.path.dirname(srcfile) # Determine if the module is package of a package or not. # If so, fix the tabmodule setting so that tables load correctly pkg = pdict.get('__package__') - if pkg and '.' not in tabmodule: - tabmodule = pkg + '.' + tabmodule + if pkg and isinstance(tabmodule, str): + if '.' not in tabmodule: + tabmodule = pkg + '.' + tabmodule + - basetabmodule = tabmodule.split('.')[-1] # Set start symbol if it's specified directly using an argument if start is not None: pdict['start'] = start @@ -3430,11 +3438,11 @@ def yacc(method='LALR', debug=yaccdebug, module=None, tabmodule=tab_module, star warned_never.append(rejected) # Write the table file if requested if write_tables: try: - lr.write_table(basetabmodule, outputdir, signature) + lr.write_table(tabmodule, outputdir, signature) except IOError as e: errorlog.warning("Couldn't create %r. %s" % (tabmodule, e)) # Write a pickled version of the tables if picklefile: -- 2.4.3