Skip to content

Commit f8ea714

Browse files
committed
run black
1 parent 6619e5e commit f8ea714

File tree

7 files changed

+138
-47
lines changed

7 files changed

+138
-47
lines changed

schema_scribe/components/writers/notion_writer.py

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -53,20 +53,28 @@ def _connect(self):
5353
api_token_param = self.params.get("api_token")
5454
token_to_use = None
5555

56-
logger.debug(f"NotionWriter._connect: raw api_token_param: {api_token_param}")
56+
logger.debug(
57+
f"NotionWriter._connect: raw api_token_param: {api_token_param}"
58+
)
5759

5860
if api_token_param:
59-
if api_token_param.startswith("${") and api_token_param.endswith("}"):
61+
if api_token_param.startswith("${") and api_token_param.endswith(
62+
"}"
63+
):
6064
env_var = api_token_param[2:-1]
6165
token_to_use = os.getenv(env_var)
62-
logger.debug(f"NotionWriter._connect: resolved from env '{env_var}': {token_to_use}")
66+
logger.debug(
67+
f"NotionWriter._connect: resolved from env '{env_var}': {token_to_use}"
68+
)
6369
if not token_to_use:
6470
raise ConfigError(
6571
f"Environment variable '{env_var}' is required but not set."
6672
)
6773
else:
6874
token_to_use = api_token_param
69-
logger.debug(f"NotionWriter._connect: using direct token: {token_to_use}")
75+
logger.debug(
76+
f"NotionWriter._connect: using direct token: {token_to_use}"
77+
)
7078

