Skip to content

Commit de7099e

Browse files
anakin87shadeMe
andauthored
ci: add job to check imports (#8594)
* try checking imports * clarify error message * better fmt * do not show complete list of successfully imported packages * refinements * relnote * add missing forward references * better function name * linting * fix linting * Update .github/utils/check_imports.py Co-authored-by: Madeesh Kannan <[email protected]> --------- Co-authored-by: Madeesh Kannan <[email protected]>
1 parent 163c06f commit de7099e

File tree

6 files changed

+129
-73
lines changed

6 files changed

+129
-73
lines changed

Diff for: .github/utils/check_imports.py

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import os
2+
import sys
3+
import importlib
4+
import traceback
5+
from haystack import logging # pylint: disable=unused-import # this is needed to avoid circular imports
6+
7+
def validate_package_imports(directory: str):
8+
"""
9+
Recursively search for directories with __init__.py and import them.
10+
"""
11+
imported = []
12+
failed = []
13+
14+
sys.path.insert(0, directory)
15+
16+
for root, _, files in os.walk(directory):
17+
# skip directories without __init__.py
18+
if not '__init__.py' in files:
19+
continue
20+
21+
init_path = os.path.join(root, '__init__.py')
22+
23+
# skip haystack/__init__.py to avoid circular imports
24+
if init_path.endswith(f'{directory}/__init__.py'):
25+
continue
26+
27+
# convert filesystem path to Python module name
28+
relative_path = os.path.relpath(root, directory)
29+
module_name = relative_path.replace(os.path.sep, '.')
30+
if module_name == '.':
31+
module_name = os.path.basename(directory)
32+
33+
try:
34+
importlib.import_module(module_name)
35+
imported.append(module_name)
36+
except:
37+
failed.append({
38+
'module': module_name,
39+
'traceback': traceback.format_exc()
40+
})
41+
42+
return imported, failed
43+
44+
45+
def main():
46+
"""
47+
This script checks that all Haystack packages can be imported successfully.
48+
This can detect several issues.
49+
One example is forgetting to use a forward reference for a type hint coming
50+
from a lazy import.
51+
"""
52+
print("Checking imports from Haystack packages...")
53+
imported, failed = validate_package_imports(directory="haystack")
54+
55+
if not imported:
56+
print("\nNO PACKAGES WERE IMPORTED")
57+
sys.exit(1)
58+
59+
print(f"\nSUCCESSFULLY IMPORTED {len(imported)} PACKAGES")
60+
61+
if failed:
62+
print(f"\nFAILED TO IMPORT {len(failed)} PACKAGES:")
63+
for fail in failed:
64+
print(f" - {fail['module']}")
65+
66+
print("\nERRORS:")
67+
for fail in failed:
68+
print(f" - {fail['module']}\n")
69+
print(f" {fail['traceback']}\n\n")
70+
sys.exit(1)
71+
72+
73+
if __name__ == '__main__':
74+
main()

Diff for: .github/workflows/tests.yml

+47
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,53 @@ jobs:
8585
- "branch:${{ github.ref_name }}"
8686
- "url:https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
8787
88+
check-imports:
89+
needs: format
90+
runs-on: ubuntu-latest
91+
steps:
92+
- uses: actions/checkout@v4
93+
94+
- uses: actions/setup-python@v5
95+
with:
96+
python-version: "${{ env.PYTHON_VERSION }}"
97+
98+
- name: Install Hatch
99+
run: pip install hatch==${{ env.HATCH_VERSION }}
100+
101+
- name: Check imports
102+
run: hatch run python .github/utils/check_imports.py
103+
104+
- name: Calculate alert data
105+
id: calculator
106+
shell: bash
107+
if: (success() || failure()) && github.ref_name == 'main'
108+
run: |
109+
if [ "${{ job.status }}" = "success" ]; then
110+
echo "alert_type=success" >> "$GITHUB_OUTPUT";
111+
else
112+
echo "alert_type=error" >> "$GITHUB_OUTPUT";
113+
fi
114+
115+
- name: Send event to Datadog
116+
if: (success() || failure()) && github.ref_name == 'main'
117+
uses: masci/datadog@v1
118+
with:
119+
api-key: ${{ secrets.CORE_DATADOG_API_KEY }}
120+
api-url: https://api.datadoghq.eu
121+
events: |
122+
- title: "${{ github.workflow }} workflow"
123+
text: "Job ${{ github.job }} in branch ${{ github.ref_name }}"
124+
alert_type: "${{ steps.calculator.outputs.alert_type }}"
125+
source_type_name: "Github"
126+
host: ${{ github.repository_owner }}
127+
tags:
128+
- "project:${{ github.repository }}"
129+
- "job:${{ github.job }}"
130+
- "run_id:${{ github.run_id }}"
131+
- "workflow:${{ github.workflow }}"
132+
- "branch:${{ github.ref_name }}"
133+
- "url:https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
134+
88135
unit-tests:
89136
name: Unit / ${{ matrix.os }}
90137
needs: format

Diff for: haystack/components/connectors/openapi_service.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ def _parse_message(self, message: ChatMessage) -> List[Dict[str, Any]]:
181181
)
182182
return function_payloads
183183

184-
def _authenticate_service(self, openapi_service: OpenAPI, credentials: Optional[Union[dict, str]] = None):
184+
def _authenticate_service(self, openapi_service: "OpenAPI", credentials: Optional[Union[dict, str]] = None):
185185
"""
186186
Authentication with an OpenAPI service.
187187
@@ -236,7 +236,7 @@ def _authenticate_service(self, openapi_service: OpenAPI, credentials: Optional[
236236
f"for it. Check the service configuration and credentials."
237237
)
238238

239-
def _invoke_method(self, openapi_service: OpenAPI, method_invocation_descriptor: Dict[str, Any]) -> Any:
239+
def _invoke_method(self, openapi_service: "OpenAPI", method_invocation_descriptor: Dict[str, Any]) -> Any:
240240
"""
241241
Invokes the specified method on the OpenAPI service.
242242

Diff for: pyproject.toml

-4
Original file line numberDiff line numberDiff line change
@@ -123,10 +123,6 @@ extra-dependencies = [
123123
# Structured logging
124124
"structlog",
125125

126-
# Looking for missing imports
127-
"isort",
128-
"pyproject-parser",
129-
130126
# Test
131127
"pytest",
132128
"pytest-bdd",
+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
enhancements:
3+
- |
4+
Add a testing job to check that all packages can be imported successfully.
5+
This should help detecting several issues, such as forgetting to use a
6+
forward reference for a type hint coming from a lazy import.

Diff for: test/test_imports.py

-67
This file was deleted.

0 commit comments

Comments
 (0)