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

rjfarmer / gfModParser / 18325561673

07 Oct 2025 08:37PM UTC coverage: 88.694% (-1.2%) from 89.901%
18325561673

push

github

rjfarmer
Typing

84 of 99 new or added lines in 13 files covered. (84.85%)

2 existing lines in 1 file now uncovered.

1012 of 1141 relevant lines covered (88.69%)

0.89 hits per line

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

98.26
/gfModParser/__init__.py
1
# SPDX-License-Identifier: GPL-2.0+
2

3
import pathlib
1✔
4
from functools import cache
1✔
5

6
from . import io
1✔
7
from .modules import mod
1✔
8
from .modules.symbols import Symbol
1✔
9

10
__all__ = ["Module", "Variables", "Parameters", "Procedures", "DerivedTypes"]
1✔
11

12

13
class Module:
1✔
14
    def __init__(self, filename):
1✔
15
        self.filename = pathlib.Path(filename)
1✔
16

17
        if self.filename.suffixes == [".mod", ".txt"]:
1✔
18
            self.header = io.read_uncompressed_header(self.filename)
1✔
19
        else:
20
            self.header = io.read_compressed_header(self.filename)
1✔
21

22
        self._version = None
1✔
23
        self._checks()
1✔
24

25
    def _checks(self):
1✔
26
        if self.version < 15 or self.version > 16:
1✔
27
            raise ValueError(f"Unsupported module version {self.version}")
1✔
28

29
        if not "GFORTRAN" in self.header:
1✔
30
            raise ValueError("Only supports Gfortran modules")
1✔
31

32
        self._mod = mod.module(self.filename, version=self.version)
1✔
33

34
    @property
1✔
35
    def version(self):
1✔
36
        if self._version is None:
1✔
37
            self._version = int(self.header.split("'")[1])
1✔
38
        return self._version
1✔
39

40
    @property
1✔
41
    def interface(self):
1✔
42
        return self._mod.interface
1✔
43

44
    @property
1✔
45
    def operator(self):
1✔
46
        return self._mod.operator
1✔
47

48
    @property
1✔
49
    def generic(self):
1✔
50
        return self._mod.generic
1✔
51

52
    def keys(self):
1✔
53
        return self._mod.keys()
1✔
54

55
    def __contains__(self, key):
1✔
56
        return key in self._mod
1✔
57

58
    def __getitem__(self, key):
1✔
59
        return self._mod[key]
1✔
60

61
    def __dir__(self):
1✔
62
        return self._mod.__dir__()
1✔
63

64
    def __str__(self):
1✔
65
        return f"Module: {self.filename} Gfortran: {self.version}"
1✔
66

67
    def __repr__(self):
1✔
68
        return f"module('{self.filename}')"
1✔
69

70

71
class Variables:
1✔
72
    """
73
    Provides a high level interface to module level variables
74
    """
75

76
    def __init__(self, module):
1✔
77
        self.module = module
1✔
78

79
    @cache
1✔
80
    def keys(self):
1✔
81
        res = []
1✔
82
        for i in self.module.keys():
1✔
83
            if self.module[i].properties.attributes.is_variable:
1✔
84
                res.append(i)
1✔
85
        return set(res)
1✔
86

87
    def __contains__(self, key):
1✔
88
        if isinstance(key, str):
1✔
89
            return key in self.keys()
1✔
90
        elif isinstance(key, Symbol):
1✔
91
            return key.properties.attributes.is_variable
1✔
92

93
    def __getitem__(self, key):
1✔
94
        if key in self:
1✔
95
            if isinstance(key, str):
1✔
96
                return self.module[key]
1✔
97
            elif isinstance(key, Symbol):
1✔
98
                return key
1✔
99
        else:
100
            raise KeyError(f"Can't find {key} or its not a variable")
1✔
101

102
    def _id(self, key):
1✔
103
        if isinstance(key, str):
1✔
104
            return self.module[key].id
1✔
105
        elif isinstance(key, Symbol):
1✔
106
            return key.id
1✔
107

108
    @cache
1✔
109
    def type(self, key):
1✔
110
        """
111
        Return the Fortran type (INTEGER, REAL, LOGICAL, CHARACTER, etc)
112
        """
113
        if key in self:
1✔
114
            return self.module[self._id(key)].type
1✔
115

116
    @cache
1✔
117
    def kind(self, key):
1✔
118
        """
119
        Returns the Fortran kind (1,4,8,16) its not formally the number of bytes but
120
        for gfortran can be treated as such
121
        """
122
        if key in self:
1✔
123
            return self.module[self._id(key)].kind
1✔
124

125
    @cache
1✔
126
    def array(self, key):
1✔
127
        """
128
        Returns an array_spec object which stores information about if the variable
129
        is an array and if so, its shape, size etc
130
        """
131
        if key in self:
1✔
132
            return self.module[self._id(key)].properties.array_spec
1✔
133

134
    @cache
1✔
135
    def is_array(self, key) -> bool:
1✔
136
        """
137
        Returns if object is an array
138
        """
UNCOV
139
        if key in self:
×
UNCOV
140
            return self.module[self._id(key)].is_array
×
NEW
141
        return False
×
142

143

144
class Parameters:
1✔
145
    """
146
    Provides a high level interface to module parameters
147
    """
148

149
    def __init__(self, module):
1✔
150
        self.module = module
1✔
151

152
    @cache
1✔
153
    def keys(self):
1✔
154
        res = []
1✔
155
        for i in self.module.keys():
1✔
156
            if self.module[i].properties.attributes.is_parameter:
1✔
157
                res.append(i)
1✔
158
        return set(res)
1✔
159

160
    def __getitem__(self, key):
1✔
161
        if key in self:
1✔
162
            return self.module[key]
1✔
163

164
    def __contains__(self, key):
1✔
165
        return key in self.keys()
1✔
166

167
    @cache
1✔
168
    def value(self, key):
1✔
169
        """
170
        Returns the parameter value
171
        """
172
        if key in self:
1✔
173
            return self.module[key].properties.parameter.value
1✔
174

175
    @cache
1✔
176
    def type(self, key):
1✔
177
        """
178
        Return the Fortran type (INTEGER, REAL, LOGICAL, CHARACTER, etc)
179
        """
180
        if key in self:
1✔
181
            return self.module[key].properties.typespec.type
1✔
182

183
    @cache
1✔
184
    def kind(self, key):
1✔
185
        """
186
        Returns the Fortran kind (1,4,8,16) its not formally the number of bytes but
187
        for gfortran can be treated as such
188
        """
189
        if key in self:
1✔
190
            return self.module[key].properties.typespec.kind
1✔
191

192
    @cache
1✔
193
    def array(self, key):
1✔
194
        """
195
        Returns an array_spec object which stores information about if the variable
196
        is an array and if so, its shape, size etc
197
        """
198
        if key in self:
1✔
199
            return self.module[key].properties.array_spec
1✔
200

201

202
class Procedures:
1✔
203
    """
204
    Provides a high level interface to module procedures
205
    """
206

207
    def __init__(self, module):
1✔
208
        self.module = module
1✔
209

210
    @cache
1✔
211
    def keys(self):
1✔
212
        res = []
1✔
213
        for i in self.module.keys():
1✔
214
            if self.module[i].properties.attributes.is_procedure:
1✔
215
                res.append(i)
1✔
216
        return set(res)
1✔
217

218
    def __getitem__(self, key):
1✔
219
        if key in self:
1✔
220
            return self.module[key]
1✔
221

222
    def __contains__(self, key):
1✔
223
        return key in self.keys()
1✔
224

225
    @cache
1✔
226
    def result(self, key):
1✔
227
        """
228
        Return the function result variable or None if subroutine
229

230
        This can be fed back into the Variables() class for easier accessing
231
        """
232
        if key in self:
1✔
233
            ref = self.module[key].properties.symbol_reference
1✔
234
            if ref > 0:
1✔
235
                return self.module[ref]
1✔
236

237
    @cache
1✔
238
    def arguments(self, key):
1✔
239
        """
240
        Returns a dict of the dummy arguments to the procedure
241

242
        These can be fed back individually into the Variables() class for easier accessing
243
        """
244
        if key in self:
1✔
245
            ref = self.module[key].properties.formal_argument
1✔
246
            if ref:
1✔
247
                return {self.module[i].name: self.module[i] for i in ref}
1✔
248
            else:
249
                return {}
1✔
250

251

252
class DerivedTypes:
1✔
253
    """
254
    Provides a high level interface to module level derived type definitions
255
    """
256

257
    def __init__(self, module):
1✔
258
        self.module = module
1✔
259

260
    @cache
1✔
261
    def keys(self):
1✔
262
        res = []
1✔
263
        for i in self.module.keys():
1✔
264
            if self.module[i].is_dt:
1✔
265
                res.append(i)
1✔
266
        return set(res)
1✔
267

268
    def __getitem__(self, key):
1✔
269
        if key in self:
1✔
270
            return self.module[key]
1✔
271

272
    def __contains__(self, key):
1✔
273
        return key in self.keys()
1✔
274

275
    @cache
1✔
276
    def components(self, key):
1✔
277
        """
278
        Returns a dict of the components of the derived type
279

280
        Note the key must have the first letter capitalized to find the definition of the type
281
        """
282
        res = {}
1✔
283
        if key in self:
1✔
284
            ref = self.module[key]
1✔
285
            for component in ref.properties.components.keys():
1✔
286
                res[component] = ref.properties.components[component]
1✔
287
            return res
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