7179
if not token_to_use:
7280
raise ConfigError(
@@ -137,23 +145,23 @@ def _H2(self, text: str) -> Dict[str, Any]:
137145
return {
138146
"object": "block",
139147
"type": "heading_2",
140-
"heading_2": {"rich_text": [{"text": {"content": text}}]}
148+
"heading_2": {"rich_text": [{"text": {"content": text}}]},
141149
}
142150

143151
def _H3(self, text: str) -> Dict[str, Any]:
144152
"""Creates a Notion Heading 3 block."""
145153
return {
146154
"object": "block",
147155
"type": "heading_3",
148-
"heading_3": {"rich_text": [{"text": {"content": text}}]}
156+
"heading_3": {"rich_text": [{"text": {"content": text}}]},
149157
}
150158

151159
def _Para(self, text: str) -> Dict[str, Any]:
152160
"""Creates a Notion Paragraph block."""
153161
return {
154162
"object": "block",
155163
"type": "paragraph",
156-
"paragraph": {"rich_text": [{"text": {"content": text}}]}
164+
"paragraph": {"rich_text": [{"text": {"content": text}}]},
157165
}
158166

159167
def _Code(self, text: str, lang: str = "sql") -> Dict[str, Any]:
@@ -176,8 +184,7 @@ def _clean_mermaid_code(self, code: str) -> str:
176184
return code.replace("```mermaid", "").replace("```", "").strip()
177185

178186
def _generate_notion_blocks(
179-
self,
180-
catalog_data: Dict[str, Any]
187+
self, catalog_data: Dict[str, Any]
181188
) -> List[Dict[str, Any]]:
182189
"""
183190
Dynamically generates Notion blocks by detecting the catalog structure.
@@ -215,9 +222,7 @@ def _generate_notion_blocks(
215222
return [self._Para("Unknown catalog structure provided.")]
216223

217224
def _create_column_table(
218-
self,
219-
columns: List[Dict[str, Any]],
220-
is_dbt: bool = False
225+
self, columns: List[Dict[str, Any]], is_dbt: bool = False
221226
) -> Dict[str, Any]:
222227
"""
223228
Creates a Notion Table block to display column details.
@@ -287,8 +292,7 @@ def _generate_mermaid_erd(self, foreign_keys: List[Dict[str, str]]) -> str:
287292
return "\n".join(code)
288293

289294
def _generate_db_blocks(
290-
self,
291-
catalog_data: Dict[str, Any]
295+
self, catalog_data: Dict[str, Any]
292296
) -> List[Dict[str, Any]]:
293297
"""
294298
Generates a list of Notion blocks for a traditional database catalog.
@@ -334,8 +338,7 @@ def _generate_db_blocks(
334338
return blocks
335339

336340
def _generate_dbt_blocks(
337-
self,
338-
catalog_data: Dict[str, Any]
341+
self, catalog_data: Dict[str, Any]
339342
) -> List[Dict[str, Any]]:
340343
"""
341344
Generates a list of Notion blocks for a dbt project catalog.

schema_scribe/services/catalog_generator.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,4 +217,4 @@ def generate_catalog(
217217
catalog_data["foreign_keys"] = foreign_keys
218218

219219
logger.info("Catalog generation completed.")
220-
return catalog_data
220+
return catalog_data

schema_scribe/tests/integration/test_db_workflow.py

Lines changed: 94 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@
1111
from unittest.mock import MagicMock, patch
1212

1313
from schema_scribe.workflows.db_workflow import DbWorkflow
14-
from schema_scribe.core.interfaces import BaseConnector, BaseLLMClient, BaseWriter
14+
from schema_scribe.core.interfaces import (
15+
BaseConnector,
16+
BaseLLMClient,
17+
BaseWriter,
18+
)
1519

1620

1721
@pytest.fixture
@@ -27,33 +31,97 @@ def mock_db_connector(sqlite_db: str):
2731
{"name": "orders", "comment": None},
2832
]
2933
mock_connector.get_views.return_value = [
30-
{"name": "user_orders", "definition": "SELECT * FROM users JOIN orders ON users.id = orders.user_id"}
34+
{
35+
"name": "user_orders",
36+
"definition": "SELECT * FROM users JOIN orders ON users.id = orders.user_id",
37+
}
3138
]
3239
mock_connector.get_columns.side_effect = [
3340
# users table columns
3441
[
35-
{"name": "id", "type": "INTEGER", "is_nullable": False, "is_pk": True, "comment": None},
36-
{"name": "email", "type": "TEXT", "is_nullable": False, "is_pk": False, "comment": None},
42+
{
43+
"name": "id",
44+
"type": "INTEGER",
45+
"is_nullable": False,
46+
"is_pk": True,
47+
"comment": None,
48+
},
49+
{
50+
"name": "email",
51+
"type": "TEXT",
52+
"is_nullable": False,
53+
"is_pk": False,
54+
"comment": None,
55+
},
3756
],
3857
# products table columns
3958
[
40-
{"name": "id", "type": "INTEGER", "is_nullable": False, "is_pk": True, "comment": None},
41-
{"name": "name", "type": "TEXT", "is_nullable": False, "is_pk": False, "comment": None},
42-
{"name": "price", "type": "REAL", "is_nullable": False, "is_pk": False, "comment": None},
59+
{
60+
"name": "id",
61+
"type": "INTEGER",
62+
"is_nullable": False,
63+
"is_pk": True,
64+
"comment": None,
65+
},
66+
{
67+
"name": "name",
68+
"type": "TEXT",
69+
"is_nullable": False,
70+
"is_pk": False,
71+
"comment": None,
72+
},
73+
{
74+
"name": "price",
75+
"type": "REAL",
76+
"is_nullable": False,
77+
"is_pk": False,
78+
"comment": None,
79+
},
4380
],
4481
# orders table columns
4582
[
46-
{"name": "id", "type": "INTEGER", "is_nullable": False, "is_pk": True, "comment": None},
47-
{"name": "user_id", "type": "INTEGER", "is_nullable": False, "is_pk": False, "comment": None},
48-
{"name": "product_id", "type": "INTEGER", "is_nullable": False, "is_pk": False, "comment": None},
83+
{
84+
"name": "id",
85+
"type": "INTEGER",
86+
"is_nullable": False,
87+
"is_pk": True,
88+
"comment": None,
89+
},
90+
{
91+
"name": "user_id",
92+
"type": "INTEGER",
93+
"is_nullable": False,
94+
"is_pk": False,
95+
"comment": None,
96+
},
97+
{
98+
"name": "product_id",
99+
"type": "INTEGER",
100+
"is_nullable": False,
101+
"is_pk": False,
102+
"comment": None,
103+
},
49104
],
50105
]
51106
mock_connector.get_foreign_keys.return_value = [
52-
{"source_table": "orders", "source_column": "user_id", "target_table": "users", "target_column": "id"},
53-
{"source_table": "orders", "source_column": "product_id", "target_table": "products", "target_column": "id"},
107+
{
108+
"source_table": "orders",
109+
"source_column": "user_id",
110+
"target_table": "users",
111+
"target_column": "id",
112+
},
113+
{
114+
"source_table": "orders",
115+
"source_column": "product_id",
116+
"target_table": "products",
117+
"target_column": "id",
118+
},
54119
]
55120
mock_connector.get_column_profile.return_value = {
56-
"total_count": 0, "null_count": 0, "distinct_count": 0, "is_unique": True
121+
"total_count": 0,
122+
"null_count": 0,
123+
"distinct_count": 0,
124+
"is_unique": True,
57125
}
58126
mock_connector.close.return_value = None
59127
return mock_connector
@@ -66,7 +134,9 @@ def mock_llm_client():
66134
"""
67135
mock_client = MagicMock(spec=BaseLLMClient)
68136
mock_client.llm_profile_name = "test_llm"
69-
mock_client.get_description.return_value = "This is an AI-generated description."
137+
mock_client.get_description.return_value = (
138+
"This is an AI-generated description."
139+
)
70140
return mock_client
71141

72142

@@ -113,9 +183,11 @@ def test_db_workflow_end_to_end(
113183
# 1. Verify components were called
114184
mock_db_connector.get_tables.assert_called_once()
115185
mock_db_connector.get_views.assert_called_once()
116-
assert mock_db_connector.get_columns.call_count == 3 # Only called for tables
186+
assert (
187+
mock_db_connector.get_columns.call_count == 3
188+
) # Only called for tables
117189
mock_db_connector.get_foreign_keys.assert_called_once()
118-
mock_llm_client.get_description.assert_called() # Called for tables, views, columns
190+
mock_llm_client.get_description.assert_called() # Called for tables, views, columns
119191
mock_writer.write.assert_called_once()
120192
mock_db_connector.close.assert_called_once()
121193

@@ -129,7 +201,7 @@ def test_db_workflow_end_to_end(
129201

130202
assert captured_writer_params == {
131203
"db_profile_name": "test_db",
132-
"db_connector": mock_db_connector, # Added mock_db_connector to expected params
204+
"db_connector": mock_db_connector, # Added mock_db_connector to expected params
133205
"output_filename": str(output_md_path),
134206
}
135207

@@ -182,7 +254,11 @@ def test_db_workflow_end_to_end_with_profiling(
182254
for call in calls:
183255
prompt_text = call[0][0]
184256
# Make the search more flexible
185-
if "Table: {'name': 'users', 'comment': None}" in prompt_text and "Column: id" in prompt_text and "Data Profile Context:" in prompt_text:
257+
if (
258+
"Table: {'name': 'users', 'comment': None}" in prompt_text
259+
and "Column: id" in prompt_text
260+
and "Data Profile Context:" in prompt_text
261+
):
186262
users_id_prompt = prompt_text
187263
break
188264

schema_scribe/tests/integration/test_dbt_workflow.py

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,11 @@
1616

1717
from schema_scribe.workflows.dbt_workflow import DbtWorkflow
1818
from schema_scribe.core.exceptions import CIError
19-
from schema_scribe.core.interfaces import BaseConnector, BaseLLMClient, BaseWriter
19+
from schema_scribe.core.interfaces import (
20+
BaseConnector,
21+
BaseLLMClient,
22+
BaseWriter,
23+
)
2024

2125
# A minimal manifest.json structure needed for the tests
2226
MINIMAL_MANIFEST = {
@@ -129,7 +133,9 @@ def mock_llm_client():
129133
"""
130134
mock_client = MagicMock(spec=BaseLLMClient)
131135
mock_client.llm_profile_name = "test_llm"
132-
mock_client.get_description.return_value = "This is an AI-generated description."
136+
mock_client.get_description.return_value = (
137+
"This is an AI-generated description."
138+
)
133139
return mock_client
134140

135141

@@ -221,7 +227,9 @@ def test_dbt_workflow_update(
221227
{"name": "first_name", "description": "", "type": "TEXT"},
222228
],
223229
"path": "customers.sql",
224-
"original_file_path": os.path.join(dbt_project, "models", "customers.sql"),
230+
"original_file_path": os.path.join(
231+
dbt_project, "models", "customers.sql"
232+
),
225233
}
226234
]
227235
mock_parser_constructor.return_value = mock_parser_instance
@@ -282,7 +290,9 @@ def test_dbt_workflow_check_fails(
282290
{"name": "first_name", "description": "", "type": "TEXT"},
283291
],
284292
"path": "customers.sql",
285-
"original_file_path": os.path.join(dbt_project, "models", "customers.sql"),
293+
"original_file_path": os.path.join(
294+
dbt_project, "models", "customers.sql"
295+
),
286296
}
287297
]
288298
mock_parser_constructor.return_value = mock_parser_instance
@@ -327,7 +337,9 @@ def test_dbt_workflow_check_succeeds(
327337
{"name": "first_name", "description": "", "type": "TEXT"},
328338
],
329339
"path": "customers.sql",
330-
"original_file_path": os.path.join(dbt_project, "models", "customers.sql"),
340+
"original_file_path": os.path.join(
341+
dbt_project, "models", "customers.sql"
342+
),
331343
}
332344
]
333345
mock_parser_constructor.return_value = mock_parser_instance
@@ -501,4 +513,4 @@ def test_dbt_workflow_drift_mode_drift_detected(
501513
assert (
502514
"Unique ID for the customer" in drift_prompt_call[0][0]
503515
) # Existing doc
504-
assert "Is Unique: False" in drift_prompt_call[0][0] # Conflicting stat
516+
assert "Is Unique: False" in drift_prompt_call[0][0] # Conflicting stat

schema_scribe/tests/integration/test_lineage_workflow.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ def test_lineage_workflow_e2e(
3636
"target_column": "id",
3737
}
3838
]
39-
mock_db_connector.db_profile_name = "test_db" # Add this for logging
39+
mock_db_connector.db_profile_name = "test_db" # Add this for logging
4040
mock_db_connector.close.return_value = None
4141

