Skip to content

Commit

Permalink
Clean PythonCodePrinter and add dtype property (#1260)
Browse files Browse the repository at this point in the history
Remove the duplicate `_print_NumpyArray` function from
PythonCodePrinter. The original `_print_NumpyArray` function is more
accurate as it specifies the `dtype` etc explicitly. Specifying the `dtype`
explicitly makes issue #1377 reproducible. To fix this problem support is
added for `a.dtype` expressions (Fixes #1421) using the similar function
[`np.result_type`](https://numpy.org/doc/stable/reference/generated/numpy.result_type.html).

The initialisation dtype is saved and used in the Python printer. This
is a work-around until #1334 is resolved well enough to define a clear
issue. Additionally a warning is raised if the Python code is not
consistent. Fixes #1377.

**Additional commits**
- Simplify bot linux/windows/macosx output to reduce duplication. Change
regex for C now that the test is no longer verbose.
- Stop generating `numpy.bool` in code as it has been deprecated by
NumPy. Instead use the default bool (with precision `-1`).
- Add support for NumPy's short type names.
- Reduce duplication in the Python printer.
- Remove outdated skips on tests.
- Stop array error tests failing in developer mode.
  • Loading branch information
EmilyBourne committed Aug 15, 2023
1 parent 564974c commit 3964466
Show file tree
Hide file tree
Showing 14 changed files with 506 additions and 350 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ All notable changes to this project will be documented in this file.
- Add Python support for a simple class.
- #1430 : Add conjugate support to booleans.
- #1452 : Add C printing support for a class containing only functions.
- #1260 : Add support for NumPy `dtype` property: `a.dtype`.
- #1260 : Add support for NumPy `result_type` function.

### Fixed

Expand All @@ -31,6 +33,7 @@ All notable changes to this project will be documented in this file.

### Deprecated

- Stop generating `numpy.bool` (deprecated from NumPy) in code.
- \[INTERNALS\] Removed `obsolete` folder.
- \[INTERNALS\] Removed out of date `samples` folder.
- \[INTERNALS\] Removed out of date `doc` folder.
Expand Down
59 changes: 20 additions & 39 deletions ci_tools/json_pytest_output.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import re
import sys

def mini_md_summary(title, outcome, c, f, py):
def mini_md_summary(title, outcome, failed_tests):
"""
Generate Markdown.
Expand All @@ -30,12 +30,8 @@ def mini_md_summary(title, outcome, c, f, py):
The title of the summary.
outcome : str
The result of a completed step, Possible values are success, failure, cancelled, or skipped.
c : list
A list of C test summaries, (Failed tests).
f : list
A list of Fortran test summaries, (Failed tests).
py : list
A list of Python test summaries, (Failed tests).
failed_tests : dict
A dictionary whose keys are languages and whose values are lists of failed test summaries.
Returns
-------
Expand All @@ -44,21 +40,12 @@ def mini_md_summary(title, outcome, c, f, py):
"""
md = f"## {title} - {outcome} "
if outcome == "failure":
if len(c) != 0:
md = md + '\n' + "### C Test summary: "
md = md + '\n'
for i in c:
md = md + i + "\n"
if len(f) != 0:
md = md + '\n' + "### Fortran Test summary: "
md = md + '\n'
for i in f:
md = md + i + "\n"
if len(py) != 0:
md = md + '\n' + "### Python Test summary: "
md = md + '\n'
for i in py:
md = md + i + "\n"
for lang, errs in failed_tests.items():
if len(errs) != 0:
md = md + '\n' + f"### {lang.capitalize()} Test summary: "
md = md + '\n'
for i in errs:
md = md + i + "\n"
md = md + "\n"
return(md)

Expand All @@ -73,6 +60,10 @@ def mini_md_summary(title, outcome, c, f, py):
output_file = 'test_json_result.json'
summary = ""

failed_pattern = re.compile(r".*FAILED.*")
languages = ('c', 'fortran', 'python')
pattern = {lang: re.compile(r".*\["+lang+r"\]\ \_.*") for lang in languages}

for i in p_args.tests:
values = i.split(':')
mini_title = values[0] if len(values) >= 1 else None
Expand All @@ -86,28 +77,18 @@ def mini_md_summary(title, outcome, c, f, py):
c_tests = []
f_tests = []
py_tests = []
failed_pattern = r".*FAILED.*"
c_pattern = r".*\[c\].*"
f_pattern = r".*\[fortran\]\ \_.*"
py_pattern = r".*\[python\]\ \_.*"

failed_matches = re.findall(failed_pattern, outfile, re.MULTILINE)
failed_matches = failed_pattern.findall(outfile, re.MULTILINE)
failed_matches = [re.sub(r'.*FAILED ', "- ``", string) for string in failed_matches]

r = re.compile(c_pattern)
c_failed = list(filter(r.match, failed_matches))
c_failed = [re.sub(r'\[c\]', "`` :heavy_multiplication_x:", string) for string in c_failed]

failed_matches = re.findall(f_pattern, outfile, re.MULTILINE)
failed_matches = ["- ``" + string.strip('_') for string in failed_matches]
f_failed = [re.sub(r'\[fortran\]', "`` :heavy_multiplication_x:", string) for string in failed_matches]

failed_matches = re.findall(py_pattern, outfile, re.MULTILINE)
failed_matches = ["- ``" + string.strip('_') for string in failed_matches]
py_failed = [re.sub(r'\[python\]', "`` :heavy_multiplication_x:", string) for string in failed_matches]
fails = {}

for lang in languages:
failed_matches = pattern[lang].findall(outfile, re.MULTILINE)
failed_matches = ["- ``" + string.strip('_') for string in failed_matches]
fails[lang] = [re.sub(r'\['+lang+r'\]', "`` :heavy_multiplication_x:", string) for string in failed_matches]

summary = summary + mini_md_summary(mini_title, outcome, c_failed, f_failed, py_failed)
summary = summary + mini_md_summary(mini_title, outcome, fails)

print(summary)
json_ouput = {
Expand Down
2 changes: 1 addition & 1 deletion docs/numpy-functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -570,6 +570,6 @@ In Pyccel we try to support the NumPy functions which developers use the most..

- others:

- `amax`, `amin`, `sum`, `shape`, `size`, `floor`, `sign`
- `amax`, `amin`, `sum`, `shape`, `size`, `floor`, `sign`, `result_type`

If discrepancies beyond round-off error are found between [NumPy](https://numpy.org/doc/stable/reference/)'s and [Pyccel](https://github.com/pyccel/pyccel)'s results, please create an issue at <https://github.com/pyccel/pyccel/issues> and provide a small example of your problem. Do not forget to specify your target language.
6 changes: 4 additions & 2 deletions pyccel/ast/class_defs.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
NativeComplex, NativeString, NativeNumeric)
from .numpyext import (NumpyShape, NumpySum, NumpyAmin, NumpyAmax,
NumpyImag, NumpyReal, NumpyTranspose,
NumpyConjugate, NumpySize)
NumpyConjugate, NumpySize, NumpyResultType)

__all__ = ('BooleanClass',
'IntegerClass',
Expand Down Expand Up @@ -158,7 +158,9 @@
PyccelFunctionDef('conj', func_class = NumpyConjugate,
decorators = {'numpy_wrapper': 'numpy_wrapper'}),
PyccelFunctionDef('conjugate', func_class = NumpyConjugate,
decorators = {'numpy_wrapper': 'numpy_wrapper'})
decorators = {'numpy_wrapper': 'numpy_wrapper'}),
PyccelFunctionDef('dtype', func_class = NumpyResultType,
decorators = {'property': 'property', 'numpy_wrapper': 'numpy_wrapper'}),
]
)

Expand Down
6 changes: 2 additions & 4 deletions pyccel/ast/cwrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ def arg_names(self):
(NativeFloat(), 4) : 'f',
(NativeComplex(), 4) : 'O',
(NativeComplex(), 8) : 'O',
(NativeBool(), 4) : 'p',
(NativeBool(), -1) : 'p',
(NativeString(), 0) : 's',
(PyccelPyObject(), 0) : 'O',
}
Expand Down Expand Up @@ -366,7 +366,7 @@ def Python_to_C(c_object):

