This updates the Python scripts shipped with GROMACS to use Python 3.5+.
Most changes done are either due to `__cmp__` not being available in py3
(replaced by `functools.total_ordering`), py2-iterators being replaced by
py3-iterators, or print statements being replaced by functions.
Additionaly, some changes in the Cmake files were made to select the
different Python version.
All python scripts having an explicit `#!/usr/bin/env python2` as a first
line were checked and updated. Larger changes were only needed for the
documentation scripts, other scripts did not require any changes. Scripts
not explicitly using shebangs were also checked, but no changes were
needed. The following scripts were not touched:
- all scripts under tests/physicalvalidation/ (already py3 compatible)
- all scripts under python_packaging/
- scripts/make_gromos_rtp.py - this file is not valid py2.7
Refs #2615
Change-Id: I2edbe213bc6401563934ce56f5fd6a39886d3095
-#!/usr/bin/env python
+#!/usr/bin/env python3
#
# This file is part of the GROMACS molecular simulation package.
#
-# Copyright (c) 2013,2014,2015,2016,2018, by the GROMACS development team, led by
+# Copyright (c) 2013,2014,2015,2016,2018,2019, by the GROMACS development team, led by
# Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
# and including many others, as listed in the AUTHORS file in the
# top-level source directory and at http://www.gromacs.org.
#
# This file is part of the GROMACS molecular simulation package.
#
-# Copyright (c) 2015, by the GROMACS development team, led by
+# Copyright (c) 2015,2019, by the GROMACS development team, led by
# Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
# and including many others, as listed in the AUTHORS file in the
# top-level source directory and at http://www.gromacs.org.
# Adapted from code posted on cmake-users by Mark Moll (the execute_process()
# call remains, but other things have been rewritten for nicer behavior).
-find_package(PythonInterp 2.7)
+find_package(PythonInterp 3.5)
function (find_python_module module)
string(TOUPPER ${module} _module_upper)
# A module's location is usually a directory, but for binary modules
# it's a .so file.
execute_process(COMMAND "${PYTHON_EXECUTABLE}" "-c"
- "import re, ${module}; print re.compile('/__init__.py.*').sub('',${module}.__file__)"
+ "import re, ${module}; print(re.compile('/__init__.py.*').sub('',${module}.__file__))"
RESULT_VARIABLE _status
OUTPUT_VARIABLE _location
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
#
# This file is part of the GROMACS molecular simulation package.
#
-# Copyright (c) 2015,2018, by the GROMACS development team, led by
+# Copyright (c) 2015,2018,2019, by the GROMACS development team, led by
# Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
# and including many others, as listed in the AUTHORS file in the
# top-level source directory and at http://www.gromacs.org.
if (Sphinx_FIND_QUIETLY)
set(_find_deps_options QUIET)
endif()
-include(FindPythonModule)
-find_python_module(pygments ${_find_deps_options})
-if (PYTHONMODULE_PYGMENTS)
+execute_process(COMMAND "${PYTHON_EXECUTABLE}" "-c"
+ "import pygments"
+ RESULT_VARIABLE _pygments_status
+ ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
+if (_pygments_status)
set(Sphinx_pygments_FOUND 1)
endif()
# Keep quiet on subsequent runs of cmake
set(PythonInterp_FIND_QUIETLY ON)
endif()
-find_package(PythonInterp 2.7)
-
-
-if (NOT ${PYTHON_VERSION_MAJOR} EQUAL 3)
- find_package(Sphinx ${EXPECTED_SPHINX_VERSION} QUIET COMPONENTS pygments)
-else()
- MESSAGE(STATUS "Can not build documentation with Python 3")
-endif()
+find_package(PythonInterp 3.5)
+find_package(Sphinx ${EXPECTED_SPHINX_VERSION} QUIET COMPONENTS pygments)
# Even if we aren't going to make the full webpage, set up to put all
# the documentation output in the same place, for convenience
set(MANUAL_BUILD_NOT_POSSIBLE_REASON "the build is in-source")
else()
include(manual/UseLATEX.cmake)
- if(${PYTHON_VERSION_MAJOR} EQUAL 3)
- set(MANUAL_BUILD_IS_POSSIBLE OFF)
- set(MANUAL_BUILD_NOT_POSSIBLE_REASON "We can not build the documentation when using python3")
- elseif(NOT SPHINX_FOUND)
+ if(NOT SPHINX_FOUND)
set(MANUAL_BUILD_IS_POSSIBLE OFF)
set(MANUAL_BUILD_NOT_POSSIBLE_REASON "Sphinx has not been found and is needed to create the LaTex input files")
elseif(NOT PDFLATEX_COMPILER)
DEPENDS sphinx-programs
DEPENDS sphinx-input
DEPENDS sphinx-image-conversion
- DEPENDS manual
+ DEPENDS manual
COMMAND
${CMAKE_COMMAND} -E make_directory ${SPHINX_INPUT_DIR}/_static
COMMAND
#
# This file is part of the GROMACS molecular simulation package.
#
-# Copyright (c) 2015,2016,2017,2018, by the GROMACS development team, led by
+# Copyright (c) 2015,2016,2017,2018,2019, by the GROMACS development team, led by
# Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
# and including many others, as listed in the AUTHORS file in the
# top-level source directory and at http://www.gromacs.org.
import os
import sys
-execfile('conf-vars.py')
+exec(open('conf-vars.py').read())
sys.path.append(gmx_sphinx_extension_path)
if releng_path and os.path.isdir(releng_path):
sys.path.append(releng_path)
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
if tags.has('do_man'):
- execfile('conf-man.py')
+ exec(open('conf-man.py').read())
# If true, show URL addresses after external links.
#man_show_urls = False
mark_as_advanced(GMX_COMPACT_DOXYGEN)
set(USE_PYTHON_SCRIPTS OFF)
-if (PYTHONINTERP_FOUND AND NOT PYTHON_VERSION_STRING VERSION_LESS "2.6" AND NOT ${PYTHON_VERSION_MAJOR} EQUAL 3)
+if (PYTHONINTERP_FOUND)
set(USE_PYTHON_SCRIPTS ON)
endif()
-#!/usr/bin/env python2
+#!/usr/bin/env python3
#
# This file is part of the GROMACS molecular simulation package.
#
-# Copyright (c) 2014,2015,2018, by the GROMACS development team, led by
+# Copyright (c) 2014,2015,2018,2019, by the GROMACS development team, led by
# Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
# and including many others, as listed in the AUTHORS file in the
# top-level source directory and at http://www.gromacs.org.
# Only report cycles to nodes that haven't been processed
# yet to avoid duplicates.
elif linkorder[nextnode] == preorder[nextnode]:
- for index in xrange(len(currlist)):
- if currlist[index][0] == nextnode:
+ for index, node in enumerate(currlist):
+ if node[0] == nextnode:
cycle = [(nextnode, edge)]
cycle.extend(currlist[index+1:])
graph.report_cycle(cycle, reporter)
-#!/usr/bin/env python2
+#!/usr/bin/env python3
#
# This file is part of the GROMACS molecular simulation package.
#
-# Copyright (c) 2014,2015,2016,2018, by the GROMACS development team, led by
+# Copyright (c) 2014,2015,2016,2018,2019, by the GROMACS development team, led by
# Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
# and including many others, as listed in the AUTHORS file in the
# top-level source directory and at http://www.gromacs.org.
import os.path
import xml.etree.ElementTree as ET
+import functools
import reporter
def _show_list(title, objlist):
"""Helper function for formatting a list of objects for debug output."""
if objlist:
- print '{0}:'.format(title)
+ print('{0}:'.format(title))
for obj in objlist:
- print ' ', obj
+ print(' ', obj)
+@functools.total_ordering
class DocType(object):
"""Documentation visibility in the generated documentation."""
"""Return string representation for the documentation type."""
return self._names[self._value]
- def __cmp__(self, other):
+ def __eq__(self, other):
"""Order documentation types in the order of visibility."""
- return cmp(self._value, other._value)
+ return self._value == other._value
+
+ def __lt__(self, other):
+ """Order documentation types in the order of visibility."""
+ return self._value < other._value
# Static values for documentation types.
DocType.none = DocType(0)
def get_full_string(self):
return '{0}:{1}:{2}'.format(self.filepath, self.line, self.column)
+@functools.total_ordering
class BodyLocation(object):
"""Body location of a Doxygen entity.
self.startline = int(elem.attrib['bodystart'])
self.endline = int(elem.attrib['bodyend'])
- def __cmp__(self, other):
- result = cmp(self.filepath, other.filepath)
- if result == 0:
- result = cmp(self.startline, other.startline)
- if result == 0:
- result = cmp(self.endline, other.endline)
- return result
+ def __eq__(self, other):
+ return (self.filepath == other.filepath and
+ self.startline == other.startline and
+ self.endline == other.endline)
+
+ def __lt__(self, other):
+ if self.filepath != other.filepath:
+ if other.filepath is None:
+ return False
+ if self.filepath is None:
+ return True
+ return self.filepath < other.filepath
+ elif self.startline != other.startline:
+ return self.startline < other.startline
+ else: # check for endline
+ return self.endline < other.endline
def __hash__(self):
return hash(self.filepath) ^ hash(self.startline) ^ hash(self.endline)
This is called from subclass show() methods to show base information
about the entity.
"""
- print 'ID: {0}'.format(self._id)
- print 'Name: {0}'.format(self._name)
- print 'Location: {0}'.format(self.get_reporter_location())
+ print('ID: {0}'.format(self._id))
+ print('Name: {0}'.format(self._name))
+ print('Location: {0}'.format(self.get_reporter_location()))
doctype = []
if self._has_brief_description:
doctype.append('brief')
doctype.append('in-body')
if not doctype:
doctype.append('none')
- print 'Doc: {0}'.format(', '.join(doctype))
- print 'Visibility: {0}'.format(self._visibility)
+ print('Doc: {0}'.format(', '.join(doctype)))
+ print('Visibility: {0}'.format(self._visibility))
# Member entities
self.show_base()
if self._alternates:
idlist = [x.get_id() for x in self._alternates]
- print 'Alt. IDs: {0}'.format(', '.join(idlist))
- print 'Parent vis: {0}'.format(self.get_inherited_visibility())
- print 'Location: {0}'.format(self.get_location().get_full_string())
- print 'Body loc: {0}'.format(self.get_body_location().get_full_string())
+ print('Alt. IDs: {0}'.format(', '.join(idlist)))
+ print('Parent vis: {0}'.format(self.get_inherited_visibility()))
+ print('Location: {0}'.format(self.get_location().get_full_string()))
+ print('Body loc: {0}'.format(self.get_body_location().get_full_string()))
_show_list('Parents', self._parents)
class Define(Member):
"""
Entity.show_base(self)
if self._groups:
- print 'Groups: {0}'.format(', '.join(map(str, self._groups)))
+ print('Groups: {0}'.format(', '.join(map(str, self._groups))))
def show_members(self):
"""Show list of members.
to print the list of members.
"""
for section in self._sections:
- print 'Member section: {0}'.format(section)
+ print('Member section: {0}'.format(section))
for member in section._members:
- print ' ', member
+ print(' ', member)
class File(Compound):
def __init__(self, name, refid):
def show(self):
self.show_base()
- print 'Path: {0}'.format(self._path)
- print 'Directory: {0}'.format(self._directory)
- print 'Source: {0}'.format(self._is_source_file)
+ print('Path: {0}'.format(self._path))
+ print('Directory: {0}'.format(self._directory))
+ print('Source: {0}'.format(self._is_source_file))
_show_list('Namespaces', self._namespaces)
_show_list('Classes', self._classes)
self.show_members()
def show(self):
self.show_base()
- print 'Path: {0}'.format(self._path)
+ print('Path: {0}'.format(self._path))
if self._parent:
- print 'Parent: {0}'.format(self._parent)
+ print('Parent: {0}'.format(self._parent))
_show_list('Subdirectories', self._subdirs)
_show_list('Files', self._files)
def show(self):
self.show_base()
- print 'Title: {0}'.format(self._title)
- print 'Inner compounds:'
+ print('Title: {0}'.format(self._title))
+ print('Inner compounds:')
for compound in self._children:
- print ' ', compound
+ print(' ', compound)
self.show_members()
class Namespace(Compound):
def show(self):
self.show_base()
- print 'Doc. loc.: {0}'.format(self._doclocation.get_full_string())
+ print('Doc. loc.: {0}'.format(self._doclocation.get_full_string()))
_show_list('Inner namespaces', self._innernamespaces)
_show_list('Classes', self._classes)
self.show_members()
def show(self):
self.show_base()
- print 'Namespace: {0}'.format(self._namespace)
+ print('Namespace: {0}'.format(self._namespace))
if self._outerclass:
- print 'Outer cls: {0}'.format(self._outerclass)
+ print('Outer cls: {0}'.format(self._outerclass))
location = self._location
- print 'Location: {0}'.format(location.get_location().get_full_string())
- print 'Body loc: {0}'.format(location.get_body_location().get_full_string())
+ print('Location: {0}'.format(location.get_location().get_full_string()))
+ print('Body loc: {0}'.format(location.get_body_location().get_full_string()))
_show_list('Inner classes', self._innerclasses)
self.show_members()
If filelist is set, it should be a list of file paths, and details will
be loaded only for files in those paths. The paths should be relative
to the root of the Gromacs source tree."""
- for compound in self._compounds.itervalues():
+ for compound in self._compounds.values():
if isinstance(compound, (Directory, Group)):
compound.load_details()
elif not filelist and isinstance(compound, File):
# details are loaded, because Doxygen does not write that into
# index.xml. But we can use the Directory objects (where the name
# is the relative path) to get the path.
- for compound in self._compounds.itervalues():
+ for compound in self._compounds.values():
if isinstance(compound, File):
dirobj = compound.get_directory()
if not dirobj:
def load_details(self):
"""Load detailed XML files for each compound."""
- for compound in self._compounds.itervalues():
+ for compound in self._compounds.values():
compound.load_details()
if isinstance(compound, File):
self._files[compound.get_path()] = compound
method.
"""
members_by_body = dict()
- for member in self._members.itervalues():
+ for member in self._members.values():
bodyloc = member.get_body_location()
if bodyloc:
index = (bodyloc, type(member), member.get_name())
if index not in members_by_body:
members_by_body[index] = []
members_by_body[index].append(member)
- for memberlist in members_by_body.itervalues():
+ for memberlist in members_by_body.values():
if len(memberlist) > 1:
declaration = None
otherdeclarations = []
def get_compounds(self, types, predicate=None):
result = []
- for compound in self._compounds.itervalues():
+ for compound in self._compounds.values():
if isinstance(compound, types) and \
(predicate is None or predicate(compound)):
result.append(compound)
def get_members(self, types=None, predicate=None):
# self._members can contain duplicates because of merge_duplicates()
result = set()
- for member in self._members.itervalues():
+ for member in self._members.values():
if (types is None or isinstance(member, types)) and \
(predicate is None or predicate(member)):
result.add(member)
-#!/usr/bin/env python2
+#!/usr/bin/env python3
#
# This file is part of the GROMACS molecular simulation package.
#
else:
return '"{0}"'.format(self._included_path)
+ def __lt__(self, other):
+ return str(self) < str(other)
+
def is_system(self):
return self._is_system
The return value is empty if find_define_file_uses() has not been called,
as well as for headers that declare these defines."""
- return set(self._used_defines.iterkeys())
+ return set(self._used_defines.keys())
def get_used_defines(self, define_file):
"""Return set of defines used in this file for a given file like config.h.
return self._group
def get_dependencies(self):
- return self._dependencies.itervalues()
+ return self._dependencies.values()
class Namespace(object):
if only_files:
filelist = only_files
else:
- filelist = self._files.itervalues()
+ filelist = self._files.values()
define_files = list(self.get_checked_define_files())
for define_file in list(define_files):
if isinstance(define_file, GeneratedFile) and \
args = ['git', 'check-attr', '--stdin', 'filter']
git_check_attr = subprocess.Popen(args, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, cwd=self._source_root)
- filelist = '\n'.join(map(File.get_relpath, self._files.itervalues()))
- filters = git_check_attr.communicate(filelist)[0]
+ filelist = '\n'.join(map(File.get_relpath, self._files.values()))
+ filters = git_check_attr.communicate(filelist.encode())[0].decode()
for fileinfo in filters.splitlines():
path, dummy, value = fileinfo.split(': ')
fileobj = self._files.get(path)
args.extend(['-e', define])
args.extend(['--', '*.cpp', '*.c', '*.cu', '*.h', '*.cuh'])
define_re = r'\b(?:' + '|'.join(all_defines)+ r')\b'
- output = subprocess.check_output(args, cwd=self._source_root)
+ output = subprocess.check_output(args, cwd=self._source_root).decode()
for line in output.splitlines():
(filename, text) = line.split('\0')
fileobj = self._files.get(filename)
def get_files(self):
"""Get iterable for all files in the source tree."""
- return self._files.itervalues()
+ return self._files.values()
def get_modules(self):
"""Get iterable for all modules in the source tree."""
- return self._modules.itervalues()
+ return self._modules.values()
def get_classes(self):
"""Get iterable for all classes in the source tree."""
-#!/usr/bin/env python2
+#!/usr/bin/env python3
#
# This file is part of the GROMACS molecular simulation package.
#
-# Copyright (c) 2012,2013,2014,2015,2018, by the GROMACS development team, led by
+# Copyright (c) 2012,2013,2014,2015,2018,2019, by the GROMACS development team, led by
# Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
# and including many others, as listed in the AUTHORS file in the
# top-level source directory and at http://www.gromacs.org.
import os.path
import re
+import functools
from gmxtree import DocType
+@functools.total_ordering
class EdgeType(object):
"""Enumeration type for edge types in include dependency graphs."""
"""Return string representation for the edge type (for debugging)."""
return self._names[self._value]
- def __cmp__(self, other):
+ def __eq__(self, other):
"""Order edge types in the order of increasing coupling."""
- return cmp(self._value, other._value)
+ return self._value == other._value
+
+ def __lt__(self, other):
+ """Order edge types in the order of increasing coupling."""
+ return self._value < other._value
# Tests depend on test
EdgeType.test = EdgeType(0)
are in the list of nodes.
"""
edges = []
- for fileobj in filenodes.iterkeys():
+ for fileobj in filenodes.keys():
for includedfile in fileobj.get_includes():
otherfile = includedfile.get_file()
if otherfile and otherfile in filenodes:
dependency are in the list of nodes.
"""
edges = []
- for moduleobj in modulenodes.iterkeys():
+ for moduleobj in modulenodes.keys():
for dep in moduleobj.get_dependencies():
othermodule = dep.get_other_module()
if othermodule and othermodule in modulenodes:
-#!/usr/bin/env python2
+#!/usr/bin/env python3
#
# This file is part of the GROMACS molecular simulation package.
#
-# Copyright (c) 2012,2013,2014,2015,2016,2017,2018, by the GROMACS development team, led by
+# Copyright (c) 2012,2013,2014,2015,2016,2017,2018,2019, by the GROMACS development team, led by
# Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
# and including many others, as listed in the AUTHORS file in the
# top-level source directory and at http://www.gromacs.org.
import os.path
import re
import sys
+import functools
+@functools.total_ordering
class IncludeGroup(object):
"""Enumeration type for grouping includes."""
"""
self._value = value
- def __cmp__(self, other):
+ def __eq__(self, other):
"""Order include groups in the desired order."""
- return cmp(self._value, other._value)
+ return self._value == other._value
+
+ def __lt__(self, other):
+ """Order include groups in the desired order."""
+ return self._value < other._value
# gmxpre.h is always first
IncludeGroup.pre = IncludeGroup(0)
Returns a new list of lines for the block.
If anything is changed, self._changed is set to True, and the caller
can check that."""
- includes = map(self._sortmethod.get_sortable_object, block.get_includes())
- includes.sort()
+ includes = sorted(map(self._sortmethod.get_sortable_object, block.get_includes()))
result = []
prev = None
current_line_number = block.get_first_line()-1
-#!/usr/bin/env python2
+#!/usr/bin/env python3
#
# This file is part of the GROMACS molecular simulation package.
#
-# Copyright (c) 2014,2018, by the GROMACS development team, led by
+# Copyright (c) 2014,2018,2019, by the GROMACS development team, led by
# Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
# and including many others, as listed in the AUTHORS file in the
# top-level source directory and at http://www.gromacs.org.
# the research papers on the package. Check out http://www.gromacs.org.
import sys
+import functools
from fnmatch import fnmatch
certain messages.
"""
+@functools.total_ordering
class Location(object):
"""Location for a reported message."""
self.filename = filename
self.line = line
- def __nonzero__(self):
+ def __bool__(self):
"""Make empty locations False in boolean context."""
return self.filename is not None
else:
return '<unknown>'
- def __cmp__(self, other):
+ def __eq__(self, other):
"""Sort locations based on file name and line number."""
- result = cmp(self.filename, other.filename)
- if not self.filename or result != 0:
- return result
- return cmp(self.line, other.line)
+ return self.filename == other.filename and self.line == other.line
+ def __lt__(self, other):
+ """Sort locations based on file name and line number."""
+ if self.filename != other.filename:
+ if other.filename is None:
+ return False
+ if self.filename is None:
+ return True
+ return self.filename < other.filename
+ else:
+ if not self.filename:
+ return False
+ if other.line is None:
+ return False
+ if self.line is None:
+ return True
+ return self.line < other.line
+
+@functools.total_ordering
class Message(object):
"""Single reported message.
self.message = message
self.details = details
- def __cmp__(self, other):
+ def __eq__(self, other):
+ """Sort messages based on file name and line number."""
+ return self.location == other.location
+
+ def __lt__(self, other):
"""Sort messages based on file name and line number."""
- return cmp(self.location, other.location)
+ return self.location < other.location
class Filter(object):
-#!/usr/bin/env python2
+#!/usr/bin/env python3
#
# This file is part of the GROMACS molecular simulation package.
#
-#!/usr/bin/env python2
+#!/usr/bin/env python3
#
# This file is part of the GROMACS molecular simulation package.
#
-# Copyright (c) 2012,2018, by the GROMACS development team, led by
+# Copyright (c) 2012,2018,2019, by the GROMACS development team, led by
# Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
# and including many others, as listed in the AUTHORS file in the
# top-level source directory and at http://www.gromacs.org.