• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

rjfarmer / gfModParser / 25401429739

05 May 2026 08:05PM UTC coverage: 96.206% (-0.3%) from 96.514%
25401429739

push

github

rjfarmer
Add assumed rank tests

6 of 10 new or added lines in 1 file covered. (60.0%)

1141 of 1186 relevant lines covered (96.21%)

0.96 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.62
/gfModParser/modules/arrays.py
1
# SPDX-License-Identifier: GPL-2.0+
2

3
from functools import cached_property
1✔
4

5
import numpy as np
1✔
6
from packaging.version import Version
1✔
7

8
from . import expressions
1✔
9

10

11
class arrayspec:
1✔
12
    def __init__(self, array, *, version: Version) -> None:
1✔
13
        self._array = array
1✔
14
        self.version = version
1✔
15

16
    def __bool__(self) -> bool:
1✔
17
        return self.is_array
1✔
18

19
    @property
1✔
20
    def is_array(self) -> bool:
1✔
21
        return len(self._array) > 0
1✔
22

23
    @property
1✔
24
    def ndims(self) -> int:
1✔
25
        if self.is_array:
1✔
26
            return self.rank
1✔
27
        return -1
1✔
28

29
    @property
1✔
30
    def rank(self) -> int:
1✔
31
        if self.is_array:
1✔
32
            return int(self._array[0])
1✔
33
        return -1
1✔
34

35
    @property
1✔
36
    def corank(self) -> int:
1✔
37
        if self.is_array:
1✔
38
            return int(self._array[1])
1✔
39
        return -1
1✔
40

41
    @property
1✔
42
    def type(self) -> str:
1✔
43
        if self.is_array:
1✔
44
            return self._array[2]
1✔
45
        return ""
1✔
46

47
    @property
1✔
48
    def is_deferred(self) -> bool:
1✔
49
        """
50
        Deferred arrays (like allocatable) do not have compile time bounds, but do have
51
        compile time rank
52
        """
53
        if self.is_array:
1✔
54
            return self.type == "DEFERRED" or self.type == "ASSUMED_SHAPE"
1✔
55
        return False
1✔
56

57
    @property
1✔
58
    def is_explicit(self) -> bool:
1✔
59
        if self.is_array:
1✔
60
            return self.type == "EXPLICIT"
×
61
        return False
1✔
62

63
    @property
1✔
64
    def is_assumed_size(self) -> bool:
1✔
NEW
65
        if self.is_array:
×
NEW
66
            return self.type == "ASSUMED_SIZE"
×
NEW
67
        return False
×
68

69
    @property
1✔
70
    def is_assumed_rank(self) -> bool:
1✔
71
        if self.is_array:
1✔
72
            return self.type == "ASSUMED_RANK"
1✔
NEW
73
        return False
×
74

75
    @cached_property
1✔
76
    def lower(self) -> tuple[expressions.Expression, ...]:
1✔
77
        low = []
1✔
78
        if self.is_array:
1✔
79
            for i in range(self.rank + self.corank):
1✔
80
                if len(self._array[3 + i * 2]):
1✔
81
                    low.append(
1✔
82
                        expressions.Expression(
83
                            self._array[3 + i * 2], version=self.version
84
                        )
85
                    )
86

87
            return tuple(low)
1✔
88
        return ()
1✔
89

90
    @cached_property
1✔
91
    def upper(self) -> tuple[expressions.Expression, ...]:
1✔
92
        up = []
1✔
93
        if self.is_array:
1✔
94
            for i in range(self.rank + self.corank):
1✔
95
                if len(self._array[4 + i * 2]):
1✔
96
                    up.append(
1✔
97
                        expressions.Expression(
98
                            self._array[4 + i * 2], version=self.version
99
                        )
100
                    )
101

102
            return tuple(up)
1✔
103
        return ()
1✔
104

105
    @property
1✔
106
    def fshape(self) -> tuple[tuple[int, int], ...]:
1✔
107
        """
108
        Returns the array shape as a tuple of Fortran bounds ((lower, upper),..)
109
        """
110
        if self.is_array:
1✔
111
            res = []
1✔
112
            for l, u in zip(self.lower, self.upper):
1✔
113
                res.append((l.value, u.value))
1✔
114

115
            return tuple(res)
1✔
116
        return ()
1✔
117

118
    @property
1✔
119
    def pyshape(self) -> tuple[int, ...]:
1✔
120
        """
121
        Returns the array shape as a tuple of Python bounds (ndim1,ndim2,..)
122
        """
123
        if self.is_array:
1✔
124
            res = []
1✔
125
            for l, u in zip(self.lower, self.upper):
1✔
126
                res.append(u.value - l.value + 1)
1✔
127

128
            return tuple(res)
1✔
129
        return ()
1✔
130

131
    @property
1✔
132
    def size(self) -> np.int64:
1✔
133
        if self.is_array:
1✔
134
            if not self.is_deferred:
1✔
135
                return np.prod(self.pyshape)
1✔
136

137
        return np.int64(-1)
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc