sqlmesh 0.196.4.dev2__py3-none-any.whl → 0.196.4.dev3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
sqlmesh/_version.py CHANGED
@@ -17,5 +17,5 @@ __version__: str
17
17
  __version_tuple__: VERSION_TUPLE
18
18
  version_tuple: VERSION_TUPLE
19
19
 
20
- __version__ = version = '0.196.4.dev2'
21
- __version_tuple__ = version_tuple = (0, 196, 4, 'dev2')
20
+ __version__ = version = '0.196.4.dev3'
21
+ __version_tuple__ = version_tuple = (0, 196, 4, 'dev3')
@@ -8,7 +8,7 @@ import operator as op
8
8
  from collections.abc import Iterator, Iterable, Set, Mapping, Callable
9
9
  from functools import reduce
10
10
  from sqlmesh.core.model import Model
11
- from sqlmesh.core.linter.rule import Rule, RuleViolation, Range
11
+ from sqlmesh.core.linter.rule import Rule, RuleViolation, Range, Fix
12
12
  from sqlmesh.core.console import LinterConsole, get_console
13
13
 
14
14
  if t.TYPE_CHECKING:
@@ -75,6 +75,7 @@ class Linter:
75
75
  model=model,
76
76
  violation_type="error",
77
77
  violation_range=violation.violation_range,
78
+ fixes=violation.fixes,
78
79
  )
79
80
  for violation in error_violations
80
81
  ] + [
@@ -84,6 +85,7 @@ class Linter:
84
85
  model=model,
85
86
  violation_type="warning",
86
87
  violation_range=violation.violation_range,
88
+ fixes=violation.fixes,
87
89
  )
88
90
  for violation in warn_violations
89
91
  ]
@@ -152,7 +154,8 @@ class AnnotatedRuleViolation(RuleViolation):
152
154
  model: Model,
153
155
  violation_type: t.Literal["error", "warning"],
154
156
  violation_range: t.Optional[Range] = None,
157
+ fixes: t.Optional[t.List[Fix]] = None,
155
158
  ) -> None:
156
- super().__init__(rule, violation_msg, violation_range)
159
+ super().__init__(rule, violation_msg, violation_range, fixes)
157
160
  self.model = model
158
161
  self.violation_type = violation_type
@@ -39,6 +39,22 @@ class Range:
39
39
  end: Position
40
40
 
41
41
 
42
+ @dataclass(frozen=True)
43
+ class TextEdit:
44
+ """A text edit to apply to a file."""
45
+
46
+ range: Range
47
+ new_text: str
48
+
49
+
50
+ @dataclass(frozen=True)
51
+ class Fix:
52
+ """A fix that can be applied to resolve a rule violation."""
53
+
54
+ title: str
55
+ edits: t.List[TextEdit]
56
+
57
+
42
58
  class _Rule(abc.ABCMeta):
43
59
  def __new__(cls: Type[_Rule], clsname: str, bases: t.Tuple, attrs: t.Dict) -> _Rule:
44
60
  attrs["name"] = clsname.lower()
@@ -66,10 +82,14 @@ class Rule(abc.ABC, metaclass=_Rule):
66
82
  self,
67
83
  violation_msg: t.Optional[str] = None,
68
84
  violation_range: t.Optional[Range] = None,
85
+ fixes: t.Optional[t.List[Fix]] = None,
69
86
  ) -> RuleViolation:
70
87
  """Create a RuleViolation instance for this rule"""
71
88
  return RuleViolation(
72
- rule=self, violation_msg=violation_msg or self.summary, violation_range=violation_range
89
+ rule=self,
90
+ violation_msg=violation_msg or self.summary,
91
+ violation_range=violation_range,
92
+ fixes=fixes,
73
93
  )
74
94
 
75
95
  def get_definition_location(self) -> RuleLocation:
@@ -103,11 +123,16 @@ class Rule(abc.ABC, metaclass=_Rule):
103
123
 
104
124
  class RuleViolation:
105
125
  def __init__(
106
- self, rule: Rule, violation_msg: str, violation_range: t.Optional[Range] = None
126
+ self,
127
+ rule: Rule,
128
+ violation_msg: str,
129
+ violation_range: t.Optional[Range] = None,
130
+ fixes: t.Optional[t.List[Fix]] = None,
107
131
  ) -> None:
108
132
  self.rule = rule
109
133
  self.violation_msg = violation_msg
110
134
  self.violation_range = violation_range
135
+ self.fixes = fixes or []
111
136
 
112
137
  def __repr__(self) -> str:
113
138
  return f"{self.rule.name}: {self.violation_msg}"
