Skip to content

Commit

Permalink
Preparation for package publication
Browse files Browse the repository at this point in the history
  • Loading branch information
SebastienRietteMTO committed Oct 16, 2024
1 parent a0c4e45 commit 92ab74b
Show file tree
Hide file tree
Showing 6 changed files with 209 additions and 152 deletions.
2 changes: 2 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[flake8]
max-line-length = 100
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,7 @@
# Fxtran building
bin/fxtran
site/fxtran

# Package building
src/pyft.egg-info/
dist/
109 changes: 4 additions & 105 deletions bin/pyft_parallel_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,111 +4,10 @@
Main tool to apply in parallel source-to-source transformations using pyft
"""

# This script only contains a call to the mainParallel function
# It must remain unchanged to be equivalent to the entry point defined in pyproject.toml

import logging
import argparse
from multiprocessing.managers import BaseManager
from multiprocessing import Pool
import sys
import traceback

from pyft import PYFT # pylint: disable=import-error
from pyft.tree import Tree # pylint: disable=import-error
from pyft.util import PYFTError # pylint: disable=import-error
# pylint: disable-next=import-error
from pyft.scripting import updateParser, getParserOptions, \
getDescTree, applyTransfo, getArgs


class MyManager(BaseManager):
"""
Custom manager to deal with Tree instances
"""


MyManager.register('Tree', Tree)


def init(cls):
"""
Pool initializer
"""
# After many, many attempts, it seems very difficult (if not impossible)
# to do without this global variable
global PYFT # pylint: disable=global-statement
PYFT = cls

from pyft.scripting import mainParallel # pylint: disable=import-error

if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Python FORTRAN tool', allow_abbrev=False,
epilog="The argument order matters.")

updateParser(parser, withInput=False, withOutput=False, withXml=False, withPlotCentralFile=True,
treeIsOptional=False, nbPar=True, restrictScope=False)
commonArgs, getFileArgs = getArgs(parser)

# Manager to share the Tree instance
with MyManager() as manager:
# Set-up the Tree instance
sharedTree = getDescTree(commonArgs, manager.Tree)

# Prepare PYFT to be used in parallel
PYFT.setParallel(sharedTree)

allFileArgs = {file: getFileArgs(file) for file in sharedTree.getFiles()}

# Defined here to use the allFileArgs
def task(filename):
"""
Function to use on each file
:param clsPYFT: PYFT class to use
:param filename: file name
"""
allArgs, orderedOptions = allFileArgs[filename]
try:
# Opening and reading of the FORTRAN file
pft = PYFT(filename, filename, parser=allArgs.parser,
parserOptions=getParserOptions(allArgs), verbosity=allArgs.logLevel,
wrapH=allArgs.wrapH,
enableCache=allArgs.enableCache)

# apply the transformation in the order they were specified
for arg in orderedOptions:
logging.debug('Applying %s on %s', arg, filename)
applyTransfo(pft, arg, allArgs,
filename if filename == allArgs.plotCentralFile else None)
logging.debug(' -> Done')

# Writing
if not allArgs.dryRun:
pft.write()

# Closing and reporting
pft.close()
return (0, filename)

except Exception as exc: # pylint: disable=broad-except
logging.error("The following error has occurred in the file %s", filename)
PYFT.unlockFile(filename, silence=True)
traceback.print_exception(exc, file=sys.stdout)
sys.stdout.flush()
return (1, filename)

# Set-up the processes
# allFileArgs = {file: getFileArgs(file) for file in sharedTree.getFiles()}
logging.info('Executing in parallel on %i files with a maximum of %i processes',
len(allFileArgs), commonArgs.nbPar)
with Pool(commonArgs.nbPar, initializer=init, initargs=(PYFT, )) as pool:
result = pool.map(task, sharedTree.getFiles())

# Writting the descTree object
sharedTree.toJson(commonArgs.descTree)

# General error
errors = [item[1] for item in result if item[0] != 0]
status = len(errors)
if status != 0:
logging.error('List of files with error:')
for error in errors:
logging.error(' - %s', error)
raise PYFTError(f"Errors have been reported in {status} file(s).")
mainParallel()
49 changes: 4 additions & 45 deletions bin/pyft_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,51 +4,10 @@
Main tool to apply source-to-source transformations using pyft
"""

