@@ -162,6 +162,13 @@ def _extract_time_travel_from_options(options: dict) -> dict:
162162 - Automatically sets time_travel_mode to 'at'
163163 - Cannot be used with time_travel_mode='before' (raises error)
164164 - Cannot be mixed with regular 'timestamp' option (raises error)
165+
166+ Special handling for 'SNAPSHOT-ID' / 'SNAPSHOT_ID' (Spark Iceberg
167+ compatibility) — both aliases map to the internal ``version`` time
168+ travel parameter:
169+ - Automatically set time_travel_mode to 'at'
170+ (Iceberg snapshot ids only support ``AT(VERSION => N)``, not ``BEFORE``)
171+ - Cannot be used with time_travel_mode='before' (raises error)
165172 """
166173 result = {}
167174 excluded_keys = set ()
@@ -183,6 +190,35 @@ def _extract_time_travel_from_options(options: dict) -> dict:
183190 result ["timestamp" ] = options ["AS-OF-TIMESTAMP" ]
184191 excluded_keys .add ("TIMESTAMP" )
185192
193+ # Handle Iceberg snapshot id (Spark ``snapshot-id`` / ``snapshot_id``).
194+ # Auto-sets mode='at' since ``AT(VERSION => N)`` is the only valid form.
195+ snapshot_id_value = options .get ("SNAPSHOT-ID" )
196+ snapshot_id_source = "snapshot-id"
197+ if snapshot_id_value is None :
198+ snapshot_id_value = options .get ("SNAPSHOT_ID" )
199+ snapshot_id_source = "snapshot_id"
200+ if snapshot_id_value is not None :
201+ if (
202+ "TIME_TRAVEL_MODE" in options
203+ and options ["TIME_TRAVEL_MODE" ].lower () == "before"
204+ ):
205+ raise ValueError (
206+ f"Cannot use '{ snapshot_id_source } ' option with "
207+ "time_travel_mode='before'. Iceberg snapshot id time travel "
208+ "only supports time_travel_mode='at'."
209+ )
210+ # Coerce string snapshot ids (Spark accepts both string and long
211+ # literals via .option(); we normalize to int so the SQL emits an
212+ # unquoted long).
213+ try :
214+ result ["version" ] = int (snapshot_id_value )
215+ except (TypeError , ValueError ):
216+ raise ValueError (
217+ f"'{ snapshot_id_source } ' must be a 64-bit integer Iceberg "
218+ f"snapshot id, got { snapshot_id_value !r} ."
219+ )
220+ result ["time_travel_mode" ] = "at"
221+
186222 for option_key , param_name in _TIME_TRAVEL_OPTIONS_PARAMS_MAP .items ():
187223 if option_key in options and option_key not in excluded_keys :
188224 result [param_name ] = options [option_key ]
@@ -549,6 +585,7 @@ def table(
549585 timestamp : Optional [Union [str , datetime ]] = None ,
550586 timestamp_type : Optional [Union [str , TimestampTimeZone ]] = None ,
551587 stream : Optional [str ] = None ,
588+ ** kwargs ,
552589 ) -> Table :
553590 """Returns a Table that points to the specified table.
554591
@@ -605,6 +642,15 @@ def table(
605642 ... .option("offset", -60) # This will be IGNORED
606643 ... .table("my_table", time_travel_mode="at", offset=-3600)) # Only this is used
607644 """
645+ # ``version`` (Iceberg snapshot id) is intentionally not in the public
646+ # signature — it's consumed by Snowpark Connect and may be removed
647+ # once a first-class API lands. Accept it through **kwargs so direct
648+ # callers can still pass it without us advertising it.
649+ version = kwargs .pop ("version" , None )
650+ if kwargs :
651+ raise TypeError (
652+ f"table() got unexpected keyword arguments: { sorted (kwargs )} "
653+ )
608654
609655 # AST.
610656 stmt = None
@@ -626,14 +672,22 @@ def table(
626672 if stream is not None :
627673 ast .stream .value = stream
628674
629- if time_travel_mode is not None :
675+ if time_travel_mode is not None or version is not None :
676+ # If version is provided without mode, default to 'at' (snapshot ids
677+ # only make sense with AT — symmetric with iceberg_tag handling).
678+ effective_mode = (
679+ time_travel_mode
680+ if time_travel_mode
681+ else ("at" if version is not None else None )
682+ )
630683 time_travel_params = {
631- "time_travel_mode" : time_travel_mode ,
684+ "time_travel_mode" : effective_mode ,
632685 "statement" : statement ,
633686 "offset" : offset ,
634687 "timestamp" : timestamp ,
635688 "timestamp_type" : timestamp_type ,
636689 "stream" : stream ,
690+ "version" : version ,
637691 }
638692 else :
639693 # if time_travel_mode is not provided, extract time travel config from options
0 commit comments