4242
# --- Mock dbt Parser (Logical Lineage) ---

schema_scribe/tests/unit/llm_clients/test_google_client.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,5 +51,5 @@ def test_google_client_get_description(mock_genai, mocker):
5151
# The actual call includes generation_config
5252
mock_model_instance.generate_content.assert_called_once_with(
5353
"test prompt",
54-
generation_config=mock_genai.GenerationConfig(max_output_tokens=150)
55-
)
54+
generation_config=mock_genai.GenerationConfig(max_output_tokens=150),
55+
)

schema_scribe/tests/unit/writers/test_notion_writer.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ def test_notion_writer_success(mock_notion_client, mock_db_catalog_data):
121121
)
122122
assert table_h2 is not None
123123

124+
124125
@patch.dict(os.environ, {"NOTION_TEST_KEY": "env_key_value"})
125126
@patch("schema_scribe.components.writers.notion_writer.Client")
126127
def test_notion_writer_resolves_env_var(
@@ -134,7 +135,7 @@ def test_notion_writer_resolves_env_var(
134135
the Notion client.
135136
"""
136137
mock_notion_client.return_value = MagicMock() # Basic mock
137-
138+
138139
writer = NotionWriter()
139140
kwargs = {
140141
"api_token": "${NOTION_TEST_KEY}", # Reference the env var
@@ -143,7 +144,6 @@ def test_notion_writer_resolves_env_var(
143144

144145
writer.write(mock_db_catalog_data, **kwargs)
145146

146-
147147
# Assert client was initialized with the *resolved* key
148148
mock_notion_client.assert_called_once()
149149
call_args, call_kwargs = mock_notion_client.call_args
@@ -165,4 +165,4 @@ def test_notion_writer_config_errors(mock_db_catalog_data):
165165

166166
# 2. Missing parent_page_id
167167
with pytest.raises(ConfigError, match="'parent_page_id' is required"):
168-
writer.write(mock_db_catalog_data, api_token="fake_token")
168+
writer.write(mock_db_catalog_data, api_token="fake_token")

0 commit comments

Comments
 (0)