import logging
import argparse
# This script only contains a call to the main function
# It must remain unchanged to be equivalent to the entry point defined in pyproject.toml

from pyft import PYFT # pylint: disable=import-error
# pylint: disable-next=import-error
from pyft.scripting import updateParser, getParserOptions, \
getDescTree, applyTransfo, getArgs
from pyft.scripting import main # pylint: disable=import-error

if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Python FORTRAN tool', allow_abbrev=False,
epilog="The argument order matters.")

updateParser(parser, withInput=True, withOutput=True, withXml=True, withPlotCentralFile=False,
treeIsOptional=True, nbPar=False, restrictScope=True)
args, orderedOptions = getArgs(parser)[1]()

parserOptions = getParserOptions(args)
descTree = getDescTree(args)

try:
# Opening and reading of the FORTRAN file
pft = PYFT(args.INPUT, args.OUTPUT, parser=args.parser, parserOptions=parserOptions,
verbosity=args.logLevel, wrapH=args.wrapH, tree=descTree,
enableCache=args.enableCache)
if args.restrictScope != '':
pft = pft.getScopeNode(args.restrictScope)

# apply the transformation in the order they were specified
for arg in orderedOptions:
logging.debug('Applying %s on %s', arg, args.INPUT)
applyTransfo(pft, arg, args, plotCentralFile=args.INPUT)
logging.debug(' -> Done')

# Writing
if descTree is not None:
descTree.toJson(args.descTree)
if args.xml is not None:
pft.mainScope.writeXML(args.xml)
if not args.dryRun:
pft.mainScope.write()

# Closing
pft.mainScope.close()

except: # noqa E722
# 'exept' everything and re-raise error systematically
logging.error("The following error has occurred in the file %s", args.INPUT)
raise
main()
50 changes: 50 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"

[project]
name = "pyft"
authors = [
{name = "Quentin Rodier", email = "[email protected]"},
{name = "Sébastien Riette", email = "[email protected]"},
]
description = "Python-fortran-tool"
readme = "README.md"
requires-python = ">=3.8"
keywords = ["fortran", "static-analysis"]
license = {text = "LICENSE"}
classifiers = [
"Programming Language :: Python :: 3",
"License :: CeCILL-C Free Software License Agreement (CECILL-C)",
"Operating System :: POSIX :: Linux",
]
dependencies = [
#"fxtran",
]
dynamic = ["version"]

[project.urls]
Repository = "https://github.com/UMR-CNRM/pyft"
Documentation = "https://umr-cnrm.github.io/pyft"
Issues = "https://github.com/UMR-CNRM/pyft/issues"

[project.scripts]
'pyft_tool.py' = "pyft.scripting:main"
'pyft_parallel_tool.py' = "pyft.scripting:mainParallel"

[tool.setuptools.dynamic]
version = {attr = "pyft.__version__"}

[tool.pylint.BASIC]
function-rgx='_?_?[a-z][A-Za-z0-9]{1,30}$'
method-rgx='_?_?[a-z][A-Za-z0-9]{1,30}_?_?$'
attr-rgx='_?_?[a-z][A-Za-z0-9]{1,30}$'
argument-rgx='_?[a-z][A-Za-z0-9]{1,30}$'
variable-rgx='_?[a-z][A-Za-z0-9]{1,30}$'
inlinevar-rgx='_?[a-z][A-Za-z0-9]{0,30}$'

[tool.pylint.'MESSAGES CONTROL']
disable='no-member'