# Functions definitions are defined in pyccel/stdlib/cwrapper/cwrapper.c
py_to_c_registry = {
(NativeBool(), 4) : 'PyBool_to_Bool',
(NativeBool(), -1) : 'PyBool_to_Bool',
(NativeInteger(), 1) : 'PyInt8_to_Int8',
(NativeInteger(), 2) : 'PyInt16_to_Int16',
(NativeInteger(), 4) : 'PyInt32_to_Int32',
Expand Down Expand Up @@ -412,7 +412,6 @@ def C_to_Python(c_object):
# Functions definitions are defined in pyccel/stdlib/cwrapper/cwrapper.c
c_to_py_registry = {
(NativeBool(), -1) : 'Bool_to_PyBool',
(NativeBool(), 4) : 'Bool_to_PyBool',
(NativeInteger(), -1) : 'Int'+str(default_precision['int']*8)+'_to_PyLong',
(NativeInteger(), 1) : 'Int8_to_NumpyLong',
(NativeInteger(), 2) : 'Int16_to_NumpyLong',
Expand Down Expand Up @@ -510,7 +509,6 @@ def generate_datatype_error(variable):
# Functions definitions are defined in pyccel/stdlib/cwrapper/cwrapper.c
check_type_registry = {
(NativeBool(), -1) : 'PyIs_Bool',
(NativeBool(), 4) : 'PyIs_Bool',
(NativeInteger(), -1) : 'PyIs_NativeInt',
(NativeInteger(), 1) : 'PyIs_Int8',
(NativeInteger(), 2) : 'PyIs_Int16',
Expand Down
15 changes: 12 additions & 3 deletions pyccel/ast/datatypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@
8 : 'C_DOUBLE_COMPLEX',
16 : 'C_LONG_DOUBLE_COMPLEX'},
"logical" : {
4 : "C_BOOL"}
-1 : "C_BOOL"}
}
iso_c_binding_shortcut_mapping = {
'C_INT8_T' : 'i8',
Expand All @@ -91,31 +91,40 @@
'C_FLOAT_COMPLEX' : 'c32',
'C_DOUBLE_COMPLEX' : 'c64',
'C_LONG_DOUBLE_COMPLEX' : 'c128',
'C_BOOL' : 'b4'
'C_BOOL' : 'b1'
}
default_precision = {'float': 8,
'int': numpy.dtype(int).alignment,
'integer': numpy.dtype(int).alignment,
'complex': 8,
'bool':4}
'bool':-1}
dtype_and_precision_registry = { 'float':('float', -1),
'double':('float', -1),
'real':('float', -1),
'pythonfloat':('float', -1), # built-in float
'float32':('float',4),
'float64':('float',8),
'f4':('float',4),
'f8':('float',8),
'pythoncomplex':('complex', -1),
'complex':('complex', -1), # to create numpy array with dtype='complex'
'complex64':('complex',4),
'complex128':('complex',8),
'c8':('complex',4),
'c16':('complex',8),
'int8' :('int',1),
'int16':('int',2),
'int32':('int',4),
'int64':('int',8),
'i1' :('int',1),
'i2':('int',2),
'i4':('int',4),
'i8':('int',8),
'int' :('int', -1),
'pythonint' :('int', -1),
'integer':('int',-1),
'bool' :('bool',-1),
'b1' :('bool',-1),
'pythonbool' :('bool',-1)}


Expand Down
2 changes: 1 addition & 1 deletion pyccel/ast/numpy_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ def get_numpy_max_acceptable_version_file():
4 : np.dtype(np.int32).num,
8 : np.dtype(np.int64).num}

numpy_dtype_registry = {('bool',4) : numpy_bool_type,
numpy_dtype_registry = {('bool',-1) : numpy_bool_type,
('int',1) : numpy_num_to_type[numpy_int_type_precision_map[1]],
('int',2) : numpy_num_to_type[numpy_int_type_precision_map[2]],
('int',4) : numpy_num_to_type[numpy_int_type_precision_map[4]],
Expand Down
Loading

0 comments on commit 3964466

Please sign in to comment.