omnata-plugin-runtime 0.10.13a266__py3-none-any.whl → 0.10.14__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.
@@ -563,26 +563,137 @@ class SnowflakeViewParts(BaseModel):
563
563
  # on the SnowflakeViewColumn object.
564
564
  # Until this generate function is called with the raw stream names, we don't know which streams the user has actually selected, nor which
565
565
  # fields are actually available (some may be dropped due to something like an unsupported formula).
566
- # So now there's a pruning process where we remove columns that reference fields that are not available.
567
566
  # First, explicitly check for circular references between tables, erroring if they are found.
568
- circular_refs = {}
567
+ # This must be done before any pruning happens.
568
+ # We need to check both by stream name and by join stream alias
569
+
570
+ # Build mappings for stream names and aliases
571
+ stream_to_aliases = {} # stream_name -> set of aliases
572
+ alias_to_stream = {} # alias -> stream_name
573
+
574
+ # Initialize with the main stream
575
+ stream_to_aliases[main_stream_view_part.stream_name] = {main_stream_view_part.stream_name}
576
+ alias_to_stream[main_stream_view_part.stream_name] = main_stream_view_part.stream_name
577
+
578
+ # Process all joins to build the mappings
579
+ for part in [main_stream_view_part] + joined_parts:
580
+ # Make sure the part's stream name is in the mappings
581
+ if part.stream_name not in stream_to_aliases:
582
+ stream_to_aliases[part.stream_name] = {part.stream_name}
583
+ alias_to_stream[part.stream_name] = part.stream_name
584
+
585
+ for join in part.joins:
586
+ # Add the join stream alias to the set of aliases for that stream
587
+ if join.join_stream_name not in stream_to_aliases:
588
+ stream_to_aliases[join.join_stream_name] = set()
589
+ stream_to_aliases[join.join_stream_name].add(join.join_stream_alias)
590
+
591
+ # Map the alias back to its stream
592
+ alias_to_stream[join.join_stream_alias] = join.join_stream_name
593
+
594
+ # Also add the left alias mapping
595
+ if join.left_alias not in alias_to_stream:
596
+ # Try to find which stream this alias belongs to
597
+ for other_part in [main_stream_view_part] + joined_parts:
598
+ if other_part.stream_name == join.left_alias:
599
+ if other_part.stream_name not in stream_to_aliases:
600
+ stream_to_aliases[other_part.stream_name] = set()
601
+ stream_to_aliases[other_part.stream_name].add(join.left_alias)
602
+ alias_to_stream[join.left_alias] = other_part.stream_name
603
+ break
604
+
605
+ # Build a graph of references between streams and their aliases
606
+ circular_refs = {} # (source, target) -> [(column_name, ref_fields)]
607
+
608
+ # First, add references based on column dependencies
569
609
  for part in [main_stream_view_part] + joined_parts:
570
610
  for column in part.columns:
571
611
  if column.referenced_columns:
572
612
  for ref_stream_name, ref_fields in column.referenced_columns.items():
573
- # Record this reference
574
- if (part.stream_name, ref_stream_name) not in circular_refs:
575
- circular_refs[(part.stream_name, ref_stream_name)] = []
576
- circular_refs[(part.stream_name, ref_stream_name)].append((column.original_name, ref_fields))
613
+ # Record this reference by stream name
614
+ key = (part.stream_name, ref_stream_name)
615
+ if key not in circular_refs:
616
+ circular_refs[key] = []
617
+ circular_refs[key].append((column.original_name, ref_fields))
618
+
619
+ # Also record references by aliases
620
+ # For each alias of the source stream
621
+ for source_alias in stream_to_aliases.get(part.stream_name, {part.stream_name}):
622
+ # For each alias of the target stream
623
+ for target_alias in stream_to_aliases.get(ref_stream_name, {ref_stream_name}):
624
+ # Create a reference from source alias to target alias
625
+ alias_key = (source_alias, target_alias)
626
+ if alias_key not in circular_refs:
627
+ circular_refs[alias_key] = []
628
+ circular_refs[alias_key].append((column.original_name, ref_fields))
629
+ # Also add references from the joins
630
+ for part in [main_stream_view_part] + joined_parts:
631
+ for join in part.joins:
632
+ # Add a reference from the join stream to the left stream
633
+ key = (join.join_stream_name, part.stream_name)
634
+ if key not in circular_refs:
635
+ circular_refs[key] = []
636
+ circular_refs[key].append(("join", [join.join_stream_column]))
637
+
638
+ # Also add references by aliases
639
+ alias_key = (join.join_stream_alias, join.left_alias)
640
+ if alias_key not in circular_refs:
641
+ circular_refs[alias_key] = []
642
+ circular_refs[alias_key].append(("join", [join.join_stream_column]))
643
+
644
+ # Add references from the left alias to the join stream alias
645
+ reverse_key = (join.left_alias, join.join_stream_alias)
646
+ if reverse_key not in circular_refs:
647
+ circular_refs[reverse_key] = []
648
+ circular_refs[reverse_key].append(("join_reverse", [join.left_column]))
577
649
 
