+2024-03-24 Bruno Haible <bruno@clisp.org>
+
+ gnulib-tool.py: Use Python raw strings for regular expressions.
+ * pygnulib/*.py: Use raw string syntax for regular expression pattern
+ strings and repl strings.
+
2024-03-24 Bruno Haible <bruno@clisp.org>
gnulib-tool.py: Bring the output into the right order.
for line in snippet.split('\n')
if line.strip() ]
snippet = lines_to_multiline(lines)
- pattern = re.compile('^(.*)$', re.M)
- snippet = pattern.sub('%s\\1' % indentation, snippet)
+ pattern = re.compile(r'^(.*)$', re.M)
+ snippet = pattern.sub(r'%s\1' % indentation, snippet)
if disable_libtool:
snippet = snippet.replace('$gl_cond_libtool', 'false')
snippet = snippet.replace('gl_libdeps', 'gltests_libdeps')
else:
# Don't indent AM_GNU_GETTEXT_VERSION line, as that confuses
# autopoint through at least GNU gettext version 0.18.2.
- snippet = re.compile('^ *AM_GNU_GETTEXT_VERSION', re.M).sub('AM_GNU_GETTEXT_VERSION', snippet)
+ snippet = re.compile(r'^ *AM_GNU_GETTEXT_VERSION', re.M).sub(r'AM_GNU_GETTEXT_VERSION', snippet)
emit += snippet
if str(module) == 'alloca' and libtool and not disable_libtool:
emit += 'changequote(,)dnl\n'
emit += 'changequote([, ])dnl\n'
emit += 'AC_SUBST([LTALLOCA])'
if replace_auxdir:
- regex = 'AC_CONFIG_FILES\\(\\[(.*)\\:build-aux/(.*)\\]\\)'
- repl = 'AC_CONFIG_FILES([\\1:%s/\\2])' % auxdir
+ regex = r'AC_CONFIG_FILES\(\[(.*)\:build-aux/(.*)\]\)'
+ repl = r'AC_CONFIG_FILES([\1:%s/\2])' % auxdir
pattern = re.compile(regex, re.M)
emit = pattern.sub(repl, emit)
lines = [ line
amsnippet1 = amsnippet1.replace('lib_LIBRARIES', 'lib%_LIBRARIES')
amsnippet1 = amsnippet1.replace('lib_LTLIBRARIES', 'lib%_LTLIBRARIES')
if eliminate_LDFLAGS:
- pattern = re.compile('^(lib_LDFLAGS[\t ]*\\+=.*$\n)', re.M)
- amsnippet1 = pattern.sub('', amsnippet1)
+ pattern = re.compile(r'^(lib_LDFLAGS[\t ]*\+=.*$\n)', re.M)
+ amsnippet1 = pattern.sub(r'', amsnippet1)
# Replace NMD, so as to remove redundant "$(MKDIR_P) '.'" invocations.
# The logic is similar to how we define gl_source_base_prefix.
amsnippet1 = _eliminate_NMD(amsnippet1, automake_subdir)
- pattern = re.compile('lib_([A-Z][A-Z]*)', re.M)
- amsnippet1 = pattern.sub('%s_%s_\\1' % (libname, libext),
+ pattern = re.compile(r'lib_([A-Z][A-Z]*)', re.M)
+ amsnippet1 = pattern.sub(r'%s_%s_\1' % (libname, libext),
amsnippet1)
amsnippet1 = amsnippet1.replace('$(GNULIB_', '$(' + module_indicator_prefix + '_GNULIB_')
amsnippet1 = amsnippet1.replace('lib%_LIBRARIES', 'lib_LIBRARIES')
if str(module) == 'alloca':
amsnippet1 += '%s_%s_LIBADD += @%sALLOCA@\n' % (libname, libext, perhapsLT)
amsnippet1 += '%s_%s_DEPENDENCIES += @%sALLOCA@\n' % (libname, libext, perhapsLT)
- amsnippet1 = constants.combine_lines_matching(re.compile('%s_%s_SOURCES' % (libname, libext)),
+ amsnippet1 = constants.combine_lines_matching(re.compile(r'%s_%s_SOURCES' % (libname, libext)),
amsnippet1)
# Get unconditional snippet, edit it and save to amsnippet2.
amsnippet2 = module.getAutomakeSnippet_Unconditional()
- pattern = re.compile('lib_([A-Z][A-Z]*)', re.M)
- amsnippet2 = pattern.sub('%s_%s_\\1' % (libname, libext),
+ pattern = re.compile(r'lib_([A-Z][A-Z]*)', re.M)
+ amsnippet2 = pattern.sub(r'%s_%s_\1' % (libname, libext),
amsnippet2)
amsnippet2 = amsnippet2.replace('$(GNULIB_',
'$(' + module_indicator_prefix + '_GNULIB_')
# * https://debbugs.gnu.org/10997
# * https://debbugs.gnu.org/11030
# So we need this workaround.
- pattern = re.compile('^pkgdata_DATA *\\+=', re.M)
+ pattern = re.compile(r'^pkgdata_DATA *\+=', re.M)
if pattern.findall(allsnippets):
emit += 'pkgdata_DATA =\n'
emit += 'EXTRA_DIST =\n'
# it should not be installed.
# First test if allsnippets already specify an installation location.
lib_gets_installed = False
- regex = '^[a-zA-Z0-9_]*_%sLIBRARIES *\\+{0,1}= *%s\\.%s' % (perhapsLT, libname, libext)
+ regex = r'^[a-zA-Z0-9_]*_%sLIBRARIES *\+{0,1}= *%s\.%s' % (perhapsLT, libname, libext)
pattern = re.compile(regex, re.M)
if pattern.findall(allsnippets):
lib_gets_installed = True
for link in links
for line in link.split('\n')
if line != '' ]
- pattern = re.compile(' when linking with libtool.*')
- lines = [ pattern.sub('', line)
+ pattern = re.compile(r' when linking with libtool.*')
+ lines = [ pattern.sub(r'', line)
for line in lines ]
lines = sorted(set(lines))
for line in lines:
amsnippet1 = amsnippet1.replace('lib_LIBRARIES', 'lib%_LIBRARIES')
amsnippet1 = amsnippet1.replace('lib_LTLIBRARIES', 'lib%_LTLIBRARIES')
if eliminate_LDFLAGS:
- pattern = re.compile('^(lib_LDFLAGS[\t ]*\\+=.*$\n)', re.M)
- amsnippet1 = pattern.sub('', amsnippet1)
+ pattern = re.compile(r'^(lib_LDFLAGS[\t ]*\+=.*$\n)', re.M)
+ amsnippet1 = pattern.sub(r'', amsnippet1)
# Replace NMD, so as to remove redundant "$(MKDIR_P) '.'" invocations.
# The logic is similar to how we define gl_source_base_prefix.
amsnippet1 = _eliminate_NMD(amsnippet1, False)
- pattern = re.compile('lib_([A-Z][A-Z]*)', re.M)
- amsnippet1 = pattern.sub('libtests_a_\\1', amsnippet1)
+ pattern = re.compile(r'lib_([A-Z][A-Z]*)', re.M)
+ amsnippet1 = pattern.sub(r'libtests_a_\1', amsnippet1)
amsnippet1 = amsnippet1.replace('$(GNULIB_', '$(' + module_indicator_prefix + '_GNULIB_')
amsnippet1 = amsnippet1.replace('lib%_LIBRARIES', 'lib_LIBRARIES')
amsnippet1 = amsnippet1.replace('lib%_LTLIBRARIES', 'lib_LTLIBRARIES')
amsnippet1 += 'libtests_a_LIBADD += @ALLOCA@\n'
amsnippet1 += 'libtests_a_DEPENDENCIES += @ALLOCA@\n'
- amsnippet1 = constants.combine_lines_matching(re.compile('libtests_a_SOURCES'),
+ amsnippet1 = constants.combine_lines_matching(re.compile(r'libtests_a_SOURCES'),
amsnippet1)
# Get unconditional snippet, edit it and save to amsnippet2.
amsnippet2 = module.getAutomakeSnippet_Unconditional()
- pattern = re.compile('lib_([A-Z][A-Z]*)', re.M)
- amsnippet2 = pattern.sub('libtests_a_\\1', amsnippet2)
+ pattern = re.compile(r'lib_([A-Z][A-Z]*)', re.M)
+ amsnippet2 = pattern.sub(r'libtests_a_\1', amsnippet2)
amsnippet2 = amsnippet2.replace('$(GNULIB_',
'$(' + module_indicator_prefix + '_GNULIB_')
# Skip the contents if it's entirely empty.
# * https://debbugs.gnu.org/10997
# * https://debbugs.gnu.org/11030
# So we need this workaround.
- pattern = re.compile('^pkgdata_DATA *\\+=', re.M)
+ pattern = re.compile(r'^pkgdata_DATA *\+=', re.M)
if pattern.findall(main_snippets) or pattern.findall(longrun_snippets):
emit += 'pkgdata_DATA =\n'
data = file.read()
# Create regex object and keys.
- pattern = re.compile('^(gl_.*?)\\((.*?)\\)$', re.S | re.M)
+ pattern = re.compile(r'^(gl_.*?)\((.*?)\)$', re.S | re.M)
keys = \
[
'gl_LOCAL_DIR', 'gl_MODULES', 'gl_AVOID', 'gl_SOURCE_BASE',
if isfile(path):
with codecs.open(path, 'rb', 'UTF-8') as file:
data = file.read()
- regex = 'AC_DEFUN\\(\\[%s_FILE_LIST\\], \\[(.*?)\\]\\)' % self.cache['macro_prefix']
+ regex = r'AC_DEFUN\(\[%s_FILE_LIST\], \[(.*?)\]\)' % self.cache['macro_prefix']
pattern = re.compile(regex, re.S | re.M)
self.cache.setFiles(pattern.findall(data)[-1].strip().split())
notice = module.getNotice().strip('\n')
if notice:
print('Notice from module %s:' % str(module))
- pattern = re.compile('^(.*?)$', re.S | re.M)
- notice = pattern.sub(' \\1', notice)
+ pattern = re.compile(r'^(.*?)$', re.S | re.M)
+ notice = pattern.sub(r' \1', notice)
print(notice)
# Determine script to apply to imported library files.
with codecs.open(configure_ac, 'rb', 'UTF-8') as file:
data = file.read()
match_result1 = \
- bool(re.compile('^ *AC_PROG_CC_STDC', re.M).findall(data))
+ bool(re.compile(r'^ *AC_PROG_CC_STDC', re.M).findall(data))
match_result2 = \
- bool(re.compile('^ *AC_PROG_CC_C99', re.M).findall(data))
+ bool(re.compile(r'^ *AC_PROG_CC_C99', re.M).findall(data))
if match_result1:
print(' - replace AC_PROG_CC_STDC with AC_PROG_CC in %s,' % (configure_ac))
position_early_after = 'AC_PROG_CC_STDC'
The special __copyright__ variable is used (type is str).'''
copyright = __copyright__
# Per the GNU Coding Standards, show only the last year.
- copyright = re.compile('^[0-9]*-').sub('', copyright)
+ copyright = re.compile(r'^[0-9]*-').sub(r'', copyright)
result = 'Copyright (C) %s' % copyright
return result
args = ['git', 'log', '-n', '1', '--format=medium', '--date=iso', 'ChangeLog']
result = sp.check_output(args, cwd=DIRS['root']).decode("UTF-8")
# Get date as "2008-03-21 07:16:51 -0600" from string
- pattern = re.compile('^Date:[\t ]*(.*?)$', re.M)
+ pattern = re.compile(r'^Date:[\t ]*(.*?)$', re.M)
result = pattern.findall(result)
if (len(result) > 0):
result = result[0]
with codecs.open(os.path.join(DIRS['root'], 'ChangeLog'), 'rb', 'UTF-8') as file:
line = file.readline()
first_changelog_line = line.rstrip()
- result = re.compile(' .*').sub('', first_changelog_line)
+ result = re.compile(r' .*').sub(r'', first_changelog_line)
return result
def copyright_range(self):
listing = [ subend('.diff', '', line)
for line in listing ]
# Remove modules/ prefix from each file name.
- pattern = re.compile('^modules/')
- listing = [ pattern.sub('', line)
+ pattern = re.compile(r'^modules/')
+ listing = [ pattern.sub(r'', line)
for line in listing ]
# Filter out undesired file names.
listing = [ line
files, etc.'''
section_label_pattern = \
- re.compile('^(Description|Comment|Status|Notice|Applicability|'
- + 'Files|Depends-on|configure\\.ac-early|configure\\.ac|'
- + 'Makefile\\.am|Include|Link|License|Maintainer):$',
+ re.compile(r'^(Description|Comment|Status|Notice|Applicability|'
+ + r'Files|Depends-on|configure\.ac-early|configure\.ac|'
+ + r'Makefile\.am|Include|Link|License|Maintainer):$',
re.M)
# List of characters allowed in shell identifiers.
# Then the explicit dependencies listed in the module description.
snippet = self.sections.get('Depends-on', '')
# Remove comment lines.
- snippet = re.compile('^#.*$[\n]', re.M).sub('', snippet)
+ snippet = re.compile(r'^#.*$[\n]', re.M).sub(r'', snippet)
result += snippet
self.cache['dependencies'] = result
return self.cache['dependencies']
lines = [ line.strip()
for line in snippet.split('\n')
if line.strip() ]
- pattern = re.compile(' *\\[.*$')
- lines = [ pattern.sub('', line)
+ pattern = re.compile(r' *\[.*$')
+ lines = [ pattern.sub(r'', line)
for line in lines ]
result = [ self.modulesystem.find(module)
for module in lines
lines = [ line.strip()
for line in snippet.split('\n')
if line.strip() ]
- pattern = re.compile(' *\\[')
+ pattern = re.compile(r' *\[')
result = []
for line in lines:
match = pattern.search(line)
Return include directive.'''
if 'include' not in self.cache:
snippet = self.sections.get('Include', '')
- pattern = re.compile('^(["<])', re.M)
- result = pattern.sub('#include \\1', snippet)
+ pattern = re.compile(r'^(["<])', re.M)
+ result = pattern.sub(r'#include \1', snippet)
self.cache['include'] = result
return self.cache['include']
# Extract the value of unconditional "lib_SOURCES += ..." augmentations.
snippet = constants.remove_backslash_newline(snippet)
snippet = self.remove_if_blocks(snippet)
- pattern = re.compile('^lib_SOURCES[\t ]*\\+=([^#]*).*$', re.M)
+ pattern = re.compile(r'^lib_SOURCES[\t ]*\+=([^#]*).*$', re.M)
for matching_rhs in pattern.findall(snippet):
files = matching_rhs.split(' ')
for file in files:
notice = module.getNotice().strip('\n')
if notice:
print('Notice from module %s:' % str(module))
- pattern = re.compile('^(.*)$', re.M)
- notice = pattern.sub(' \\1', notice)
+ pattern = re.compile(r'^(.*)$', re.M)
+ notice = pattern.sub(r' \1', notice)
print(notice)
else: # if not single_configure
if verbose >= -1:
notice = module.getNotice().strip('\n')
if notice:
print('Notice from module %s:' % str(module))
- pattern = re.compile('^(.*)$', re.M)
- notice = pattern.sub(' \\1', notice)
+ pattern = re.compile(r'^(.*)$', re.M)
+ notice = pattern.sub(r' \1', notice)
print(notice)
# Determine final file list.
for line in snippet.split('\n')
if line.strip() ]
snippet = lines_to_multiline(lines)
- pattern = re.compile('AC_REQUIRE\\(\\[([^()]*)\\]\\)', re.M)
- snippet = pattern.sub('\\1', snippet)
+ pattern = re.compile(r'AC_REQUIRE\(\[([^()]*)\]\)', re.M)
+ snippet = pattern.sub(r'\1', snippet)
snippet = snippet.strip()
snippets += [snippet]
snippets = [ snippet
for line in snippet.split('\n')
if line.strip() ]
snippet = lines_to_multiline(lines)
- pattern = re.compile('AC_REQUIRE\\(\\[([^()]*)\\]\\)', re.M)
- snippet = pattern.sub('\\1', snippet)
+ pattern = re.compile(r'AC_REQUIRE\(\[([^()]*)\]\)', re.M)
+ snippet = pattern.sub(r'\1', snippet)
snippet = snippet.strip()
snippets += [snippet]
snippets = [ snippet
# Extract the value of "CLEANFILES += ..." and "MOSTLYCLEANFILES += ...".
regex_find = list()
- pattern = re.compile('^CLEANFILES[\t ]*\\+=(.*)$', re.M)
+ pattern = re.compile(r'^CLEANFILES[\t ]*\+=(.*)$', re.M)
regex_find += pattern.findall(snippet)
- pattern = re.compile('^MOSTLYCLEANFILES[\t ]*\\+=(.*)$', re.M)
+ pattern = re.compile(r'^MOSTLYCLEANFILES[\t ]*\+=(.*)$', re.M)
regex_find += pattern.findall(snippet)
regex_find = [ line.strip()
for line in regex_find
# Extract the value of "BUILT_SOURCES += ...". Remove variable references
# such $(FOO_H) because they don't refer to distributed files.
regex_find = list()
- pattern = re.compile('^BUILT_SOURCES[\t ]*\\+=(.*)$', re.M)
+ pattern = re.compile(r'^BUILT_SOURCES[\t ]*\+=(.*)$', re.M)
regex_find += pattern.findall(snippet)
regex_find = [ line.strip()
for line in regex_find
if line.strip()]
built_sources = [ line
for line in built_sources
- if not bool(re.compile('[$]\\([A-Za-z0-9_]*\\)$').findall(line)) ]
+ if not bool(re.compile(r'[$]\([A-Za-z0-9_]*\)$').findall(line)) ]
distributed_built_sources = [ file
for file in built_sources
if file not in cleaned_files ]
# Extract the value of "CLEANFILES += ..." and "MOSTLYCLEANFILES += ...".
regex_find = list()
- pattern = re.compile('^CLEANFILES[\t ]*\\+=(.*)$', re.M)
+ pattern = re.compile(r'^CLEANFILES[\t ]*\+=(.*)$', re.M)
regex_find += pattern.findall(snippet)
- pattern = re.compile('^MOSTLYCLEANFILES[\t ]*\\+=(.*)$', re.M)
+ pattern = re.compile(r'^MOSTLYCLEANFILES[\t ]*\+=(.*)$', re.M)
regex_find += pattern.findall(snippet)
regex_find = [ line.strip()
for line in regex_find
# Extract the value of "BUILT_SOURCES += ...". Remove variable references
# such $(FOO_H) because they don't refer to distributed files.
regex_find = list()
- pattern = re.compile('^BUILT_SOURCES[\t ]*\\+=(.*)$', re.M)
+ pattern = re.compile(r'^BUILT_SOURCES[\t ]*\+=(.*)$', re.M)
regex_find += pattern.findall(snippet)
regex_find = [ line.strip()
for line in regex_find
if line.strip() ]
tests_built_sources = [ line
for line in tests_built_sources
- if not bool(re.compile('[$]\\([A-Za-z0-9_]*\\)$').findall(line)) ]
+ if not bool(re.compile(r'[$]\([A-Za-z0-9_]*\)$').findall(line)) ]
tests_distributed_built_sources = [ file
for file in tests_built_sources
if file not in tests_cleaned_files]
listing = list()
for filename in filelist:
if filename.startswith(prefix) and filename.endswith(suffix):
- pattern = re.compile('^%s(.*)%s$'
+ pattern = re.compile(r'^%s(.*)%s$'
% (removed_prefix, removed_suffix))
- result = pattern.sub('%s\\1%s'
+ result = pattern.sub(r'%s\1%s'
% (added_prefix, added_suffix), filename)
listing += [result]
# Return an empty string if no files were matched, else combine them
# Do use line breaks to separate the parts of [ ... for ... ] iterations.
# - String literals: Use 'single-quotes'.
# Rationale: <https://lists.gnu.org/archive/html/bug-gnulib/2024-02/msg00226.html>
+# - Use raw string syntax for regular expression pattern strings and repl
+# strings:
+# re.compile(r'...').sub(r'...', ...)
+# re.sub(r'...', r'...', ...)
+# Rationale: This avoids the need to double backslashes, making the pattern
+# and repl strings easier to understand.
# - Comparison operators:
# Use == and != for variables which can contain only strings, numbers, lists,
# and None.
# Convert the file name to a POSIX basic regex.
# Needs to handle . [ \ * ^ $.
filename_regex = filename.replace('\\', '\\\\').replace('[', '\\[').replace('^', '\\^')
- filename_regex = re.compile('([.*$])').sub('[\\1]', filename_regex)
+ filename_regex = re.compile(r'([.*$])').sub(r'[\1]', filename_regex)
filename_line_regex = '^' + filename_regex + '$'
# Read module candidates from gnulib root directory.
command = "find modules -type f -print | xargs -n 100 grep -l %s /dev/null | sed -e 's,^modules/,,'" % shlex.quote(filename_line_regex)
for line in result.split('\n')
if line.strip() ]
# Remove modules/ prefix from each file name.
- pattern = re.compile('^modules/')
+ pattern = re.compile(r'^modules/')
listing = [ pattern.sub('', line)
for line in listing ]
# Filter out undesired file names.