Skip to content

Commit a38e7f9

Browse files
committed
Merge branch 'master' into refactor/exceptions
2 parents 7bc2ed9 + 8b2960c commit a38e7f9

File tree

13 files changed

+191
-177
lines changed

13 files changed

+191
-177
lines changed

.github/workflows/main.yml

Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ jobs:
1010
strategy:
1111
matrix:
1212
os: [ubuntu-latest, windows-latest]
13-
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11-dev"]
13+
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12"]
1414
fail-fast: false
1515
runs-on: ${{ matrix.os }}
1616

@@ -24,9 +24,6 @@ jobs:
2424
- name: Setup
2525
run: pip install .[dev]
2626

27-
- name: Unittests
28-
run: pytest --doctest-modules
29-
3027
- name: Lint
3128
run: black --diff --check --verbose .
3229

@@ -35,28 +32,11 @@ jobs:
3532
python3 -m fortls.schema
3633
git diff --exit-code ./fortls/fortls.schema.json
3734
38-
coverage:
39-
strategy:
40-
matrix:
41-
os: [ubuntu-latest, windows-latest]
42-
python-version: ["3.8","3.10"]
43-
fail-fast: false
44-
runs-on: ${{ matrix.os }}
45-
46-
steps:
47-
- uses: actions/checkout@v4
48-
- uses: actions/setup-python@v5
49-
with:
50-
python-version: ${{ matrix.python-version }}
51-
52-
- name: Coverage report
53-
run: |
54-
pip install .[dev]
55-
pytest --doctest-modules
56-
shell: bash
35+
- name: Unittests
36+
run: pytest --doctest-modules -n auto
5737

5838
- name: Upload coverage to Codecov
59-
uses: codecov/codecov-action@v4
39+
uses: codecov/codecov-action@v4.3.1
6040
with:
6141
fail_ci_if_error: true
6242
verbose: true

.github/workflows/python-publish.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ jobs:
4242
with:
4343
user: __token__
4444
password: ${{ secrets.TEST_PYPI_API_TOKEN }}
45-
repository_url: https://test.pypi.org/legacy/
45+
repository-url: https://test.pypi.org/legacy/
4646
- name: Publish to PyPi
4747
if: startsWith(github.ref, 'refs/tags')
4848
uses: pypa/gh-action-pypi-publish@release/v1

