Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • icon/ci-tooling/icon-openacc-beautifier
1 result
Show changes
Commits on Source (6)
*.egg-info
# ICON OpenACC code beautifier
#
# ---------------------------------------------------------------
# Copyright (C) 2004-2024, DWD, MPI-M, DKRZ, KIT, ETH, MeteoSwiss
# Copyright (C) 2004-2025, DWD, MPI-M, DKRZ, KIT, ETH, MeteoSwiss
# Contact information: icon-model.org
#
# See AUTHORS.md for a list of authors
......@@ -9,11 +9,7 @@
# SPDX-License-Identifier: BSD-3-Clause
# ---------------------------------------------------------------
Unittest:
stage: test
script:
- python3 test.py
.general:
tags:
# choose python capable runner
- sphinx
......@@ -24,3 +20,23 @@ Unittest:
- if: $CI_PIPELINE_SOURCE == "schedule"
- if: $CI_PIPELINE_SOURCE == "push"
when: never
Unittest:
extends:
- .general
stage: test
script:
- pip install .
- python3 test.py
Package:
extends:
- .general
stage: test
script:
- pip install .
- echo -e '!$ACC DIRECTIVE, IF(B), ASYNC(1),&\n!$ACC DEFAULT(PRESENT)' > test.f90
- echo -e '!$ACC DIRECTIVE IF(B) ASYNC(1) &\n!$ACC DEFAULT(PRESENT)' > target.f90
- icon-openacc-beautifier test.f90
- diff test.f90 target.f90
- id: icon-openacc-beautifier
name: icon-openacc-beautifier
description: "Applies rules from the ICON OpenACC style guide"
entry: icon-openacc-beautifier
language: python
types: [fortran]
......@@ -5,6 +5,4 @@ List of authors of the ICON OpenACC code beautifier main code:
Marek Jacob
Wilton Jaciel Loch
Roland Wirth
Special components:
(./balanced_paren.py): Gene Olson
Sergey Kosukhin
......@@ -12,10 +12,17 @@ Tested with Python 3.6.12.
Warning: This main.py modifies given files in place!
```
Syntax: `main.py file1 file2 directory1/ directory2/`
Syntax: `icon-openacc-beautifier file1 file2 directory1/ directory2/`
Merge requests and comments welcome!
# How to install
```
pip install .
```
# Dependencies
Python >= 3.9
# Partnership
......
"""
Here is a simple python program showing how to use regular
expressions to write a paren-matching recursive parser.
This parser recognizes items enclosed by parens, brackets,
braces and <> symbols, but is adaptable to any set of
open/close patterns. This is where the re package greatly
assists in parsing.
Source:
Author: Gene Olson
SPDX-License-Identifier: CC-BY-SA-3.0
See LICENSES/ for license information
https://stackoverflow.com/a/39263467
"""
import re
# The pattern below recognises a sequence consisting of:
# 1. Any characters not in the set of open/close strings.
# 2. One of the open/close strings.
# 3. The remainder of the string.
#
# There is no reason the opening pattern can't be the
# same as the closing pattern, so quoted strings can
# be included. However quotes are not ignored inside
# quotes. More logic is needed for that....
pat = re.compile(r"""
( .*? )
( \( | \) | \[ | \] | \{ | \} | \< | \> |
\' | \" | BEGIN | END | $ )
( .* )
""", re.X)
# The keys to the dictionary below are the opening strings,
# and the values are the corresponding closing strings.
# For example "(" is an opening string and ")" is its
# closing string.
matching = { "(" : ")",
"[" : "]",
"{" : "}",
"<" : ">",
'"' : '"',
"'" : "'",
"BEGIN" : "END" }
# The procedure below matches string s and returns a
# recursive list matching the nesting of the open/close
# patterns in s.
def matchnested(s, term=""):
lst = []
while True:
m = pat.match(s)
if m.group(1) != "":
lst.append(m.group(1))
if m.group(2) == term:
return lst, m.group(3)
if m.group(2) in matching:
item, s = matchnested(m.group(3), matching[m.group(2)])
lst.append(m.group(2))
lst.append(item)
lst.append(matching[m.group(2)])
else:
raise ValueError("After <<%s %s>> expected %s not %s" %
(lst, s, term, m.group(2)))
# Unit test.
if __name__ == "__main__":
for s in ("simple string",
""" "double quote" """,
""" 'single quote' """,
"one'two'three'four'five'six'seven",
"one(two(three(four)five)six)seven",
"one(two(three)four)five(six(seven)eight)nine",
"one(two)three[four]five{six}seven<eight>nine",
"one(two[three{four<five>six}seven]eight)nine",
"oneBEGINtwo(threeBEGINfourENDfive)sixENDseven",
"ERROR testing ((( mismatched ))] parens"):
print "\ninput", s
try:
lst, s = matchnested(s)
print "output", lst
except ValueError as e:
print str(e)
print "done"
\ No newline at end of file
#!/bin/bash
# ICON OpenACC code beautifier
#
# ---------------------------------------------------------------
# Copyright (C) 2004-2024, DWD, MPI-M, DKRZ, KIT, ETH, MeteoSwiss
# Contact information: icon-model.org
#
# See AUTHORS.md for a list of authors
# See LICENSES/ for license information
# SPDX-License-Identifier: BSD-3-Clause
# ---------------------------------------------------------------
# A pre-commit hook script to apply the icon-openacc-beautifier to all staged files
#
# Instructions
# ------------
# Link or move to .git/hooks/pre-commit to enable.
# E.g. from the icon directory:
# ln -s ../icon-openacc-beautifier/pre-commit .git/hooks/pre-commit
if [ -x "../icon-openacc-beautifier/main.py" ]; then
readarray -t STAGED_FILES <<< "$(git diff --cached --name-only --diff-filter=ACMR -- '*.?90')"
if [ -n "${STAGED_FILES[0]}" ]; then
UNSTAGED_CHANGES="$(git diff)"
if [ -n "${UNSTAGED_CHANGES}" ]; then
git stash push --staged
git stash push
git stash apply 1
../icon-openacc-beautifier/main.py "${STAGED_FILES[@]}"
git add "${STAGED_FILES[@]}"
git stash pop
git stash drop 0
else
../icon-openacc-beautifier/main.py "${STAGED_FILES[@]}"
git add "${STAGED_FILES[@]}"
fi
fi
else
echo "============================= WARNING ============================="
echo "Error in pre-commit linter hook: Icon OpenACC beautifier not found!"
echo "Please place the linter in the same folder as icon."
echo "==================================================================="
exit 0
fi
# ---------------------------------------------------------------
# Copyright (C) 2004-2025, DWD, MPI-M, DKRZ, KIT, ETH, MeteoSwiss
# Contact information: icon-model.org
# See AUTHORS.TXT for a list of authors
# See LICENSES/ for license information
# SPDX-License-Identifier: BSD-3-Clause
# ---------------------------------------------------------------
[build-system]
requires = [ "setuptools>=61"]
[project]
name = "icon_openacc_beautifier"
version = "1.1.0"
description = "Apply the ICON OpenACC coding style guides automatically"
keywords = [ "linter", "OpenACC", "tools" ]
license = { file = "LICENSES/BSD-3-Clause.txt" }
#authors = [
# { name = "", email = "" },
#]
requires-python = ">=3.9"
classifiers = [
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
"License :: OSI Approved :: BSD License",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy",
]
optional-dependencies.all = [ ]
scripts.icon-openacc-beautifier = "icon_openacc_beautifier:main"
......@@ -3,7 +3,7 @@
# ICON OpenACC code beautifier
#
# ---------------------------------------------------------------
# Copyright (C) 2004-2024, DWD, MPI-M, DKRZ, KIT, ETH, MeteoSwiss
# Copyright (C) 2004-2025, DWD, MPI-M, DKRZ, KIT, ETH, MeteoSwiss
# Contact information: icon-model.org
#
# See AUTHORS.md for a list of authors
......@@ -499,8 +499,7 @@ def apply_ICON_acc_style(in_file, out_file):
return lines_changed
if __name__ == "__main__":
def main():
stream_handler = logging.StreamHandler(stream=sys.stdout)
log.handlers = [stream_handler]
......@@ -508,19 +507,20 @@ if __name__ == "__main__":
print("Missing argument.")
print("Warning: This program modifies given files in place!")
print(f"Syntax: {sys.argv[0]} file1 file2 directory1/ directory2/")
print("")
print("Debug messages: set environmental variable LOGLEVEL to 'DEBUG'")
sys.exit(1)
else:
files_or_dirs = sys.argv[1:]
if len(files_or_dirs) == 1 and os.path.isfile(files_or_dirs[0]):
log.setLevel(logging.DEBUG)
else:
log.setLevel(logging.INFO)
print("Warning: This program modifies given files in place!")
LOGLEVEL = os.environ.get('LOGLEVEL', 'INFO').upper()
log.setLevel(LOGLEVEL)
for f in files_or_dirs:
if os.path.isdir(f):
walk(f)
else:
apply_ICON_acc_style(f, f)
if __name__ == "__main__":
main()
# ICON OpenACC code beautifier
#
# ---------------------------------------------------------------
# Copyright (C) 2004-2024, DWD, MPI-M, DKRZ, KIT, ETH, MeteoSwiss
# Copyright (C) 2004-2025, DWD, MPI-M, DKRZ, KIT, ETH, MeteoSwiss
# Contact information: icon-model.org
#
# See AUTHORS.md for a list of authors
......@@ -13,14 +13,14 @@ import unittest
import unittest.mock as mock
from io import StringIO
import main
import icon_openacc_beautifier
class Test(unittest.TestCase):
def apply_ICON_acc_style(self, input, output):
m = mock.mock_open(read_data=input)
with mock.patch("main.open", m, create=True):
main.apply_ICON_acc_style("mock_fileA", "mock_fileB")
with mock.patch("icon_openacc_beautifier.open", m, create=True):
icon_openacc_beautifier.apply_ICON_acc_style("mock_fileA", "mock_fileB")
# convert generator, that was passed to writelines(), to string
written_output = "".join(m().writelines.call_args.args[0])
self.assertEqual(written_output, output)
......@@ -170,8 +170,8 @@ class Test(unittest.TestCase):
CALL something()
"""
m = mock.mock_open(read_data=input)
with mock.patch("main.open", m, create=True):
main.apply_ICON_acc_style("mock_file", "mock_file")
with mock.patch("icon_openacc_beautifier.open", m, create=True):
icon_openacc_beautifier.apply_ICON_acc_style("mock_file", "mock_file")
# test that there was no second call with "w"rite mode
m.assert_called_once_with("mock_file")
......@@ -184,8 +184,8 @@ class Test(unittest.TestCase):
CALL something()
"""
m = mock.mock_open(read_data=input)
with mock.patch("main.open", m, create=True):
main.apply_ICON_acc_style("mock_fileA", "mock_fileB")
with mock.patch("icon_openacc_beautifier.open", m, create=True):
icon_openacc_beautifier.apply_ICON_acc_style("mock_fileA", "mock_fileB")
m.assert_any_call("mock_fileA")
m.assert_called_with("mock_fileB", "w") # test last call
......@@ -196,8 +196,8 @@ class Test(unittest.TestCase):
!$acc DEFAULT(present)
""" # this input is not beautiful -> beautifier has to work.
m = mock.mock_open(read_data=input)
with mock.patch("main.open", m, create=True):
main.apply_ICON_acc_style("mock_file", "mock_file")
with mock.patch("icon_openacc_beautifier.open", m, create=True):
icon_openacc_beautifier.apply_ICON_acc_style("mock_file", "mock_file")
m.assert_any_call("mock_file")
m.assert_called_with("mock_file", "w") # test last call
......