@@ -8,7 +8,7 @@ from sqlglot.expressions import Star
8
8
  from sqlglot.helper import subclasses
9
9
 
10
10
  from sqlmesh.core.linter.helpers import TokenPositionDetails
11
- from sqlmesh.core.linter.rule import Rule, RuleViolation, Range
11
+ from sqlmesh.core.linter.rule import Rule, RuleViolation, Range, Fix, TextEdit
12
12
  from sqlmesh.core.linter.definition import RuleSet
13
13
  from sqlmesh.core.model import Model, SqlModel
14
14
 
@@ -22,7 +22,8 @@ class NoSelectStar(Rule):
22
22
  return None
23
23
  if model.query.is_star:
24
24
  violation_range = self._get_range(model)
25
- return self.violation(violation_range=violation_range)
25
+ fixes = self._create_fixes(model, violation_range)
26
+ return self.violation(violation_range=violation_range, fixes=fixes)
26
27
  return None
27
28
 
28
29
  def _get_range(self, model: SqlModel) -> t.Optional[Range]:
@@ -37,6 +38,28 @@ class NoSelectStar(Rule):
37
38
 
38
39
  return None
39
40
 
41
+ def _create_fixes(
42
+ self, model: SqlModel, violation_range: t.Optional[Range]
43
+ ) -> t.Optional[t.List[Fix]]:
44
+ """Create fixes for the SELECT * violation."""
45
+ if not violation_range:
46
+ return None
47
+ columns = model.columns_to_types
48
+ if not columns:
49
+ return None
50
+ new_text = ", ".join(columns.keys())
51
+ return [
52
+ Fix(
53
+ title="Replace SELECT * with explicit column list",
54
+ edits=[
55
+ TextEdit(
56
+ range=violation_range,
57
+ new_text=new_text,
58
+ )
59
+ ],
60
+ )
61
+ ]
62
+
40
63
 
41
64
  class InvalidSelectStarExpansion(Rule):
42
65
  def check_model(self, model: Model) -> t.Optional[RuleViolation]:
sqlmesh/lsp/context.py CHANGED
@@ -1,5 +1,6 @@
1
1
  from dataclasses import dataclass
2
2
  from pathlib import Path
3
+ import uuid
3
4
  from sqlmesh.core.context import Context
4
5
  import typing as t
5
6
 
@@ -8,6 +9,7 @@ from sqlmesh.core.linter.definition import AnnotatedRuleViolation
8
9
  from sqlmesh.lsp.custom import ModelForRendering
9
10
  from sqlmesh.lsp.custom import AllModelsResponse, RenderModelEntry
10
11
  from sqlmesh.lsp.uri import URI
12
+ from lsprotocol import types
11
13
 
12
14
 
13
15
  @dataclass
@@ -33,8 +35,14 @@ class LSPContext:
33
35
  map: t.Dict[Path, t.Union[ModelTarget, AuditTarget]]
34
36
  _render_cache: t.Dict[Path, t.List[RenderModelEntry]]
35
37
  _lint_cache: t.Dict[Path, t.List[AnnotatedRuleViolation]]
38
+ _version_id: str
39
+ """
40
+ This is a version ID for the context. It is used to track changes to the context. It can be used to
41
+ return a version number to the LSP client.
42
+ """
36
43
 
37
44
  def __init__(self, context: Context) -> None:
45
+ self._version_id = str(uuid.uuid4())
38
46
  self.context = context
39
47
  self._render_cache = {}
40
48
  self._lint_cache = {}
@@ -62,6 +70,11 @@ class LSPContext:
62
70
  **audit_map,
63
71
  }
64
72
 
73
+ @property
74
+ def version_id(self) -> str:
75
+ """Get the version ID for the context."""
76
+ return self._version_id
77
+
65
78
  def render_model(self, uri: URI) -> t.List[RenderModelEntry]:
66
79
  """Get rendered models for a file, using cache when available.
67
80
 
@@ -150,6 +163,86 @@ class LSPContext:
150
163
  self._lint_cache[path] = diagnostics
151
164
  return diagnostics
152
165
 
166
+ def get_code_actions(
167
+ self, uri: URI, params: types.CodeActionParams
168
+ ) -> t.Optional[t.List[t.Union[types.Command, types.CodeAction]]]:
169
+ """Get code actions for a file."""
170
+
171
+ # Get the violations (which contain the fixes)
172
+ violations = self.lint_model(uri)
173
+
174
+ # Convert violations to a map for quick lookup
175
+ # Use a hashable representation of Range as the key
176
+ violation_map: t.Dict[
177
+ t.Tuple[str, t.Tuple[int, int, int, int]], AnnotatedRuleViolation
178
+ ] = {}
179
+ for violation in violations:
180
+ if violation.violation_range:
181
+ lsp_diagnostic = self.diagnostic_to_lsp_diagnostic(violation)
182
+ if lsp_diagnostic:
183
+ # Create a hashable key from the diagnostic message and range
184
+ key = (
185
+ lsp_diagnostic.message,
186
+ (
187
+ lsp_diagnostic.range.start.line,
188
+ lsp_diagnostic.range.start.character,
189
+ lsp_diagnostic.range.end.line,
190
+ lsp_diagnostic.range.end.character,
191
+ ),
192
+ )
193
+ violation_map[key] = violation
194
+
195
+ # Get diagnostics in the requested range
196
+ diagnostics = params.context.diagnostics if params.context else []
197
+
198
+ code_actions: t.List[t.Union[types.Command, types.CodeAction]] = []
199
+
200
+ for diagnostic in diagnostics:
201
+ # Find the corresponding violation
202
+ key = (
203
+ diagnostic.message,
204
+ (
205
+ diagnostic.range.start.line,
206
+ diagnostic.range.start.character,
207
+ diagnostic.range.end.line,
208
+ diagnostic.range.end.character,
209
+ ),
210
+ )
211
+ found_violation = violation_map.get(key)
212
+
213
+ if found_violation is not None and found_violation.fixes:
214
+ # Create code actions for each fix
215
+ for fix in found_violation.fixes:
216
+ # Convert our Fix to LSP TextEdits
217
+ text_edits = []
218
+ for edit in fix.edits:
219
+ text_edits.append(
220
+ types.TextEdit(
221
+ range=types.Range(
222
+ start=types.Position(
223
+ line=edit.range.start.line,
224
+ character=edit.range.start.character,
225
+ ),
226
+ end=types.Position(
227
+ line=edit.range.end.line,
228
+ character=edit.range.end.character,
229
+ ),
230
+ ),
231
+ new_text=edit.new_text,
232
+ )
233
+ )
234
+
235
+ # Create the code action
236
+ code_action = types.CodeAction(
237
+ title=fix.title,
238
+ kind=types.CodeActionKind.QuickFix,
239
+ diagnostics=[diagnostic],
240
+ edit=types.WorkspaceEdit(changes={params.text_document.uri: text_edits}),
241
+ )
242
+ code_actions.append(code_action)
243
+
244
+ return code_actions if code_actions else None
245
+
153
246
  def list_of_models_for_rendering(self) -> t.List[ModelForRendering]:
154
247
  """Get a list of models for rendering.
155
248
 
@@ -186,3 +279,68 @@ class LSPContext:
186
279
  from sqlmesh.lsp.completions import get_sql_completions
187
280
 
188
281
  return get_sql_completions(self, uri, file_content)
282
+
283
+ @staticmethod
284
+ def diagnostics_to_lsp_diagnostics(
285
+ diagnostics: t.List[AnnotatedRuleViolation],
286
+ ) -> t.List[types.Diagnostic]:
287
+ """
288
+ Converts a list of AnnotatedRuleViolations to a list of LSP diagnostics. It will remove duplicates based on the message and range.
289
+ """
290
+ lsp_diagnostics = {}
291
+ for diagnostic in diagnostics:
292
+ lsp_diagnostic = LSPContext.diagnostic_to_lsp_diagnostic(diagnostic)
293
+ if lsp_diagnostic is not None:
294
+ # Create a unique key combining message and range
295
+ diagnostic_key = (
296
+ lsp_diagnostic.message,
297
+ lsp_diagnostic.range.start.line,
298
+ lsp_diagnostic.range.start.character,
299
+ lsp_diagnostic.range.end.line,
300
+ lsp_diagnostic.range.end.character,
301
+ )
302
+ if diagnostic_key not in lsp_diagnostics:
303
+ lsp_diagnostics[diagnostic_key] = lsp_diagnostic
304
+ return list(lsp_diagnostics.values())
305
+
306
+ @staticmethod
307
+ def diagnostic_to_lsp_diagnostic(
308
+ diagnostic: AnnotatedRuleViolation,
309
+ ) -> t.Optional[types.Diagnostic]:
310
+ if diagnostic.model._path is None:
311
+ return None
312
+ if not diagnostic.violation_range:
313
+ with open(diagnostic.model._path, "r", encoding="utf-8") as file:
314
+ lines = file.readlines()
315
+ diagnostic_range = types.Range(
316
+ start=types.Position(line=0, character=0),
317
+ end=types.Position(line=len(lines) - 1, character=len(lines[-1])),
318
+ )
319
+ else:
320
+ diagnostic_range = types.Range(
321
+ start=types.Position(
322
+ line=diagnostic.violation_range.start.line,
323
+ character=diagnostic.violation_range.start.character,
324
+ ),
325
+ end=types.Position(
326
+ line=diagnostic.violation_range.end.line,
327
+ character=diagnostic.violation_range.end.character,
328
+ ),
329
+ )
330
+
331
+ # Get rule definition location for diagnostics link
332
+ rule_location = diagnostic.rule.get_definition_location()
333
+ rule_uri_wihout_extension = URI.from_path(rule_location.file_path)
334
+ rule_uri = f"{rule_uri_wihout_extension.value}#L{rule_location.start_line}"
335
+
336
+ # Use URI format to create a link for "related information"
337
+ return types.Diagnostic(
338
+ range=diagnostic_range,
339
+ message=diagnostic.violation_msg,
340
+ severity=types.DiagnosticSeverity.Error
341
+ if diagnostic.violation_type == "error"
342
+ else types.DiagnosticSeverity.Warning,
343
+ source="sqlmesh",
344
+ code=diagnostic.rule.name,
345
+ code_description=types.CodeDescription(href=rule_uri),
346
+ )
sqlmesh/lsp/main.py CHANGED
@@ -8,11 +8,13 @@ from pathlib import Path
8
8
  import urllib.parse
