@@ -203,8 +203,18 @@ def __init__(self, **properties):
203203 # Extract storage properties
204204 self .storage_properties = {k [8 :]: v for k , v in properties .items () if k .startswith ("storage." )}
205205
206- # Create client
207- self ._client = HiveMetastoreClient (self .uri , self .ugi )
206+ # Store properties for pickling support
207+ self ._properties = properties .copy ()
208+
209+ # Lazy initialization to support pickling
210+ self ._client = None
211+
212+ @property
213+ def client (self ):
214+ """Get the Hive client, initializing it if necessary."""
215+ if self ._client is None :
216+ self ._client = HiveMetastoreClient (self .uri , self .ugi )
217+ return self ._client
208218
209219 def _normalize_identifier (self , identifier : List [str ]) -> tuple :
210220 """Normalize identifier to (database, table) tuple."""
@@ -231,7 +241,7 @@ def list_namespaces(self, request: ListNamespacesRequest) -> ListNamespacesRespo
231241 # Non-root namespaces don't have children in Hive2
232242 return ListNamespacesResponse (namespaces = [])
233243
234- with self ._client as client :
244+ with self .client as client :
235245 databases = client .get_all_databases ()
236246 # Return just database names as strings (excluding default)
237247 namespaces = [db for db in databases if db != "default" ]
@@ -259,7 +269,7 @@ def describe_namespace(self, request: DescribeNamespaceRequest) -> DescribeNames
259269
260270 database_name = request .id [0 ]
261271
262- with self ._client as client :
272+ with self .client as client :
263273 database = client .get_database (database_name )
264274
265275 properties = {}
@@ -309,7 +319,7 @@ def create_namespace(self, request: CreateNamespaceRequest) -> CreateNamespaceRe
309319 if k not in ["comment" , "owner" , "location" ]
310320 }
311321
312- with self ._client as client :
322+ with self .client as client :
313323 client .create_database (database )
314324
315325 return CreateNamespaceResponse ()
@@ -331,7 +341,7 @@ def drop_namespace(self, request: DropNamespaceRequest) -> DropNamespaceResponse
331341
332342 database_name = request .id [0 ]
333343
334- with self ._client as client :
344+ with self .client as client :
335345 # Check if database is empty
336346 tables = client .get_all_tables (database_name )
337347 cascade = request .behavior == "CASCADE" if request .behavior else False
@@ -360,7 +370,7 @@ def namespace_exists(self, request: NamespaceExistsRequest) -> None:
360370
361371 database_name = request .id [0 ]
362372
363- with self ._client as client :
373+ with self .client as client :
364374 client .get_database (database_name )
365375 except Exception as e :
366376 if NoSuchObjectException and isinstance (e , NoSuchObjectException ):
@@ -380,7 +390,7 @@ def list_tables(self, request: ListTablesRequest) -> ListTablesResponse:
380390
381391 database_name = request .id [0 ]
382392
383- with self ._client as client :
393+ with self .client as client :
384394 table_names = client .get_all_tables (database_name )
385395
386396 # Filter for Lance tables if needed
@@ -410,7 +420,7 @@ def describe_table(self, request: DescribeTableRequest) -> DescribeTableResponse
410420 try :
411421 database , table_name = self ._normalize_identifier (request .id )
412422
413- with self ._client as client :
423+ with self .client as client :
414424 table = client .get_table (database , table_name )
415425
416426 # Check if it's a Lance table (case insensitive)
@@ -531,7 +541,7 @@ def register_table(self, request: RegisterTableRequest) -> RegisterTableResponse
531541 if k not in [TABLE_TYPE_KEY , MANAGED_BY_KEY , VERSION_KEY ]:
532542 hive_table .parameters [k ] = v
533543
534- with self ._client as client :
544+ with self .client as client :
535545 client .create_table (hive_table )
536546
537547 return RegisterTableResponse (
@@ -549,7 +559,7 @@ def table_exists(self, request: TableExistsRequest) -> None:
549559 try :
550560 database , table_name = self ._normalize_identifier (request .id )
551561
552- with self ._client as client :
562+ with self .client as client :
553563 table = client .get_table (database , table_name )
554564
555565 # Check if it's a Lance table (case insensitive)
@@ -569,7 +579,7 @@ def drop_table(self, request: DropTableRequest) -> DropTableResponse:
569579 try :
570580 database , table_name = self ._normalize_identifier (request .id )
571581
572- with self ._client as client :
582+ with self .client as client :
573583 # Get table to check if it's a Lance table
574584 table = client .get_table (database , table_name )
575585
@@ -595,7 +605,7 @@ def deregister_table(self, request: DeregisterTableRequest) -> DeregisterTableRe
595605 try :
596606 database , table_name = self ._normalize_identifier (request .id )
597607
598- with self ._client as client :
608+ with self .client as client :
599609 # Get table to check if it's a Lance table
600610 table = client .get_table (database , table_name )
601611
@@ -710,4 +720,16 @@ def _pyarrow_type_to_hive_type(self, dtype: pa.DataType) -> str:
710720 field_strs .append (f"{ field .name } :{ field_type } " )
711721 return f"struct<{ ',' .join (field_strs )} >"
712722 else :
713- return "string" # Default to string for unknown types
723+ return "string" # Default to string for unknown types
724+
725+ def __getstate__ (self ):
726+ """Prepare instance for pickling by excluding unpickleable objects."""
727+ state = self .__dict__ .copy ()
728+ # Remove the unpickleable Hive client
729+ state ['_client' ] = None
730+ return state
731+
732+ def __setstate__ (self , state ):
733+ """Restore instance from pickled state."""
734+ self .__dict__ .update (state )
735+ # The Hive client will be re-initialized lazily via the property
0 commit comments