Skip to content

Commit 226e6ce

Browse files
lnenovGauvain Pocentek
authored and
Gauvain Pocentek
committed
Module's base objects serialization (#359)
Make gitlab objects serializable With current implementation of API v3 and v4 support, some instances have properties of type module and are not serializable. Handle these properties manually with setstate and getstate methods.
1 parent 38d4467 commit 226e6ce

File tree

5 files changed

+62
-0
lines changed

5 files changed

+62
-0
lines changed

gitlab/__init__.py

+11
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,17 @@ def __init__(self, url, private_token=None, email=None, password=None,
138138
manager = getattr(objects, cls_name)(self)
139139
setattr(self, var_name, manager)
140140

141+
def __getstate__(self):
142+
state = self.__dict__.copy()
143+
state.pop('_objects')
144+
return state
145+
146+
def __setstate__(self, state):
147+
self.__dict__.update(state)
148+
objects = importlib.import_module('gitlab.v%s.objects' %
149+
self._api_version)
150+
self._objects = objects
151+
141152
@property
142153
def api_version(self):
143154
return self._api_version

gitlab/base.py

+22
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,17 @@ def __init__(self, gl, data=None, **kwargs):
416416
if not hasattr(self, "id"):
417417
self.id = None
418418

419+
def __getstate__(self):
420+
state = self.__dict__.copy()
421+
module = state.pop('_module')
422+
state['_module_name'] = module.__name__
423+
return state
424+
425+
def __setstate__(self, state):
426+
module_name = state.pop('_module_name')
427+
self.__dict__.update(state)
428+
self._module = importlib.import_module(module_name)
429+
419430
def _set_manager(self, var, cls, attrs):
420431
manager = cls(self.gitlab, self, attrs)
421432
setattr(self, var, manager)
@@ -555,6 +566,17 @@ def __init__(self, manager, attrs):
555566
self.__dict__['_parent_attrs'] = self.manager.parent_attrs
556567
self._create_managers()
557568

569+
def __getstate__(self):
570+
state = self.__dict__.copy()
571+
module = state.pop('_module')
572+
state['_module_name'] = module.__name__
573+
return state
574+
575+
def __setstate__(self, state):
576+
module_name = state.pop('_module_name')
577+
self.__dict__.update(state)
578+
self._module = importlib.import_module(module_name)
579+
558580
def __getattr__(self, name):
559581
try:
560582
return self.__dict__['_updated_attrs'][name]

gitlab/tests/test_base.py

+10
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
# You should have received a copy of the GNU Lesser General Public License
1616
# along with this program. If not, see <http://www.gnu.org/licenses/>.
1717

18+
import pickle
1819
try:
1920
import unittest
2021
except ImportError:
@@ -86,6 +87,15 @@ def test_instanciate(self):
8687
self.assertEqual(self.manager, obj.manager)
8788
self.assertEqual(self.gitlab, obj.manager.gitlab)
8889

90+
def test_pickability(self):
91+
obj = FakeObject(self.manager, {'foo': 'bar'})
92+
original_obj_module = obj._module
93+
pickled = pickle.dumps(obj)
94+
unpickled = pickle.loads(pickled)
95+
self.assertIsInstance(unpickled, FakeObject)
96+
self.assertTrue(hasattr(unpickled, '_module'))
97+
self.assertEqual(unpickled._module, original_obj_module)
98+
8999
def test_attrs(self):
90100
obj = FakeObject(self.manager, {'foo': 'bar'})
91101

gitlab/tests/test_gitlab.py

+9
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
from __future__ import print_function
2020

21+
import pickle
2122
try:
2223
import unittest
2324
except ImportError:
@@ -890,6 +891,14 @@ def setUp(self):
890891
email="testuser@test.com", password="testpassword",
891892
ssl_verify=True)
892893

894+
def test_pickability(self):
895+
original_gl_objects = self.gl._objects
896+
pickled = pickle.dumps(self.gl)
897+
unpickled = pickle.loads(pickled)
898+
self.assertIsInstance(unpickled, Gitlab)
899+
self.assertTrue(hasattr(unpickled, '_objects'))
900+
self.assertEqual(unpickled._objects, original_gl_objects)
901+
893902
def test_credentials_auth_nopassword(self):
894903
self.gl.email = None
895904
self.gl.password = None

gitlab/tests/test_gitlabobject.py

+10
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from __future__ import absolute_import
2222

2323
import json
24+
import pickle
2425
try:
2526
import unittest
2627
except ImportError:
@@ -158,6 +159,15 @@ def test_json(self):
158159
self.assertEqual(data["username"], "testname")
159160
self.assertEqual(data["gitlab"]["url"], "http://localhost/api/v3")
160161

162+
def test_pickability(self):
163+
gl_object = CurrentUser(self.gl, data={"username": "testname"})
164+
original_obj_module = gl_object._module
165+
pickled = pickle.dumps(gl_object)
166+
unpickled = pickle.loads(pickled)
167+
self.assertIsInstance(unpickled, CurrentUser)
168+
self.assertTrue(hasattr(unpickled, '_module'))
169+
self.assertEqual(unpickled._module, original_obj_module)
170+
161171
def test_data_for_gitlab(self):
162172
class FakeObj1(GitlabObject):
163173
_url = '/fake1'

0 commit comments

Comments
 (0)