30
30
import base64
31
31
import bz2
32
32
import io
33
+ import sys
33
34
import threading
34
35
import zlib
35
36
37
+ from google .protobuf .internal import api_implementation
38
+
36
39
from apache_beam .internal .cloudpickle import cloudpickle
37
40
38
41
try :
39
42
from absl import flags
40
43
except (ImportError , ModuleNotFoundError ):
41
44
pass
42
45
46
+
47
+ def _get_proto_enum_descriptor_class ():
48
+ implementation_type = api_implementation .Type ()
49
+
50
+ if implementation_type == 'upb' :
51
+ try :
52
+ from google ._upb ._message import EnumDescriptor
53
+ return EnumDescriptor
54
+ except ImportError :
55
+ pass
56
+ elif implementation_type == 'cpp' :
57
+ try :
58
+ from google .protobuf .pyext ._message import EnumDescriptor
59
+ return EnumDescriptor
60
+ except ImportError :
61
+ pass
62
+ elif implementation_type == 'python' :
63
+ try :
64
+ from google .protobuf .internal .python_message import EnumDescriptor
65
+ return EnumDescriptor
66
+ except ImportError :
67
+ pass
68
+
69
+ return None
70
+
71
+
72
+ EnumDescriptor = _get_proto_enum_descriptor_class ()
73
+
43
74
# Pickling, especially unpickling, causes broken module imports on Python 3
44
75
# if executed concurrently, see: BEAM-8651, http://bugs.python.org/issue38884.
45
76
_pickle_lock = threading .RLock ()
46
77
RLOCK_TYPE = type (_pickle_lock )
78
+ LOCK_TYPE = type (threading .Lock ())
79
+
80
+
81
+ def _reconstruct_enum_descriptor (full_name ):
82
+ for _ , module in sys .modules .items ():
83
+ if not hasattr (module , 'DESCRIPTOR' ):
84
+ continue
85
+
86
+ for _ , attr_value in vars (module ).items ():
87
+ if not hasattr (attr_value , 'DESCRIPTOR' ):
88
+ continue
89
+
90
+ if hasattr (attr_value .DESCRIPTOR , 'enum_types_by_name' ):
91
+ for (_ , enum_desc ) in attr_value .DESCRIPTOR .enum_types_by_name .items ():
92
+ if enum_desc .full_name == full_name :
93
+ return enum_desc
94
+ raise ImportError (f'Could not find enum descriptor: { full_name } ' )
95
+
96
+
97
+ def _pickle_enum_descriptor (obj ):
98
+ full_name = obj .full_name
99
+ return _reconstruct_enum_descriptor , (full_name , )
47
100
48
101
49
102
def dumps (o , enable_trace = True , use_zlib = False ) -> bytes :
@@ -59,6 +112,12 @@ def dumps(o, enable_trace=True, use_zlib=False) -> bytes:
59
112
pickler .dispatch_table [RLOCK_TYPE ] = _pickle_rlock
60
113
except NameError :
61
114
pass
115
+ try :
116
+ pickler .dispatch_table [LOCK_TYPE ] = _lock_reducer
117
+ except NameError :
118
+ pass
119
+ if EnumDescriptor is not None :
120
+ pickler .dispatch_table [EnumDescriptor ] = _pickle_enum_descriptor
62
121
pickler .dump (o )
63
122
s = file .getvalue ()
64
123
@@ -106,6 +165,10 @@ def _pickle_rlock(obj):
106
165
return RLOCK_TYPE , tuple ([])
107
166
108
167
168
+ def _lock_reducer (obj ):
169
+ return threading .Lock , tuple ([])
170
+
171
+
109
172
def dump_session (file_path ):
110
173
# It is possible to dump session with cloudpickle. However, since references
111
174
# are saved it should not be necessary. See https://s.apache.org/beam-picklers
0 commit comments