9
9
 
10
10
  from lsprotocol import types
11
+ from lsprotocol.types import (
12
+ WorkspaceDiagnosticRefreshRequest,
13
+ WorkspaceInlayHintRefreshRequest,
14
+ )
11
15
  from pygls.server import LanguageServer
12
-
13
16
  from sqlmesh._version import __version__
14
17
  from sqlmesh.core.context import Context
15
- from sqlmesh.core.linter.definition import AnnotatedRuleViolation
16
18
  from sqlmesh.lsp.api import (
17
19
  API_FEATURE,
18
20
  ApiRequest,
@@ -216,6 +218,79 @@ class SQLMeshLanguageServer:
216
218
  ]
217
219
  )
218
220
 
221
+ def _reload_context_and_publish_diagnostics(
222
+ self, ls: LanguageServer, uri: URI, document_uri: str
223
+ ) -> None:
224
+ """Helper method to reload context and publish diagnostics."""
225
+ if isinstance(self.context_state, NoContext):
226
+ return
227
+
228
+ if isinstance(self.context_state, ContextFailed):
229
+ if self.context_state.context:
230
+ try:
231
+ self.context_state.context.load()
232
+ # Creating a new LSPContext will naturally create fresh caches
233
+ self.context_state = ContextLoaded(
234
+ lsp_context=LSPContext(self.context_state.context)
235
+ )
236
+ except Exception as e:
237
+ ls.log_trace(f"Error loading context: {e}")
238
+ if not isinstance(self.context_state, ContextFailed):
239
+ raise Exception("Context state should be failed")
240
+ self.context_state = ContextFailed(
241
+ error_message=str(e), context=self.context_state.context
242
+ )
243
+ return
244
+ else:
245
+ # If there's no context, try to create one from scratch
246
+ try:
247
+ self._ensure_context_for_document(uri)
248
+ # If successful, context_state will be ContextLoaded
249
+ if isinstance(self.context_state, ContextLoaded):
250
+ ls.show_message(
251
+ "Successfully loaded SQLMesh context",
252
+ types.MessageType.Info,
253
+ )
254
+ except Exception as e:
255
+ ls.log_trace(f"Still cannot load context: {e}")
256
+ return
257
+
258
+ # Reload the context if it was successfully loaded
259
+ try:
260
+ context = self.context_state.lsp_context.context
261
+ context.load()
262
+ # Create new LSPContext which will have fresh, empty caches
263
+ self.context_state = ContextLoaded(lsp_context=LSPContext(context))
264
+ except Exception as e:
265
+ ls.log_trace(f"Error loading context: {e}")
266
+ self.context_state = ContextFailed(
267
+ error_message=str(e), context=self.context_state.lsp_context.context
268
+ )
269
+ return
270
+
271
+ # Send a workspace diagnostic refresh request to the client. This is used to notify the client that the diagnostics have changed.
272
+ ls.lsp.send_request(
273
+ types.WORKSPACE_DIAGNOSTIC_REFRESH,
274
+ WorkspaceDiagnosticRefreshRequest(
275
+ id=self.context_state.lsp_context.version_id,
276
+ ),
277
+ )
278
+
279
+ ls.lsp.send_request(
280
+ types.WORKSPACE_INLAY_HINT_REFRESH,
281
+ WorkspaceInlayHintRefreshRequest(
282
+ id=self.context_state.lsp_context.version_id,
283
+ ),
284
+ )
285
+
286
+ # Only publish diagnostics if client doesn't support pull diagnostics
287
+ if not self.client_supports_pull_diagnostics:
288
+ diagnostics = self.context_state.lsp_context.lint_model(uri)
289
+ ls.publish_diagnostics(
290
+ document_uri,
291
+ LSPContext.diagnostics_to_lsp_diagnostics(diagnostics),
292
+ )
293
+
219
294
  def _register_features(self) -> None:
220
295
  """Register LSP features on the internal LanguageServer instance."""
221
296
  for name, method in self._supported_custom_methods.items():
@@ -278,63 +353,13 @@ class SQLMeshLanguageServer:
278
353
  diagnostics = context.lint_model(uri)
279
354
  ls.publish_diagnostics(
280
355
  params.text_document.uri,
281
- SQLMeshLanguageServer._diagnostics_to_lsp_diagnostics(diagnostics),
356
+ LSPContext.diagnostics_to_lsp_diagnostics(diagnostics),
282
357
  )
283
358
 
284
359
  @self.server.feature(types.TEXT_DOCUMENT_DID_SAVE)
285
360
  def did_save(ls: LanguageServer, params: types.DidSaveTextDocumentParams) -> None:
286
361
  uri = URI(params.text_document.uri)
287
- if isinstance(self.context_state, NoContext):
288
- return
289
-
290
- if isinstance(self.context_state, ContextFailed):
291
- if self.context_state.context:
292
- try:
293
- self.context_state.context.load()
294
- self.context_state = ContextLoaded(
295
- lsp_context=LSPContext(self.context_state.context)
296
- )
297
- except Exception as e:
298
- ls.log_trace(f"Error loading context: {e}")
299
- if not isinstance(self.context_state, ContextFailed):
300
- raise Exception("Context state should be failed")
301
- self.context_state = ContextFailed(
302
- error_message=str(e), context=self.context_state.context
303
- )
304
- return
305
- else:
306
- # If there's no context, try to create one from scratch
307
- try:
308
- self._ensure_context_for_document(uri)
309
- # If successful, context_state will be ContextLoaded
310
- if isinstance(self.context_state, ContextLoaded):
311
- ls.show_message(
312
- "Successfully loaded SQLMesh context",
313
- types.MessageType.Info,
314
- )
315
- except Exception as e:
316
- ls.log_trace(f"Still cannot load context: {e}")
317
- return
318
-
319
- # Reload the context if was successfully
320
- try:
321
- context = self.context_state.lsp_context.context
322
- context.load()
323
- self.context_state = ContextLoaded(lsp_context=LSPContext(context))
324
- except Exception as e:
325
- ls.log_trace(f"Error loading context: {e}")
326
- self.context_state = ContextFailed(
327
- error_message=str(e), context=self.context_state.lsp_context.context
328
- )
329
- return
330
-
331
- # Only publish diagnostics if client doesn't support pull diagnostics
332
- if not self.client_supports_pull_diagnostics:
333
- diagnostics = self.context_state.lsp_context.lint_model(uri)
334
- ls.publish_diagnostics(
335
- params.text_document.uri,
336
- SQLMeshLanguageServer._diagnostics_to_lsp_diagnostics(diagnostics),
337
- )
362
+ self._reload_context_and_publish_diagnostics(ls, uri, params.text_document.uri)
338
363
 
339
364
  @self.server.feature(types.TEXT_DOCUMENT_FORMATTING)
340
365
  def formatting(
@@ -630,6 +655,21 @@ class SQLMeshLanguageServer:
630
655
  )
631
656
  return types.WorkspaceDiagnosticReport(items=[])
632
657
 
