Skip to content

Commit 15dd042

Browse files
committed
fix: stop early SQL lint promptly on Ctrl-C and match lint paths without the Windows verbatim prefix
1 parent 5abe26b commit 15dd042

20 files changed

Lines changed: 220 additions & 58 deletions

File tree

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
//! Joining a native thread from Python's main thread without hiding Ctrl+C.
2+
3+
use std::thread::JoinHandle;
4+
use std::time::Duration;
5+
6+
use pyo3::prelude::{PyErr, Python};
7+
8+
/// How often a join checks for pending signals such as Ctrl+C.
9+
const SIGNAL_POLL_INTERVAL: Duration = Duration::from_millis(5);
10+
11+
/// A joined thread's outcome, or the signal raised while waiting for it.
12+
pub(crate) enum Joined<T> {
13+
Finished(std::thread::Result<T>),
14+
Interrupted(PyErr),
15+
}
16+
17+
/// Join `thread` without the GIL; on a signal call `interrupt`, finish the join and return the signal.
18+
pub(crate) fn join_interruptibly<T: Send>(
19+
py: Python<'_>,
20+
thread: JoinHandle<T>,
21+
interrupt: impl FnOnce(),
22+
) -> Joined<T> {
23+
while !thread.is_finished() {
24+
if let Err(signal) = py.check_signals() {
25+
interrupt();
26+
let _ = py.detach(|| thread.join());
27+
return Joined::Interrupted(signal);
28+
}
29+
py.detach(|| std::thread::sleep(SIGNAL_POLL_INTERVAL));
30+
}
31+
Joined::Finished(py.detach(|| thread.join()))
32+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
pub(crate) mod constants;
22
pub(crate) mod exit_signal;
3+
pub(crate) mod interruptible_join;

‎crates/sqlbuild-python/src/bindings/_helpers/planner_migrations/column_entries.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ pub(super) fn checked<'py>(
171171
&[
172172
(
173173
"connection",
174-
runtime_field(&runtime, |runtime| &runtime.connection)?,
174+
runtime_field(runtime, |runtime| &runtime.connection)?,
175175
),
176176
("destination", relation),
177177
],

‎crates/sqlbuild-python/src/bindings/_helpers/planner_migrations/discovery_models.rs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use std::collections::BTreeMap;
1717
pub(super) fn ordered<'py>(runtime: &Bound<'py, PyAny>) -> PyResult<Vec<Bound<'py, PyAny>>> {
1818
let mut models: BTreeMap<String, Bound<'py, PyAny>> = BTreeMap::new();
1919
let mut dependencies: BTreeMap<String, Vec<String>> = BTreeMap::new();
20-
for item in runtime_field(&runtime, |runtime| &runtime.project)?
20+
for item in runtime_field(runtime, |runtime| &runtime.project)?
2121
.getattr("models")?
2222
.try_iter()?
2323
{
@@ -77,7 +77,7 @@ pub(super) fn metadata<'py>(
7777
models: &[Bound<'py, PyAny>],
7878
) -> PyResult<Bound<'py, PyDict>> {
7979
let py = runtime.py();
80-
let project = runtime_field(&runtime, |runtime| &runtime.project)?;
80+
let project = runtime_field(runtime, |runtime| &runtime.project)?;
8181
let functions = native(
8282
py,
8383
NativeAttr::BuildFunctionLocalHashes,

‎crates/sqlbuild-python/src/bindings/_helpers/planner_migrations/model_overlay.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ pub(super) fn overlay<'py>(
125125
}
126126

127127
fn cursor_enabled(runtime: &Bound<'_, PyAny>, name: &Bound<'_, PyAny>) -> PyResult<bool> {
128-
for item in runtime_field(&runtime, |runtime| &runtime.project)?
128+
for item in runtime_field(runtime, |runtime| &runtime.project)?
129129
.getattr("models")?
130130
.try_iter()?
131131
{

‎crates/sqlbuild-python/src/bindings/_helpers/planner_migrations/planning_execution.rs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ fn migration_promotion<'py>(
2626
runtime: &Bound<'py, PyAny>,
2727
decision: &Bound<'py, PyAny>,
2828
) -> PyResult<Bound<'py, PyAny>> {
29-
let adapter = runtime_field(&runtime, |runtime| &runtime.adapter)?;
29+
let adapter = runtime_field(runtime, |runtime| &runtime.adapter)?;
3030
let promotion = registry::class(runtime.py(), RecordId::MigrationPromotion)?;
3131
if adapter
3232
.call_method0("supports_transactional_ddl")?
@@ -48,7 +48,7 @@ fn migration_with_execution<'py>(
4848
entry: &Bound<'py, PyAny>,
4949
) -> PyResult<Bound<'py, PyAny>> {
5050
let py = runtime.py();
51-
let adapter = runtime_field(&runtime, |runtime| &runtime.adapter)?;
51+
let adapter = runtime_field(runtime, |runtime| &runtime.adapter)?;
5252
let transient = if adapter.getattr("adapter_name")?.eq("snowflake")? {
5353
PyBool::new(
5454
py,

‎crates/sqlbuild-python/src/bindings/_helpers/planner_migrations/planning_origin.rs‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ fn named<'py>(
3333
runtime: &Bound<'py, PyAny>,
3434
state: &Bound<'py, PyAny>,
3535
) -> PyResult<Bound<'py, PyAny>> {
36-
for item in runtime_field(&runtime, |runtime| &runtime.project)?
36+
for item in runtime_field(runtime, |runtime| &runtime.project)?
3737
.getattr("models")?
3838
.try_iter()?
3939
{
@@ -74,7 +74,7 @@ fn input_error(py: Python<'_>, message: String) -> PyResult<PyErr> {
7474
#[pyfunction]
7575
#[pyo3(signature = (*, runtime))]
7676
fn migration_planning_database<'py>(runtime: &Bound<'py, PyAny>) -> PyResult<Bound<'py, PyAny>> {
77-
let project = runtime_field(&runtime, |runtime| &runtime.project)?;
77+
let project = runtime_field(runtime, |runtime| &runtime.project)?;
7878
let fallback = project.getattr("effective_target_database")?;
7979
for item in project.getattr("models")?.try_iter()? {
8080
let database = item?.getattr("destination")?.getattr("database")?;
@@ -89,7 +89,7 @@ fn migration_planning_database<'py>(runtime: &Bound<'py, PyAny>) -> PyResult<Bou
8989
#[pyo3(signature = (*, runtime))]
9090
fn migration_project_schemas<'py>(runtime: &Bound<'py, PyAny>) -> PyResult<Bound<'py, PyAny>> {
9191
let schemas = PySet::empty(runtime.py())?;
92-
for item in runtime_field(&runtime, |runtime| &runtime.project)?
92+
for item in runtime_field(runtime, |runtime| &runtime.project)?
9393
.getattr("models")?
9494
.try_iter()?
9595
{

‎crates/sqlbuild-python/src/bindings/_helpers/planner_phases/buildability.rs‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ pub(crate) fn check_selected_scope_buildability<'py>(
1818
deferral: &Bound<'py, PyAny>,
1919
) -> PyResult<()> {
2020
let py = runtime.py();
21-
let project = runtime_field(&runtime, |runtime| &runtime.project)?;
21+
let project = runtime_field(runtime, |runtime| &runtime.project)?;
2222
let selected_scope = scopes.getattr("selected_scope")?;
2323
let mut external_seeds: Vec<_> = Vec::new();
2424
for seed in project.getattr("seeds")?.try_iter()? {
@@ -35,7 +35,7 @@ pub(crate) fn check_selected_scope_buildability<'py>(
3535
("upstream_deps", selected_scope.getattr("upstream_deps")?),
3636
(
3737
"snapshot",
38-
warehouse_field(&warehouse, |warehouse| &warehouse.snapshot)?,
38+
warehouse_field(warehouse, |warehouse| &warehouse.snapshot)?,
3939
),
4040
(
4141
"deferred_relations",
@@ -70,10 +70,10 @@ pub(crate) fn check_selected_scope_buildability<'py>(
7070
check_selected_source_tables_exist(
7171
&project,
7272
(
73-
&runtime_field(&runtime, |runtime| &runtime.adapter)?,
74-
&runtime_field(&runtime, |runtime| &runtime.connection)?,
73+
&runtime_field(runtime, |runtime| &runtime.adapter)?,
74+
&runtime_field(runtime, |runtime| &runtime.connection)?,
7575
),
7676
&selected_scope,
77-
&warehouse_field(&warehouse, |warehouse| &warehouse.inspection_relations)?,
77+
&warehouse_field(warehouse, |warehouse| &warehouse.inspection_relations)?,
7878
)
7979
}

‎crates/sqlbuild-python/src/bindings/_helpers/planner_phases/execution_changes.rs‎

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -70,16 +70,16 @@ pub(crate) fn build_planner_entry_results<'py>(
7070
source_freshness: &Bound<'py, PyAny>,
7171
) -> PyResult<ModelEntryResults<'py>> {
7272
let py = runtime.py();
73-
let project = runtime_field(&runtime, |runtime| &runtime.project)?;
74-
let config = runtime_field(&runtime, |runtime| &runtime.project_config)?;
73+
let project = runtime_field(runtime, |runtime| &runtime.project)?;
74+
let config = runtime_field(runtime, |runtime| &runtime.project_config)?;
7575
let relations = planner_relations_context(RelationsRequest {
7676
project: project.clone(),
77-
adapter: runtime_field(&runtime, |runtime| &runtime.adapter)?,
78-
connection: runtime_field(&runtime, |runtime| &runtime.connection)?,
77+
adapter: runtime_field(runtime, |runtime| &runtime.adapter)?,
78+
connection: runtime_field(runtime, |runtime| &runtime.connection)?,
7979
scope: execution_scope.clone(),
8080
deferral: deferral.clone(),
8181
project_config: config.clone(),
82-
local_config: runtime_field(&runtime, |runtime| &runtime.local_config)?,
82+
local_config: runtime_field(runtime, |runtime| &runtime.local_config)?,
8383
known_source_columns: warehouse
8484
.getattr("inspection_relations")?
8585
.getattr("source_warehouse_columns")?,
@@ -132,7 +132,7 @@ pub(crate) fn build_planner_entry_results<'py>(
132132
),
133133
(
134134
"invocation_time",
135-
runtime_field(&runtime, |runtime| &runtime.invocation_time)?,
135+
runtime_field(runtime, |runtime| &runtime.invocation_time)?,
136136
),
137137
("max_microbatches", max_microbatches),
138138
(
@@ -147,9 +147,9 @@ pub(crate) fn build_planner_entry_results<'py>(
147147
)?;
148148
plan_entries(PlanEntriesRequest {
149149
project,
150-
adapter: runtime_field(&runtime, |runtime| &runtime.adapter)?,
150+
adapter: runtime_field(runtime, |runtime| &runtime.adapter)?,
151151
scope: execution_scope.clone(),
152-
snapshot: warehouse_field(&warehouse, |warehouse| &warehouse.snapshot)?,
152+
snapshot: warehouse_field(warehouse, |warehouse| &warehouse.snapshot)?,
153153
relations,
154154
resolved_models: reconciliation.resolved_actions.getattr("models")?,
155155
cursor_overrides: overrides.getattr("cursor_overrides")?,

‎crates/sqlbuild-python/src/bindings/_helpers/planner_phases/output_assembly.rs‎

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -93,11 +93,11 @@ pub(crate) fn base_plan_output<'py>(
9393
)?;
9494
let mut output = PlanOutputFields {
9595
fields: plan_output_fields(PlanOutputInputs {
96-
project: runtime_field(&runtime, |runtime| &runtime.project)?,
97-
adapter: runtime_field(&runtime, |runtime| &runtime.adapter)?,
96+
project: runtime_field(runtime, |runtime| &runtime.project)?,
97+
adapter: runtime_field(runtime, |runtime| &runtime.adapter)?,
9898
scope: execution_scope.clone(),
99-
snapshot: warehouse_field(&warehouse, |warehouse| &warehouse.snapshot)?,
100-
relations: warehouse_field(&warehouse, |warehouse| &warehouse.inspection_relations)?,
99+
snapshot: warehouse_field(warehouse, |warehouse| &warehouse.snapshot)?,
100+
relations: warehouse_field(warehouse, |warehouse| &warehouse.inspection_relations)?,
101101
changes: reconciliation.changes.clone(),
102102
model_entries: entries.entries,
103103
model_warnings: entries.warnings,
@@ -163,7 +163,7 @@ pub(crate) fn add_storage_policies<'py>(
163163
.is_truthy()?
164164
{
165165
let models = PyDict::new(py);
166-
for model in runtime_field(&runtime, |runtime| &runtime.project)?
166+
for model in runtime_field(runtime, |runtime| &runtime.project)?
167167
.getattr("models")?
168168
.try_iter()?
169169
{
@@ -178,7 +178,7 @@ pub(crate) fn add_storage_policies<'py>(
178178
("models_by_name", models.into_any()),
179179
(
180180
"fingerprints",
181-
warehouse_field(&warehouse, |warehouse| &warehouse.migration_fingerprints)?,
181+
warehouse_field(warehouse, |warehouse| &warehouse.migration_fingerprints)?,
182182
),
183183
(
184184
"dialect",
@@ -191,18 +191,18 @@ pub(crate) fn add_storage_policies<'py>(
191191
}
192192
let entries = with_column_rename_hints(
193193
&entries,
194-
&warehouse_field(&warehouse, |warehouse| &warehouse.column_rename_hints)?,
194+
&warehouse_field(warehouse, |warehouse| &warehouse.column_rename_hints)?,
195195
)?;
196-
let migration_entries = warehouse_field(&warehouse, |warehouse| &warehouse.migration_entries)?;
196+
let migration_entries = warehouse_field(warehouse, |warehouse| &warehouse.migration_entries)?;
197197
let column_entries =
198-
warehouse_field(&warehouse, |warehouse| &warehouse.column_migration_entries)?;
198+
warehouse_field(warehouse, |warehouse| &warehouse.column_migration_entries)?;
199199
let old_name_entries =
200-
warehouse_field(&warehouse, |warehouse| &warehouse.old_name_view_entries)?;
201-
let old_name_views = warehouse_field(&warehouse, |warehouse| &warehouse.old_name_views)?;
200+
warehouse_field(warehouse, |warehouse| &warehouse.old_name_view_entries)?;
201+
let old_name_views = warehouse_field(warehouse, |warehouse| &warehouse.old_name_views)?;
202202
let warnings = concat(
203203
py,
204204
&[
205-
warehouse_field(&warehouse, |warehouse| &warehouse.migration_warnings)?,
205+
warehouse_field(warehouse, |warehouse| &warehouse.migration_warnings)?,
206206
output.field("warnings")?,
207207
],
208208
)?;
@@ -254,7 +254,7 @@ pub(crate) fn add_plan_warnings<'py>(
254254
("changes", stale_warning_changes.clone()),
255255
(
256256
"snapshot",
257-
warehouse_field(&warehouse, |warehouse| &warehouse.snapshot)?,
257+
warehouse_field(warehouse, |warehouse| &warehouse.snapshot)?,
258258
),
259259
(
260260
"version_identities",

0 commit comments

Comments
 (0)