# flake8 doesn't yet support the pyproject.toml file
# The flake8 configuration is deported to the .flake8 file.
147 changes: 145 additions & 2 deletions src/pyft/scripting.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,159 @@
"""

import sys
from multiprocessing import cpu_count
from multiprocessing import cpu_count, Pool
from multiprocessing.managers import BaseManager
import re
import shlex
import os
import argparse
import logging
import traceback

from pyft.pyft import PYFT
from pyft.tree import Tree
from pyft.util import isint
from pyft.util import isint, PYFTError
from pyft import __version__

def task(filename):
"""
Function to use on each file
:param clsPYFT: PYFT class to use
:param filename: file name
"""
global PYFT
global allFileArgs
allArgs, orderedOptions = allFileArgs[filename]
try:
# Opening and reading of the FORTRAN file
pft = PYFT(filename, filename, parser=allArgs.parser,
parserOptions=getParserOptions(allArgs), verbosity=allArgs.logLevel,
wrapH=allArgs.wrapH,
enableCache=allArgs.enableCache)

# apply the transformation in the order they were specified
for arg in orderedOptions:
logging.debug('Applying %s on %s', arg, filename)
applyTransfo(pft, arg, allArgs,
filename if filename == allArgs.plotCentralFile else None)
logging.debug(' -> Done')

# Writing
if not allArgs.dryRun:
pft.write()

# Closing and reporting
pft.close()
return (0, filename)

except Exception as exc: # pylint: disable=broad-except
logging.error("The following error has occurred in the file %s", filename)
PYFT.unlockFile(filename, silence=True)
traceback.print_exception(exc, file=sys.stdout)
sys.stdout.flush()
return (1, filename)

def mainParallel():
"""
Core of the pyft_parallel_tool.py command
"""

class MyManager(BaseManager):
"""
Custom manager to deal with Tree instances
"""

MyManager.register('Tree', Tree)

def init(cls, afa):
"""
Pool initializer
"""
# After many, many attempts, it seems very difficult (if not impossible)
# to do without global variables
global PYFT # pylint: disable=global-statement
global allFileArgs # pylint: disable=global-statement
PYFT = cls
allFileArgs = afa

parser = argparse.ArgumentParser(description='Python FORTRAN tool', allow_abbrev=False,
epilog="The argument order matters.")

updateParser(parser, withInput=False, withOutput=False, withXml=False, withPlotCentralFile=True,
treeIsOptional=False, nbPar=True, restrictScope=False)
commonArgs, getFileArgs = getArgs(parser)

# Manager to share the Tree instance
with MyManager() as manager:
# Set-up the Tree instance
sharedTree = getDescTree(commonArgs, manager.Tree)

# Prepare PYFT to be used in parallel
PYFT.setParallel(sharedTree)

# Set-up the processes
allFileArgs = {file: getFileArgs(file) for file in sharedTree.getFiles()}
logging.info('Executing in parallel on %i files with a maximum of %i processes',
len(allFileArgs), commonArgs.nbPar)
with Pool(commonArgs.nbPar, initializer=init, initargs=(PYFT, allFileArgs)) as pool:
result = pool.map(task, sharedTree.getFiles())

# Writting the descTree object
sharedTree.toJson(commonArgs.descTree)

# General error
errors = [item[1] for item in result if item[0] != 0]
status = len(errors)
if status != 0:
logging.error('List of files with error:')
for error in errors:
logging.error(' - %s', error)
raise PYFTError(f"Errors have been reported in {status} file(s).")

def main():
"""
Core of the pyft_tool.py command
"""
parser = argparse.ArgumentParser(description='Python FORTRAN tool', allow_abbrev=False,
epilog="The argument order matters.")

updateParser(parser, withInput=True, withOutput=True, withXml=True, withPlotCentralFile=False,
treeIsOptional=True, nbPar=False, restrictScope=True)
args, orderedOptions = getArgs(parser)[1]()

parserOptions = getParserOptions(args)
descTree = getDescTree(args)

try:
# Opening and reading of the FORTRAN file
pft = PYFT(args.INPUT, args.OUTPUT, parser=args.parser, parserOptions=parserOptions,
verbosity=args.logLevel, wrapH=args.wrapH, tree=descTree,
enableCache=args.enableCache)
if args.restrictScope != '':
pft = pft.getScopeNode(args.restrictScope)

# apply the transformation in the order they were specified
for arg in orderedOptions:
logging.debug('Applying %s on %s', arg, args.INPUT)
applyTransfo(pft, arg, args, plotCentralFile=args.INPUT)
logging.debug(' -> Done')

# Writing
if descTree is not None:
descTree.toJson(args.descTree)
if args.xml is not None:
pft.mainScope.writeXML(args.xml)
if not args.dryRun:
pft.mainScope.write()

# Closing
pft.mainScope.close()

except: # noqa E722
# 'exept' everything and re-raise error systematically
logging.error("The following error has occurred in the file %s", args.INPUT)
raise

ARG_UPDATE_CNT = ('--alignContinuation', '--addBeginContinuation',
'--removeBeginContinuation',
'--emoveALLContinuation')
Expand Down

0 comments on commit 92ab74b

Please sign in to comment.