658
+ @self.server.feature(types.TEXT_DOCUMENT_CODE_ACTION)
659
+ def code_action(
660
+ ls: LanguageServer, params: types.CodeActionParams
661
+ ) -> t.Optional[t.List[t.Union[types.Command, types.CodeAction]]]:
662
+ try:
663
+ ls.log_trace(f"Codeactionrequest: {params}")
664
+ uri = URI(params.text_document.uri)
665
+ context = self._context_get_or_load(uri)
666
+ code_actions = context.get_code_actions(uri, params)
667
+ return code_actions
668
+
669
+ except Exception as e:
670
+ ls.log_trace(f"Error getting code actions: {e}")
671
+ return None
672
+
633
673
  @self.server.feature(
634
674
  types.TEXT_DOCUMENT_COMPLETION,
635
675
  types.CompletionOptions(trigger_characters=["@"]), # advertise "@" for macros
@@ -718,7 +758,7 @@ class SQLMeshLanguageServer:
718
758
  try:
719
759
  context = self._context_get_or_load(uri)
720
760
  diagnostics = context.lint_model(uri)
721
- return SQLMeshLanguageServer._diagnostics_to_lsp_diagnostics(diagnostics), 0
761
+ return LSPContext.diagnostics_to_lsp_diagnostics(diagnostics), 0
722
762
  except Exception:
723
763
  return [], 0
724
764
 
@@ -829,71 +869,6 @@ class SQLMeshLanguageServer:
829
869
  self.context_state = ContextFailed(error_message=str(e), context=context)
830
870
  return None
831
871
 
832
- @staticmethod
833
- def _diagnostic_to_lsp_diagnostic(
834
- diagnostic: AnnotatedRuleViolation,
835
- ) -> t.Optional[types.Diagnostic]:
836
- if diagnostic.model._path is None:
837
- return None
838
- if not diagnostic.violation_range:
839
- with open(diagnostic.model._path, "r", encoding="utf-8") as file:
840
- lines = file.readlines()
841
- range = types.Range(
842
- start=types.Position(line=0, character=0),
843
- end=types.Position(line=len(lines) - 1, character=len(lines[-1])),
844
- )
845
- else:
846
- range = types.Range(
847
- start=types.Position(
848
- line=diagnostic.violation_range.start.line,
849
- character=diagnostic.violation_range.start.character,
850
- ),
851
- end=types.Position(
852
- line=diagnostic.violation_range.end.line,
853
- character=diagnostic.violation_range.end.character,
854
- ),
855
- )
856
-
857
- # Get rule definition location for diagnostics link
858
- rule_location = diagnostic.rule.get_definition_location()
859
- rule_uri_wihout_extension = URI.from_path(rule_location.file_path)
860
- rule_uri = f"{rule_uri_wihout_extension.value}#L{rule_location.start_line}"
861
-
862
- # Use URI format to create a link for "related information"
863
- return types.Diagnostic(
864
- range=range,
865
- message=diagnostic.violation_msg,
866
- severity=types.DiagnosticSeverity.Error
867
- if diagnostic.violation_type == "error"
868
- else types.DiagnosticSeverity.Warning,
869
- source="sqlmesh",
870
- code=diagnostic.rule.name,
871
- code_description=types.CodeDescription(href=rule_uri),
872
- )
873
-
874
- @staticmethod
875
- def _diagnostics_to_lsp_diagnostics(
876
- diagnostics: t.List[AnnotatedRuleViolation],
877
- ) -> t.List[types.Diagnostic]:
878
- """
879
- Converts a list of AnnotatedRuleViolations to a list of LSP diagnostics. It will remove duplicates based on the message and range.
880
- """
881
- lsp_diagnostics = {}
882
- for diagnostic in diagnostics:
883
- lsp_diagnostic = SQLMeshLanguageServer._diagnostic_to_lsp_diagnostic(diagnostic)
884
- if lsp_diagnostic is not None:
885
- # Create a unique key combining message and range
886
- diagnostic_key = (
887
- lsp_diagnostic.message,
888
- lsp_diagnostic.range.start.line,
889
- lsp_diagnostic.range.start.character,
890
- lsp_diagnostic.range.end.line,
891
- lsp_diagnostic.range.end.character,
892
- )
893
- if diagnostic_key not in lsp_diagnostics:
894
- lsp_diagnostics[diagnostic_key] = lsp_diagnostic
895
- return list(lsp_diagnostics.values())
896
-
897
872
  @staticmethod
898
873
  def _uri_to_path(uri: str) -> Path:
899
874
  """Convert a URI to a path."""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sqlmesh
3
- Version: 0.196.4.dev2
3
+ Version: 0.196.4.dev3
4
4
  Summary: Next-generation data transformation framework
5
5
  Author-email: "TobikoData Inc." <engineering@tobikodata.com>
6
6
  License: Apache License
@@ -1,5 +1,5 @@
1
1
  sqlmesh/__init__.py,sha256=QjwaamJIdW7voXoS880yAx7tHm-Im4_mqGA-XJgafos,7631
2
- sqlmesh/_version.py,sha256=hkmHuuGvg0szEqtQQOR7Utu7hkmn5d3NsxaeLGxswP4,528
2
+ sqlmesh/_version.py,sha256=qpC7oSM5ytmbweRolzwz-C_TfdZEg-XTlrkpntxGzVw,528
3
3
  sqlmesh/magics.py,sha256=nMfwSW5rIkdnyO9MXYm9u24hNl6dqgAWybC-MnRcNnE,41451
4
4
  sqlmesh/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  sqlmesh/cicd/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -76,11 +76,11 @@ sqlmesh/core/engine_adapter/snowflake.py,sha256=IEEzepxNpfqBIMe4ziz2k8fjOcJPeQPZ
76
76
  sqlmesh/core/engine_adapter/spark.py,sha256=sYkVOPS0X43UPbI0z7Hh_EpKlI36qkOcr4NNFOTQlLs,21045
77
77
  sqlmesh/core/engine_adapter/trino.py,sha256=7WdLFlT0AyD5NF0EDP7GqX0SHF8sTm7cafBZxk84cmY,15798
78
78
  sqlmesh/core/linter/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
79
- sqlmesh/core/linter/definition.py,sha256=Rjqvto7VvVEnMXXOH4q3Jol1HnPe6I6BCHK1sEJm50I,5430
79
+ sqlmesh/core/linter/definition.py,sha256=pXDxl8TxTGNuVc1B5ywYmaH7dDjsoMRvCtLCK_co-ek,5567
80
80
  sqlmesh/core/linter/helpers.py,sha256=VF4hsdzGZ8srpbtCjdRN_Hd8S_er5KTAaLXLde27Yxo,4032
81
- sqlmesh/core/linter/rule.py,sha256=iCmFUw6Qx7GuUwLKIpHrHdq3kgtgm5JC2t9VFtMY3BQ,3180
81
+ sqlmesh/core/linter/rule.py,sha256=FlsP0PN4dmke7sJ2oD8ZZo3tWw8i87Q7CvbdNOOy3N8,3648
82
82
  sqlmesh/core/linter/rules/__init__.py,sha256=gevzfb67vFqckTCoVAe_TBGf6hQ-YtE1_YuGuXyh1L0,77
83
- sqlmesh/core/linter/rules/builtin.py,sha256=EHTd4sgHT6oT93onK7t5pLmv2KgzZ81twkTnOrMi9tI,2681
83
+ sqlmesh/core/linter/rules/builtin.py,sha256=51pv76heU6dlTHBMvL3L1x1WXzbCAsFBJGRQ8zjk-OU,3452
84
84
  sqlmesh/core/metric/__init__.py,sha256=H1HmoD5IwN4YWe9iJXyueLYNmTQFZwok5nSWNJcZIBQ,237
85
85
  sqlmesh/core/metric/definition.py,sha256=Yd5aVgsZCDPJ43aGP7WqtzZOuuSUtB8uJGVA6Jw9x9M,7201
86
86
  sqlmesh/core/metric/rewriter.py,sha256=GiSTHfn2kinqCfNPYgZPRk93JFLzVaaejHtHDQ0yXZI,7326
@@ -167,12 +167,12 @@ sqlmesh/integrations/github/cicd/config.py,sha256=tRhMZaLf1p6AWXvi67n85Q-lptJNGt
167
167
  sqlmesh/integrations/github/cicd/controller.py,sha256=QCs51Ag52Eu-2C5B2ivJ3Jgh7yThKj0eBqILGCHqizk,44436
168
168
  sqlmesh/lsp/api.py,sha256=_lA_buSPZFIoLJuINbS53LbNOOaHp3orb0uFTE3aCqI,2328
169
169
  sqlmesh/lsp/completions.py,sha256=Nt1XpFL_-QAIRM8BBBC6Ia6YG0hMZriiNJra7nGfD4Q,6676
170
- sqlmesh/lsp/context.py,sha256=QGbNL0sifxzVJ7T1U5oWcJ5FXrOrLrVKt1jtH1qM_50,6099
170
+ sqlmesh/lsp/context.py,sha256=2aD_lH-GqAwCjTFHfCavH2fZz2T4IXQZVS7LDMAa2X4,12815
171
171
  sqlmesh/lsp/custom.py,sha256=IJ70li8d5RbOFDrjHfsI2UNOiOp-WB22lrgpdJ7lVSg,2942
172
172
  sqlmesh/lsp/description.py,sha256=PjguwyVw5YeYSgT0JMhkf5U1Jry-sDPLvQ2caIR9JPQ,856
173
173
  sqlmesh/lsp/helpers.py,sha256=EFc1u3-b7kSv5-tNwmKUDxId72RCLDBnN2lLTgRSzzQ,1020
174
174
  sqlmesh/lsp/hints.py,sha256=j-blccBUil94yRoDjWfkSM0HqMmsKD6hP2TaWdWWVk4,3734
175
- sqlmesh/lsp/main.py,sha256=jty883u2BDAYBcDr1Za_2imd9MI9yJObSHaS9BNye_4,39553
175
+ sqlmesh/lsp/main.py,sha256=TRuegZaC04cPDThtmz_zL6YqBpQz342brv1luIbDTZ8,38186
176
176
  sqlmesh/lsp/reference.py,sha256=NyfpK12TouDuy5-G7KOhvifkJItMfrakKwnMoU6SiVk,32088
177
177
  sqlmesh/lsp/rename.py,sha256=399v1vyVRHHxvbCHVcuS4Pl8K2N-Z60JdZ6e1znOI4s,4397
178
178
  sqlmesh/lsp/uri.py,sha256=mvSLbZGmMTHPpliThOtVWiFcHnfJzp1w39q9l-xD2SI,802
@@ -283,7 +283,7 @@ sqlmesh/utils/pydantic.py,sha256=I898jAFqa3qU6lG2uPpRebVFncOUo8ZrLWM_R3K3DHU,116
283
283
  sqlmesh/utils/rich.py,sha256=BpB47G0-JcU41LkGkeGKroexj4NOV5fox4-GOIXPgIc,3545
284
284
  sqlmesh/utils/windows.py,sha256=r7Yin4WEwbvH7sKA3hOJtRsclmscNuBeCklCfVPvtQs,611
285
285
  sqlmesh/utils/yaml.py,sha256=hvo5lmybYLcIx4p6CQwufS8X4MbwS60lEBnCmYJCXmU,2336
286
- sqlmesh-0.196.4.dev2.dist-info/licenses/LICENSE,sha256=OlMefUjgWJdULtf84BLW0AZZcY8DwdgQqb_1j2862j8,11346
286
+ sqlmesh-0.196.4.dev3.dist-info/licenses/LICENSE,sha256=OlMefUjgWJdULtf84BLW0AZZcY8DwdgQqb_1j2862j8,11346
287
287
  web/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
288
288
  web/client/dist/index.html,sha256=drXwzSCEVDTMfaIwzJYjnT8Xk4c-Y4wNJz-CflUa_vY,5472
289
289
  web/client/dist/assets/Audits-DrNQaTQA.js,sha256=E8JF632bsRUm6LGtgXlyHrJOYQe5VW2CgRZPaZNKvgg,1041
@@ -401,8 +401,8 @@ web/server/api/endpoints/models.py,sha256=ud-lRwriyI_OYg9tZchrBgeiXELiRTLNEodraf
401
401
  web/server/api/endpoints/modules.py,sha256=8hqqgonGay_mJmpCw0IdbjsPhWlQH2VLdKAqha-myac,468
402
402
  web/server/api/endpoints/plan.py,sha256=OYuQ_4dgbhG9ibTcX1a8mvYgH3ANxw9Fhbb4wg6QWqc,9222
403
403
  web/server/api/endpoints/table_diff.py,sha256=SCy3-pr5x6bEEiOaZGCDbiHQhpgxwmnz3Acqa2Ie6jI,2090
404
- sqlmesh-0.196.4.dev2.dist-info/METADATA,sha256=mEcqUtAPgGpuE7uFoysGK1WUf6AtNhOe3cxoTsYOb3o,26527
405
- sqlmesh-0.196.4.dev2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
406
- sqlmesh-0.196.4.dev2.dist-info/entry_points.txt,sha256=pIYKtg-u-uO7BK_Y0qrdmfyj0bYrcMc3Xiqr5WE3VFk,121
407
- sqlmesh-0.196.4.dev2.dist-info/top_level.txt,sha256=bspjo5vjELQkuN0qKuTFIbsrUt3Zeo8D2mlKeHG1LdE,12
408
- sqlmesh-0.196.4.dev2.dist-info/RECORD,,
404
+ sqlmesh-0.196.4.dev3.dist-info/METADATA,sha256=_UapKkAgpnTTyUueOzzOCZW_7P1Zip9IxV97CUrQyoo,26527
405
+ sqlmesh-0.196.4.dev3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
406
+ sqlmesh-0.196.4.dev3.dist-info/entry_points.txt,sha256=pIYKtg-u-uO7BK_Y0qrdmfyj0bYrcMc3Xiqr5WE3VFk,121
407
+ sqlmesh-0.196.4.dev3.dist-info/top_level.txt,sha256=bspjo5vjELQkuN0qKuTFIbsrUt3Zeo8D2mlKeHG1LdE,12
408
+ sqlmesh-0.196.4.dev3.dist-info/RECORD,,