This is an automated email from the ASF dual-hosted git repository.

yihua pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/hudi-rs.git


The following commit(s) were added to refs/heads/main by this push:
     new 7cc171b4 refactor(python): name the result instant requested_time and 
document the remaining stub items (#939)
7cc171b4 is described below

commit 7cc171b467b4ec75f75287aa1aa3b99ebf70bf53
Author: Y Ethan Guo <[email protected]>
AuthorDate: Fri Oct 30 13:44:03 2026 -0700

    refactor(python): name the result instant requested_time and document the 
remaining stub items (#939)
    
    Adds docstrings to the 29 public items in `python/hudi/_internal.pyi` that 
had none: the `HudiReadOptions` constructor, builders and accessors, 
`HudiQueryType`, `HudiInstant`, `HudiTimeline`, and `HudiDataFusionDataSource`. 
Each statement was checked against the binding and the core it calls, for 
example that the incremental window bounds completion time on table version 8 
and later, and that the timeline getters read the active timeline only. The 
package and stub module docstrings li [...]
    
    `HudiWriteResult.instant_time` and `HudiCompactionResult.instant_time` 
become `requested_time`, matching the Rust `WriteResult` and `CompactionResult` 
field and pairing with `completion_time`; the README quick start and the upsert 
benchmark read the new name. Neither class has shipped in a release.
---
 README.md                        |   4 +-
 benchmark/upsert/bench.py        |   6 +-
 python/hudi/__init__.py          |  22 +++
 python/hudi/_internal.pyi        | 283 ++++++++++++++++++++++++++++++++++-----
 python/src/internal.rs           |  18 +--
 python/tests/test_table_write.py |  26 ++--
 6 files changed, 297 insertions(+), 62 deletions(-)

diff --git a/README.md b/README.md
index b4cd1fa6..c2414d14 100644
--- a/README.md
+++ b/README.md
@@ -452,7 +452,7 @@ groups.
 
 ```python
 result = table.upsert(batch)
-print(f"instant={result.instant_time} updates={result.num_updates} 
inserts={result.num_inserts}")
+print(f"requested_time={result.requested_time} updates={result.num_updates} 
inserts={result.num_inserts}")
 
 # Partial upsert (copy-on-write only): matched rows take only these columns 
from the input.
 table.upsert(batch, update_columns=["fare"])
@@ -463,7 +463,7 @@ table.upsert(batch, update_columns=["fare"])
 ```rust
 let result = table.upsert([batch]).await?;
 println!(
-    "instant={} updates={} inserts={}",
+    "requested_time={} updates={} inserts={}",
     result.requested_time.as_deref().unwrap_or("none"),
     result.num_updates,
     result.num_inserts
diff --git a/benchmark/upsert/bench.py b/benchmark/upsert/bench.py
index bb186362..1d945c9a 100755
--- a/benchmark/upsert/bench.py
+++ b/benchmark/upsert/bench.py
@@ -259,7 +259,7 @@ class HudiCase(Case):
     def _marker(r):
         # Time travel resolves requested instants; incremental bounds on table
         # version 9 are completion times.
-        return {"instant": r.instant_time, "completion": r.completion_time}
+        return {"instant": r.requested_time, "completion": r.completion_time}
 
     def upsert(self, batch):
         r = self.t.upsert(batch)
@@ -267,7 +267,7 @@ class HudiCase(Case):
         return {
             "num_updated": r.num_updates,
             "num_inserted": r.num_inserts,
-            "instant": r.instant_time,
+            "instant": r.requested_time,
         }
 
     def record_keys(self, keys):
@@ -283,7 +283,7 @@ class HudiCase(Case):
     def delete(self, keys):
         r = self.t.delete_keys(self.record_keys(keys))
         self.last = self._marker(r)
-        return {"num_deleted": r.num_deletes, "instant": r.instant_time}
+        return {"num_deleted": r.num_deletes, "instant": r.requested_time}
 
     def _read(self, opts=None):
         batches = self.t.read(opts)
diff --git a/python/hudi/__init__.py b/python/hudi/__init__.py
index 0f8dd4b8..a28570ee 100644
--- a/python/hudi/__init__.py
+++ b/python/hudi/__init__.py
@@ -15,6 +15,28 @@
 #  specific language governing permissions and limitations
 #  under the License.
 
+"""Apache Hudi for Python, backed by the native Rust implementation hudi-rs.
+
+Start with :class:`HudiTable`: ``HudiTable.create`` makes a table and 
``HudiTable(base_uri)``
+opens an existing one; both return a handle that reads, writes, and, on a 
merge-on-read table,
+compacts (:meth:`HudiTable.compact`, experimental).
+
+Resources:
+
+- Quick start: https://hudi.apache.org/docs/python-rust-quick-start-guide, and 
the shorter
+  README quick start at https://github.com/apache/hudi-rs#quick-start.
+- Python API reference: the docstrings in the bundled type stubs, 
``hudi/_internal.pyi``
+  (https://github.com/apache/hudi-rs/blob/main/python/hudi/_internal.pyi).
+- Rust API reference: https://docs.rs/hudi (also https://docs.rs/hudi-core and
+  https://docs.rs/hudi-datafusion).
+- Runnable Rust example:
+  
https://github.com/apache/hudi-rs/blob/main/crates/core/examples/table_writes.rs.
+- Reader semantics: 
https://github.com/apache/hudi-rs/blob/main/docs/reader-spec.md.
+  Writer design: 
https://github.com/apache/hudi-rs/blob/main/docs/writer-design.md.
+- Packages: https://pypi.org/project/hudi/ and https://crates.io/crates/hudi.
+  Source: https://github.com/apache/hudi-rs.
+- Hudi concepts (timeline, table types, query types): 
https://hudi.apache.org/docs/overview.
+"""
 
 from hudi._config import HudiPlanConfig, HudiReadConfig, HudiTableConfig
 from hudi._internal import (
diff --git a/python/hudi/_internal.pyi b/python/hudi/_internal.pyi
index 2ef6aab0..fbb314e5 100644
--- a/python/hudi/_internal.pyi
+++ b/python/hudi/_internal.pyi
@@ -14,6 +14,24 @@
 #  KIND, either express or implied.  See the License for the
 #  specific language governing permissions and limitations
 #  under the License.
+"""Type stubs and API reference for the ``hudi`` package.
+
+Resources:
+
+- Quick start: https://hudi.apache.org/docs/python-rust-quick-start-guide, and 
the shorter
+  README quick start at https://github.com/apache/hudi-rs#quick-start.
+- Python API reference: the docstrings in this file.
+- Rust API reference: https://docs.rs/hudi (also https://docs.rs/hudi-core and
+  https://docs.rs/hudi-datafusion).
+- Runnable Rust example:
+  
https://github.com/apache/hudi-rs/blob/main/crates/core/examples/table_writes.rs.
+- Reader semantics: 
https://github.com/apache/hudi-rs/blob/main/docs/reader-spec.md.
+  Writer design: 
https://github.com/apache/hudi-rs/blob/main/docs/writer-design.md.
+- Packages: https://pypi.org/project/hudi/ and https://crates.io/crates/hudi.
+  Source: https://github.com/apache/hudi-rs.
+- Hudi concepts (timeline, table types, query types): 
https://hudi.apache.org/docs/overview.
+"""
+
 from dataclasses import dataclass
 from typing import Any, ClassVar, Dict, List, Optional, Protocol, Tuple, Union
 
@@ -45,9 +63,13 @@ class HudiQueryType:
     Incremental: ClassVar["HudiQueryType"]
 
     @property
-    def name(self) -> str: ...
+    def name(self) -> str:
+        """The member name, ``"Snapshot"`` or ``"Incremental"``."""
+        ...
     @property
-    def value(self) -> str: ...
+    def value(self) -> str:
+        """The config value stored under ``hoodie.read.query.type``, 
``"snapshot"`` or ``"incremental"``."""
+        ...
 
 @dataclass(init=False)
 class HudiReadOptions:
@@ -76,28 +98,85 @@ class HudiReadOptions:
         filters: Optional[List[Tuple[str, str, str]]] = None,
         projection: Optional[List[str]] = None,
         hudi_options: Optional[Dict[str, str]] = None,
-    ): ...
+    ):
+        """
+        Initializes the HudiReadOptions.
+
+        Parameters:
+            filters (Optional[List[Tuple[str, str, str]]]): Column filters as 
``(field, op, value)``
+                tuples. Parsed and cardinality-validated immediately; an 
unrecognized operator
+                or empty ``IN`` / ``NOT IN`` value list raises 
``HudiCoreError``.
+            projection (Optional[List[str]]): Column names to read. If None, 
all columns are read.
+            hudi_options (Optional[Dict[str, str]]): Per-read Hudi configs 
(``hoodie.*``).
+        """
+        ...
 
     # Builders return a new HudiReadOptions for chaining.
-    def with_query_type(self, query_type: HudiQueryType) -> "HudiReadOptions": 
...
-    def with_as_of_timestamp(self, timestamp: str) -> "HudiReadOptions": ...
-    def with_start_timestamp(self, timestamp: str) -> "HudiReadOptions": ...
-    def with_end_timestamp(self, timestamp: str) -> "HudiReadOptions": ...
+    def with_query_type(self, query_type: HudiQueryType) -> "HudiReadOptions":
+        """Set the query type. Stored under ``hoodie.read.query.type``; 
defaults to snapshot when unset."""
+        ...
+    def with_as_of_timestamp(self, timestamp: str) -> "HudiReadOptions":
+        """
+        Set the timestamp for a snapshot (time-travel) read. Stored under
+        ``hoodie.read.as.of.timestamp``; a snapshot read without it reads the 
latest commit.
+
+        The value is parsed when the read runs, not here. Accepted formats are 
the Hudi
+        timeline format (``yyyyMMddHHmmssSSS`` or ``yyyyMMddHHmmss``), epoch 
time in seconds,
+        milliseconds, microseconds or nanoseconds, and RFC 3339 
(``2024-03-15T14:25:30Z``).
+        Epoch and RFC 3339 values are converted to the table's timeline 
timezone
+        (``hoodie.table.timeline.timezone``).
+        """
+        ...
+    def with_start_timestamp(self, timestamp: str) -> "HudiReadOptions":
+        """
+        Set the exclusive start of an incremental read window. Stored under
+        ``hoodie.read.start.timestamp``; when unset, the window has no lower 
bound.
+
+        On table version 8 and later this bounds each commit's completion 
time, so pass
+        :attr:`HudiWriteResult.completion_time` rather than its 
``requested_time`` to read
+        the commits after a given write. On earlier table versions it bounds 
the requested
+        time. Accepts the same formats as :meth:`with_as_of_timestamp`.
+        """
+        ...
+    def with_end_timestamp(self, timestamp: str) -> "HudiReadOptions":
+        """
+        Set the inclusive end of an incremental read window. Stored under
+        ``hoodie.read.end.timestamp``; when unset, the window covers 
everything committed
+        so far.
+
+        Bounds the same timestamp as :meth:`with_start_timestamp` and accepts 
the same
+        formats as :meth:`with_as_of_timestamp`.
+        """
+        ...
     def with_batch_size(self, size: int) -> "HudiReadOptions":
         """Target rows per batch for streaming reads. Raises ``HudiCoreError`` 
if ``size == 0``."""
         ...
     def with_filters(self, filters: List[Tuple[str, str, str]]) -> 
"HudiReadOptions":
         """Set column filters as ``(field, op, value)`` tuples. Parses and 
cardinality-validates immediately; an unrecognized operator or empty ``IN`` / 
``NOT IN`` value list raises ``HudiCoreError``."""
         ...
-    def with_projection(self, columns: List[str]) -> "HudiReadOptions": ...
-    def with_hudi_option(self, key: str, value: str) -> "HudiReadOptions": ...
-    def with_hudi_options(self, opts: Dict[str, str]) -> "HudiReadOptions": ...
+    def with_projection(self, columns: List[str]) -> "HudiReadOptions":
+        """Set the column names to read, replacing any previous projection."""
+        ...
+    def with_hudi_option(self, key: str, value: str) -> "HudiReadOptions":
+        """Set one Hudi config (``hoodie.*``) for this read only, replacing 
any existing value for ``key``."""
+        ...
+    def with_hudi_options(self, opts: Dict[str, str]) -> "HudiReadOptions":
+        """Set several Hudi configs (``hoodie.*``) for this read only. Keys 
already set and not in ``opts`` are kept."""
+        ...
 
     # Typed accessors read from hudi_options.
-    def query_type(self) -> HudiQueryType: ...
-    def as_of_timestamp(self) -> Optional[str]: ...
-    def start_timestamp(self) -> Optional[str]: ...
-    def end_timestamp(self) -> Optional[str]: ...
+    def query_type(self) -> HudiQueryType:
+        """The query type, ``HudiQueryType.Snapshot`` if unset. Raises 
``HudiCoreError`` if the stored value is not a recognized query type."""
+        ...
+    def as_of_timestamp(self) -> Optional[str]:
+        """The snapshot (time-travel) timestamp as stored, or ``None`` if 
unset."""
+        ...
+    def start_timestamp(self) -> Optional[str]:
+        """The exclusive start of the incremental window as stored, or 
``None`` if unset."""
+        ...
+    def end_timestamp(self) -> Optional[str]:
+        """The inclusive end of the incremental window as stored, or ``None`` 
if unset."""
+        ...
     def batch_size(self) -> Optional[int]:
         """Target batch size for streaming reads, or ``None`` if unset. Raises 
``HudiCoreError`` if the stored value is malformed."""
         ...
@@ -256,14 +335,49 @@ class HudiFileSlice:
 
 @dataclass(init=False)
 class HudiInstant:
+    """
+    An action on a table's timeline at one point in time, as returned by 
:class:`HudiTimeline`.
+    """
+
     @property
-    def timestamp(self) -> str: ...
+    def timestamp(self) -> str:
+        """
+        The instant time, i.e. when the action was requested, in the Hudi 
timeline format
+        (``yyyyMMddHHmmssSSS`` or ``yyyyMMddHHmmss``).
+
+        Returns:
+            str: The requested timestamp of the instant.
+        """
+        ...
     @property
-    def action(self) -> str: ...
+    def action(self) -> str:
+        """
+        The timeline action of the instant.
+
+        Returns:
+            str: ``"commit"``, ``"deltacommit"`` or ``"replacecommit"``.
+        """
+        ...
     @property
-    def state(self) -> str: ...
+    def state(self) -> str:
+        """
+        The state of the instant.
+
+        Returns:
+            str: ``"requested"``, ``"inflight"``, or an empty string for a 
completed instant.
+                Instants returned by :class:`HudiTimeline` are all completed.
+        """
+        ...
     @property
-    def epoch_mills(self) -> int: ...
+    def epoch_mills(self) -> int:
+        """
+        The instant time (:attr:`timestamp`) as milliseconds since the Unix 
epoch, reading it in
+        the table's timeline timezone (``hoodie.table.timeline.timezone``, UTC 
when unset).
+
+        Returns:
+            int: Milliseconds since the Unix epoch.
+        """
+        ...
 
 @dataclass(init=False)
 class HudiTable:
@@ -404,6 +518,9 @@ class HudiTable:
         - Snapshot: slices visible at ``options.as_of_timestamp`` (defaults to 
the
           latest commit). ``options.filters`` drive partition pruning; 
file-level
           stats pruning applies only for COW tables or MOR read-optimized mode.
+          With the record-level index, ``=`` or ``IN`` filters on the record 
key
+          keep only the file groups the index names (latest snapshot only, not 
in
+          read-optimized mode).
           When footer stats are loaded for pruning, exact ``num_records``,
           ``byte_size``, and column stats are attached to the returned slices.
         - Incremental: slices changed in ``(options.start_timestamp,
@@ -623,8 +740,8 @@ class HudiTable:
         ...
     def compact(self) -> "HudiCompactionResult":
         """
-        Compact a merge-on-read table: every file group whose latest file slice
-        carries log files gets a new base file holding its merged rows, under 
one
+        Compact a merge-on-read table (experimental): every file group whose 
latest
+        file slice carries log files gets a new base file holding its merged 
rows, under one
         compaction instant that completes as a commit. Rows keep their commit 
time,
         so incremental reads see no new rows from a compaction.
 
@@ -662,20 +779,20 @@ class HudiWriteResult:
     Outcome of a write on :class:`HudiTable`.
 
     Attributes:
-        instant_time (Optional[str]): Instant time of the completed commit, or 
``None``
+        requested_time (Optional[str]): Requested time of the completed 
commit, or ``None``
             when no commit was made.
         completion_time (Optional[str]): When the commit completed, or 
``None`` when no
             commit was made or the table's timeline records no completion 
times (table
             version 6). When set, incremental reads compare their start bound 
against
             completion times, so ``with_start_timestamp(completion_time)`` 
returns the
-            commits after this one while passing ``instant_time`` would 
include this commit.
+            commits after this one while passing ``requested_time`` would 
include this commit.
         num_writes (int): Rows written to data files.
         num_updates (int): Input rows that replaced existing records.
         num_inserts (int): Input rows that were new records.
         num_deletes (int): Records deleted.
     """
 
-    instant_time: Optional[str]
+    requested_time: Optional[str]
     completion_time: Optional[str]
     num_writes: int
     num_updates: int
@@ -688,7 +805,7 @@ class HudiCompactionResult:
     Outcome of :meth:`HudiTable.compact`.
 
     Attributes:
-        instant_time (Optional[str]): Instant time of the completed compaction 
commit,
+        requested_time (Optional[str]): Requested time of the completed 
compaction commit,
             or ``None`` when no file group had log files and nothing was 
written.
         completion_time (Optional[str]): When the commit completed, or 
``None`` when
             nothing was written or the timeline records no completion times.
@@ -697,7 +814,7 @@ class HudiCompactionResult:
         num_writes (int): Rows written to the new base files.
     """
 
-    instant_time: Optional[str]
+    requested_time: Optional[str]
     completion_time: Optional[str]
     num_file_groups: int
     num_log_files: int
@@ -705,16 +822,105 @@ class HudiCompactionResult:
 
 @dataclass(init=False)
 class HudiTimeline:
-    def get_completed_commits(self, desc: bool = False) -> List[HudiInstant]: 
...
-    def get_completed_deltacommits(self, desc: bool = False) -> 
List[HudiInstant]: ...
-    def get_completed_replacecommits(self, desc: bool = False) -> 
List[HudiInstant]: ...
-    def get_completed_clustering_commits(
-        self, desc: bool = False
-    ) -> List[HudiInstant]: ...
-    def get_instant_metadata_in_json(self, instant: HudiInstant) -> str: ...
-    def get_latest_commit_timestamp(self) -> str: ...
-    def get_latest_avro_schema(self) -> str: ...
-    def get_latest_schema(self) -> "pyarrow.Schema": ...
+    """
+    The timeline of a Hudi table, obtained from :meth:`HudiTable.get_timeline`.
+
+    Only the active timeline is read; archived instants are not returned.
+    """
+
+    def get_completed_commits(self, desc: bool = False) -> List[HudiInstant]:
+        """
+        Returns the completed ``commit`` instants. On a MOR table, compactions 
complete as commits.
+
+        Parameters:
+            desc (bool): Sort by instant time in descending order instead of 
ascending.
+
+        Returns:
+            List[HudiInstant]: The completed commit instants.
+        """
+        ...
+    def get_completed_deltacommits(self, desc: bool = False) -> 
List[HudiInstant]:
+        """
+        Returns the completed ``deltacommit`` instants. Empty for a COW table.
+
+        Parameters:
+            desc (bool): Sort by instant time in descending order instead of 
ascending.
+
+        Returns:
+            List[HudiInstant]: The completed delta commit instants.
+        """
+        ...
+    def get_completed_replacecommits(self, desc: bool = False) -> 
List[HudiInstant]:
+        """
+        Returns the completed ``replacecommit`` instants, such as overwrites 
and clustering.
+
+        Parameters:
+            desc (bool): Sort by instant time in descending order instead of 
ascending.
+
+        Returns:
+            List[HudiInstant]: The completed replace commit instants.
+        """
+        ...
+    def get_completed_clustering_commits(self, desc: bool = False) -> 
List[HudiInstant]:
+        """
+        Returns the completed ``replacecommit`` instants whose commit metadata 
has
+        ``operationType`` ``cluster``.
+
+        Reads the commit metadata of every completed replace commit, and raises
+        ``HudiCoreError`` if one of them has no operation type.
+
+        Parameters:
+            desc (bool): Sort by instant time in descending order instead of 
ascending.
+
+        Returns:
+            List[HudiInstant]: The completed clustering instants.
+        """
+        ...
+    def get_instant_metadata_in_json(self, instant: HudiInstant) -> str:
+        """
+        Returns the commit metadata stored in the instant's timeline file, as 
JSON.
+
+        Parameters:
+            instant (HudiInstant): A completed instant from this timeline.
+
+        Returns:
+            str: The commit metadata as a JSON string.
+        """
+        ...
+    def get_latest_commit_timestamp(self) -> str:
+        """
+        Returns the instant time of the latest completed commit, delta commit, 
or replace
+        commit. Raises ``HudiCoreError`` if the table has no completed commit.
+
+        Returns:
+            str: The instant time in the Hudi timeline format.
+        """
+        ...
+    def get_latest_avro_schema(self) -> str:
+        """
+        Returns the Avro schema recorded in the latest completed commit's 
metadata.
+
+        Raises ``HudiCoreError`` if the table has no completed commit or the 
commit metadata
+        holds no schema. :meth:`HudiTable.get_schema_in_avro_str` instead 
falls back to the
+        schema in the table config when the table has no completed commit.
+
+        Returns:
+            str: The Avro schema as a JSON string.
+        """
+        ...
+    def get_latest_schema(self) -> "pyarrow.Schema":
+        """
+        Returns the data schema, without Hudi meta fields, of the latest 
completed commit.
+
+        Taken from the commit metadata, or, when the metadata holds no schema, 
from a base
+        file referenced by the commit's write stats. Raises ``HudiCoreError`` 
if the table
+        has no completed commit; :meth:`HudiTable.get_schema` instead falls 
back to the
+        schema in the table config.
+
+        Returns:
+            pyarrow.Schema: The schema of the latest commit.
+        """
+        ...
 
 def build_hudi_table(
     base_uri: str,
@@ -738,6 +944,13 @@ def build_hudi_table(
 
 @dataclass(init=False)
 class HudiDataFusionDataSource:
+    """
+    A Hudi table as a DataFusion table provider.
+
+    Register it on a ``datafusion.SessionContext`` with ``register_table`` and 
query it with
+    SQL. Requires the ``datafusion`` package, installed with the 
``hudi[datafusion]`` extra.
+    """
+
     def __init__(
         self,
         base_uri: str,
diff --git a/python/src/internal.rs b/python/src/internal.rs
index 293ef66a..9ce85568 100644
--- a/python/src/internal.rs
+++ b/python/src/internal.rs
@@ -1059,7 +1059,7 @@ impl HudiTable {
 #[cfg(not(tarpaulin_include))]
 #[pyclass(frozen, get_all)]
 pub struct HudiCompactionResult {
-    instant_time: Option<String>,
+    requested_time: Option<String>,
     completion_time: Option<String>,
     num_file_groups: usize,
     num_log_files: usize,
@@ -1075,8 +1075,8 @@ impl HudiCompactionResult {
                 .map_or_else(|| "None".to_string(), |t| format!("'{t}'"))
         };
         format!(
-            "HudiCompactionResult(instant_time={}, completion_time={}, 
num_file_groups={}, num_log_files={}, num_writes={})",
-            quoted(&self.instant_time),
+            "HudiCompactionResult(requested_time={}, completion_time={}, 
num_file_groups={}, num_log_files={}, num_writes={})",
+            quoted(&self.requested_time),
             quoted(&self.completion_time),
             self.num_file_groups,
             self.num_log_files,
@@ -1088,7 +1088,7 @@ impl HudiCompactionResult {
 impl From<CompactionResult> for HudiCompactionResult {
     fn from(r: CompactionResult) -> Self {
         Self {
-            instant_time: r.requested_time,
+            requested_time: r.requested_time,
             completion_time: r.completion_time,
             num_file_groups: r.num_file_groups,
             num_log_files: r.num_log_files,
@@ -1101,7 +1101,7 @@ impl From<CompactionResult> for HudiCompactionResult {
 #[cfg(not(tarpaulin_include))]
 #[pyclass(frozen, get_all)]
 pub struct HudiWriteResult {
-    instant_time: Option<String>,
+    requested_time: Option<String>,
     completion_time: Option<String>,
     num_writes: usize,
     num_updates: usize,
@@ -1118,8 +1118,8 @@ impl HudiWriteResult {
                 .map_or_else(|| "None".to_string(), |t| format!("'{t}'"))
         };
         format!(
-            "HudiWriteResult(instant_time={}, completion_time={}, 
num_writes={}, num_updates={}, num_inserts={}, num_deletes={})",
-            quoted(&self.instant_time),
+            "HudiWriteResult(requested_time={}, completion_time={}, 
num_writes={}, num_updates={}, num_inserts={}, num_deletes={})",
+            quoted(&self.requested_time),
             quoted(&self.completion_time),
             self.num_writes,
             self.num_updates,
@@ -1132,7 +1132,7 @@ impl HudiWriteResult {
 impl From<WriteResult> for HudiWriteResult {
     fn from(r: WriteResult) -> Self {
         Self {
-            instant_time: r.requested_time,
+            requested_time: r.requested_time,
             completion_time: r.completion_time,
             num_writes: r.num_writes,
             num_updates: r.num_updates,
@@ -2065,7 +2065,7 @@ mod tests {
             num_inserts: 2,
             num_deletes: 3,
         });
-        assert_eq!(rewrite.instant_time.as_deref(), Some("20240101000000000"));
+        assert_eq!(rewrite.requested_time.as_deref(), 
Some("20240101000000000"));
         assert_eq!(
             (
                 rewrite.num_writes,
diff --git a/python/tests/test_table_write.py b/python/tests/test_table_write.py
index 5e178786..c36e83df 100644
--- a/python/tests/test_table_write.py
+++ b/python/tests/test_table_write.py
@@ -211,7 +211,7 @@ def test_append_then_read(tmp_path, table_type):
     )
     res = table.append(trips(("t1", "sf", 1, 30.0), ("t2", "nyc", 1, 45.0)))
     assert isinstance(res, HudiWriteResult)
-    assert res.instant_time
+    assert res.requested_time
     assert (res.num_writes, res.num_inserts, res.num_updates, res.num_deletes) 
== (
         2,
         2,
@@ -219,7 +219,7 @@ def test_append_then_read(tmp_path, table_type):
         0,
     )
     assert "num_inserts=2" in repr(res)
-    assert f"instant_time='{res.instant_time}'" in repr(res)
+    assert f"requested_time='{res.requested_time}'" in repr(res)
     assert f"completion_time='{res.completion_time}'" in repr(res)
     with pytest.raises(AttributeError):
         res.num_inserts = 0
@@ -258,11 +258,11 @@ def 
test_completion_time_bounds_incremental_reads(tmp_path):
     table = HudiTable.create(str(tmp_path / "t"), record_key="id", 
ordering_fields="ts")
     base = table.append(trips(("t1", "sf", 1, 30.0), ("t2", "sf", 1, 45.0)))
     assert base.completion_time is not None
-    assert base.completion_time > base.instant_time
+    assert base.completion_time > base.requested_time
     upsert = table.upsert(trips(("t2", "sf", 2, 50.0), ("t3", "nyc", 2, 15.0)))
     assert upsert.completion_time > base.completion_time
     no_op = table.delete_keys(["missing"])
-    assert (no_op.instant_time, no_op.completion_time) == (None, None)
+    assert (no_op.requested_time, no_op.completion_time) == (None, None)
     assert "completion_time=None" in repr(no_op)
 
     def changed_after(bound):
@@ -278,7 +278,7 @@ def test_completion_time_bounds_incremental_reads(tmp_path):
     # The bound is compared against completion times: the requested time of
     # the base commit admits the base commit itself.
     assert changed_after(base.completion_time) == ["t2", "t3"]
-    assert changed_after(base.instant_time) == ["t1", "t2", "t3"]
+    assert changed_after(base.requested_time) == ["t1", "t2", "t3"]
     assert changed_after(upsert.completion_time) == []
 
 
@@ -328,8 +328,8 @@ def test_update_no_match_creates_no_commit(tmp_path):
     table = new_table(tmp_path)
     commits = len(table.get_timeline().get_completed_commits())
     res = table.update("city = 'la'", {"fare": 1.0})
-    assert (res.instant_time, res.num_updates) == (None, 0)
-    assert "instant_time=None" in repr(res)
+    assert (res.requested_time, res.num_updates) == (None, 0)
+    assert "requested_time=None" in repr(res)
     assert len(table.get_timeline().get_completed_commits()) == commits
 
 
@@ -526,7 +526,7 @@ def test_delete_by_non_key_predicate(tmp_path):
     assert res.num_deletes == 1
     assert set(snapshot(table)) == {"t1", "t3"}
     res = table.delete("fare > 1000")
-    assert (res.instant_time, res.num_deletes) == (None, 0)
+    assert (res.requested_time, res.num_deletes) == (None, 0)
 
 
 @pytest.mark.parametrize("table_type", ["cow", "mor"])
@@ -536,7 +536,7 @@ def test_delete_keys(tmp_path, table_type):
     assert res.num_deletes == 2
     assert set(snapshot(table)) == {"t2"}
     res = table.delete_keys(["missing"])
-    assert (res.instant_time, res.num_deletes) == (None, 0)
+    assert (res.requested_time, res.num_deletes) == (None, 0)
     res = table.delete_keys(k for k in ("t2",))
     assert res.num_deletes == 1
     assert snapshot(table) == {}
@@ -556,7 +556,7 @@ def test_delete_keys_rejects_bad_input(tmp_path):
 def test_overwrite(tmp_path, table_type):
     table = new_table(tmp_path, table_type)
     res = table.overwrite(trips(("t9", "sf", 9, 10.0)))
-    assert res.instant_time
+    assert res.requested_time
     assert snapshot(table) == {"t9": ("sf", 9, 10.0)}
 
 
@@ -564,7 +564,7 @@ def test_overwrite(tmp_path, table_type):
 def test_dynamic_partition_overwrite(tmp_path, table_type):
     table = new_table(tmp_path, table_type)
     res = table.dynamic_partition_overwrite(trips(("t8", "sf", 9, 11.0)))
-    assert res.instant_time
+    assert res.requested_time
     assert snapshot(table) == {"t8": ("sf", 9, 11.0), "t3": ("nyc", 1, 20.0)}
 
 
@@ -819,12 +819,12 @@ def test_compact_folds_logs_and_keeps_rows(tmp_path):
     before = snapshot(table)
     result = table.compact()
     assert isinstance(result, HudiCompactionResult)
-    assert result.instant_time is not None and result.completion_time is not 
None
+    assert result.requested_time is not None and result.completion_time is not 
None
     assert (result.num_file_groups, result.num_log_files) == (1, 1)
     assert result.num_writes == 2
     assert snapshot(table) == before
     nothing = table.compact()
-    assert nothing.instant_time is None and nothing.num_file_groups == 0
+    assert nothing.requested_time is None and nothing.num_file_groups == 0
     assert table.await_compaction() is None
 
 

Reply via email to