.pre-commit-config.yaml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,27 @@
22
# See https://pre-commit.com/hooks.html for more hooks
33
repos:
44
- repo: https://github.com/pre-commit/pre-commit-hooks
5-
rev: v4.4.0
5+
rev: v4.6.0
66
hooks:
77
- id: trailing-whitespace
88
- id: end-of-file-fixer
99
- id: check-yaml
1010
- id: check-added-large-files
1111
args: ['--maxkb=2000']
1212
- repo: https://github.com/PyCQA/flake8
13-
rev: 6.0.0
13+
rev: 7.0.0
1414
hooks:
1515
- id: flake8
1616
- repo: https://github.com/asottile/pyupgrade
17-
rev: v3.9.0
17+
rev: v3.15.2
1818
hooks:
1919
- id: pyupgrade
2020
- repo: https://github.com/pycqa/isort
21-
rev: 5.12.0
21+
rev: 5.13.2
2222
hooks:
2323
- id: isort
2424
name: isort (python)
2525
- repo: https://github.com/psf/black
26-
rev: 23.7.0
26+
rev: 24.4.2
2727
hooks:
2828
- id: black

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@
3535
- Changed automatic detection of fixed/free-form of files to ignore
3636
preprocessor lines.
3737
([#302](https://github.com/fortran-lang/fortls/pull/302))
38+
- Moved project setup from `setup.cfg` to `pyproject.toml`
39+
([#384](https://github.com/fortran-lang/fortls/pull/384))
40+
- Bumped `setuptools` version to `>=61.0.0`
41+
([#384](https://github.com/fortran-lang/fortls/pull/384))
3842

3943
### Fixed
4044

fortls/parsers/internal/ast.py

Lines changed: 60 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,7 @@
1919
class FortranAST:
2020
def __init__(self, file_obj=None):
2121
self.file = file_obj
22-
self.path: str = None
23-
if file_obj is not None:
24-
self.path = file_obj.path
22+
self.path: str | None = file_obj.path if file_obj is not None else None
2523
self.global_dict: dict = {}
2624
self.scope_list: list = []
2725
self.variable_list: list = []
@@ -39,10 +37,10 @@ def __init__(self, file_obj=None):
3937
self.none_scope = None
4038
self.inc_scope = None
4139
self.current_scope = None
42-
self.END_SCOPE_REGEX: Pattern = None
43-
self.enc_scope_name: str = None
40+
self.end_scope_regex: Pattern | None = None
41+
self.enc_scope_name: str | None = None
4442
self.last_obj = None
45-
self.pending_doc: str = None
43+
self.pending_doc: str | None = None
4644

4745
def create_none_scope(self):
4846
"""Create empty scope to hold non-module contained items"""
@@ -60,7 +58,7 @@ def get_enc_scope_name(self):
6058
def add_scope(
6159
self,
6260
new_scope: Scope,
63-
END_SCOPE_REGEX: Pattern[str],
61+
end_scope_regex: Pattern[str],
6462
exportable: bool = True,
6563
req_container: bool = False,
6664
):
@@ -80,10 +78,10 @@ def add_scope(
8078
else:
8179
self.current_scope.add_child(new_scope)
8280
self.scope_stack.append(self.current_scope)
83-
if self.END_SCOPE_REGEX is not None:
84-
self.end_stack.append(self.END_SCOPE_REGEX)
81+
if self.end_scope_regex is not None:
82+
self.end_stack.append(self.end_scope_regex)
8583
self.current_scope = new_scope
86-
self.END_SCOPE_REGEX = END_SCOPE_REGEX
84+
self.end_scope_regex = end_scope_regex
8785
self.enc_scope_name = self.get_enc_scope_name()
8886
self.last_obj = new_scope
8987
if self.pending_doc is not None:
@@ -102,9 +100,9 @@ def end_scope(self, line_number: int, check: bool = True):
102100
else:
103101
self.current_scope = None
104102
if len(self.end_stack) > 0:
105-
self.END_SCOPE_REGEX = self.end_stack.pop()
103+
self.end_scope_regex = self.end_stack.pop()
106104
else:
107-
self.END_SCOPE_REGEX = None
105+
self.end_scope_regex = None
108106
self.enc_scope_name = self.get_enc_scope_name()
109107

110108
def add_variable(self, new_var: Variable):
@@ -170,11 +168,11 @@ def add_error(self, msg: str, sev: int, ln: int, sch: int, ech: int = None):
170168
def start_ppif(self, line_number: int):
171169
self.pp_if.append([line_number - 1, -1])
172170

173-
def end_ppif(self, line_number):
171+
def end_ppif(self, line_number: int):
174172
if len(self.pp_if) > 0:
175173
self.pp_if[-1][1] = line_number - 1
176174

177-
def get_scopes(self, line_number: int = None):
175+
def get_scopes(self, line_number: int | None = None):
178176
"""Get a list of all the scopes present in the line number provided.
179177
180178
Parameters
@@ -191,65 +189,69 @@ def get_scopes(self, line_number: int = None):
191189
return self.scope_list
192190
scope_list = []
193191
for scope in self.scope_list:
194-
if (line_number >= scope.sline) and (line_number <= scope.eline):
195-
if type(scope.parent) == Interface:
196-
for use_stmnt in scope.use:
197-
if type(use_stmnt) != Import:
198-
continue
199-
# Exclude the parent and all other scopes
200-
if use_stmnt.import_type == ImportTypes.NONE:
201-
return [scope]
202-
scope_list.append(scope)
203-
scope_list.extend(iter(scope.get_ancestors()))
192+
if not scope.sline <= line_number <= scope.eline:
193+
continue
194+
if type(scope.parent) is Interface:
195+
for use_stmnt in scope.use:
196+
if type(use_stmnt) is not Import:
197+
continue
198+
# Exclude the parent and all other scopes
199+
if use_stmnt.import_type == ImportTypes.NONE:
200+
return [scope]
201+
scope_list.append(scope)
202+
scope_list.extend(iter(scope.get_ancestors()))
204203
if scope_list or self.none_scope is None:
205204
return scope_list
206-
else:
207-
return [self.none_scope]
205+
return [self.none_scope]
208206

209207
def get_inner_scope(self, line_number: int):
210208
scope_sline = -1
211209
curr_scope = None
212210
for scope in self.scope_list:
213-
if scope.sline > scope_sline and (
214-
(line_number >= scope.sline) and (line_number <= scope.eline)
215-
):
211+
if scope.sline > scope_sline and scope.sline <= line_number <= scope.eline:
216212
curr_scope = scope
217213
scope_sline = scope.sline
218214
if (curr_scope is None) and (self.none_scope is not None):
219215
return self.none_scope
220216
return curr_scope
221217

222218
def get_object(self, FQSN: str):
223-
FQSN_split = FQSN.split("::")
224-
curr_obj = self.global_dict.get(FQSN_split[0])
225-
if curr_obj is None:
226-
# Look for non-exportable scopes
227-
for scope in self.scope_list:
228-
if FQSN_split[0] == scope.FQSN:
229-
curr_obj = scope
230-
break
231-
if curr_obj is None:
219+
def find_child_by_name(parent, name):
220+
for child in parent.children:
221+
if child.name == name:
222+
return child
223+
if child.name.startswith("#GEN_INT"):
224+
found = next(
225+
(
226+
int_child
227+
for int_child in child.get_children()
228+
if int_child.name == name
229+
),
230+
None,
231+
)
232+
if found:
233+
return found
232234
return None
233-
if len(FQSN_split) > 1:
234-
for name in FQSN_split[1:]:
235-
next_obj = None
236-
for child in curr_obj.children:
237-
if child.name.startswith("#GEN_INT"):
238-
for int_child in child.get_children():
239-
if int_child.name == name:
240-
next_obj = int_child
241-
break
242-
if next_obj is not None:
243-
break
244-
if child.name == name:
245-
next_obj = child
246-
break
247-
if next_obj is None:
248-
return None
249-
curr_obj = next_obj
250-
return curr_obj
251-
252-
def resolve_includes(self, workspace, path: str = None):
235+
236+
parts = FQSN.split("::")
237+
current = self.global_dict.get(parts[0])
238+
239+
# Look for non-exportable scopes
240+
if current is None:
241+
current = next(
242+
(scope for scope in self.scope_list if scope.FQSN == parts[0]), None
243+
)
244+
if current is None:
245+
return None
246+
247+
for part in parts[1:]:
248+
current = find_child_by_name(current, part)
249+
if current is None:
250+
return None
251+
252+
return current
253+
254+
def resolve_includes(self, workspace, path: str | None = None):
253255
file_dir = os.path.dirname(self.path)
254256
for inc in self.include_statements:
255257
file_path = os.path.normpath(os.path.join(file_dir, inc.path))

0 commit comments

Comments
 (0)