578
- # Check for circular references
579
- for (stream1, stream2), refs1 in circular_refs.items():
580
- if (stream2, stream1) in circular_refs:
581
- # Found a potential circular reference between stream1 and stream2
582
- refs2 = circular_refs[(stream2, stream1)]
583
- raise ValueError(f"""Cyclic dependency detected: Circular reference between {stream1} and {stream2}.
584
- {stream1} -> {stream2}: {refs1}
585
- {stream2} -> {stream1}: {refs2}""")
650
+ # Check for circular references by stream name and by aliases
651
+ for (source, target), refs1 in circular_refs.items():
652
+ source_stream = alias_to_stream.get(source, source)
653
+ target_stream = alias_to_stream.get(target, target)
654
+
655
+ # Skip references that are just join relationships
656
+ # These are not considered circular references
657
+ if all(ref_type == "join" or ref_type == "join_reverse" for ref_type, _ in refs1):
658
+ continue
659
+
660
+ # Check for direct circular references
661
+ reverse_key = (target, source)
662
+ if reverse_key in circular_refs:
663
+ refs2 = circular_refs[reverse_key]
664
+
665
+ # Skip if both references are just join relationships
666
+ if all(ref_type == "join" or ref_type == "join_reverse" for ref_type, _ in refs2):
667
+ continue
668
+
669
+ raise ValueError(f"""Cyclic dependency detected: Circular reference between {source} and {target}.
670
+ {source} -> {target}: {refs1}
671
+ {target} -> {source}: {refs2}""")
672
+
673
+ # Check for circular references through aliases
674
+ for (other_source, other_target), refs2 in circular_refs.items():
675
+ if source == other_source or target == other_target:
676
+ continue # Skip self-comparisons
677
+
678
+ # Skip references that are just join relationships
679
+ if all(ref_type == "join" or ref_type == "join_reverse" for ref_type, _ in refs2):
680
+ continue
681
+
682
+ other_source_stream = alias_to_stream.get(other_source, other_source)
683
+ other_target_stream = alias_to_stream.get(other_target, other_target)
684
+
685
+ # Check if this is a circular reference through aliases
686
+ if target_stream == other_source_stream and source_stream == other_target_stream:
687
+ raise ValueError(f"""Cyclic dependency detected: Circular reference through aliases.
688
+ {source} ({source_stream}) -> {target} ({target_stream}): {refs1}
689
+ {other_source} ({other_source_stream}) -> {other_target} ({other_target_stream}): {refs2}""")
690
+
691
+ # If we get here, no circular references were found
692
+ logger.debug("No circular references found")
693
+
694
+ # Now proceed with the actual pruning process
695
+ # First, removing unavailable columns from other streams
696
+ # then, we can do a final pass and remove columns that reference fields that are not available in the current stream
586
697
 
587
698
  # Now proceed with the actual pruning process
588
699
  # First, removing unavailable columns from other streams
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: omnata-plugin-runtime
3
- Version: 0.10.13a266
3
+ Version: 0.10.14
4
4
  Summary: Classes and common runtime components for building and running Omnata Plugins
5
5
  Author: James Weakley
6
6
  Author-email: james.weakley@omnata.com
@@ -2,12 +2,12 @@ omnata_plugin_runtime/__init__.py,sha256=MS9d1whnfT_B3-ThqZ7l63QeC_8OEKTuaYV5wTw
2
2
  omnata_plugin_runtime/api.py,sha256=baGraSMiD4Yvi3ZWrEv_TKh8Ktd1U8riBdOpe9j0Puw,8202
3
3
  omnata_plugin_runtime/configuration.py,sha256=0rfIGv8rCu8OwL7m-VOXIBjd05iyaBWRdt2h9o6scwo,46754
4
4
  omnata_plugin_runtime/forms.py,sha256=9YHJ_T17lT-rwyDaUg_0yj_YMPda4DRCw_wrvf8hE0E,19964
5
- omnata_plugin_runtime/json_schema.py,sha256=us4T3OgpjAyfsmew4pD777PyY0PR9Qhu3v89YqcYVsw,39125
5
+ omnata_plugin_runtime/json_schema.py,sha256=GuXmUydF44xQTxKL6PF0G_gsqevl_VI_p-raG8S2ETo,45463
6
6
  omnata_plugin_runtime/logging.py,sha256=WBuZt8lF9E5oFWM4KYQbE8dDJ_HctJ1pN3BHwU6rcd0,4461
7
7
  omnata_plugin_runtime/omnata_plugin.py,sha256=M0b6f9lKKEoEI0zf-ZwZcIPKPQTmHTIMhvcrBc94Mhg,133278
8
8
  omnata_plugin_runtime/plugin_entrypoints.py,sha256=iqGl8_nEEnPGKg3Aem4YLSQ6d5xS3ju5gq8MJbx6sCA,31968
9
9
  omnata_plugin_runtime/rate_limiting.py,sha256=qpr5esU4Ks8hMzuMpSR3gLFdor2ZUXYWCjmsQH_K6lQ,25882
10
- omnata_plugin_runtime-0.10.13a266.dist-info/LICENSE,sha256=rGaMQG3R3F5-JGDp_-rlMKpDIkg5n0SI4kctTk8eZSI,56
11
- omnata_plugin_runtime-0.10.13a266.dist-info/METADATA,sha256=snbSNIEHMlkO9M-uKmUeIfzcW-MSXYk3saWTlYocQfs,2212
12
- omnata_plugin_runtime-0.10.13a266.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
13
- omnata_plugin_runtime-0.10.13a266.dist-info/RECORD,,
10
+ omnata_plugin_runtime-0.10.14.dist-info/LICENSE,sha256=rGaMQG3R3F5-JGDp_-rlMKpDIkg5n0SI4kctTk8eZSI,56
11
+ omnata_plugin_runtime-0.10.14.dist-info/METADATA,sha256=CDUnPb2-4jvcHOugd9ZOjVJYmUtDby5INIvwhf39YCA,2208
12
+ omnata_plugin_runtime-0.10.14.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
13
+ omnata_plugin_runtime-0.10.14.dist-info/RECORD,,