Skip to content

Commit b4b17de

Browse files
committed
PYCBC-1734: Migrate Collection management away from Wrapper decorators
Changes ------- * Add collection mgmt types, request builder * Add collection mgmt impl for all 3 APIs * Update APIs collection manager classes to use impl and remove wrapper decorators * Remove pytest.skip() from collection mgmt tests * Remove use of OverloadManager and instead use static type hints Change-Id: If4c16707124f205e8f561bc3555e53481f19e53d Reviewed-on: https://review.couchbase.org/c/couchbase-python-client/+/239334 Reviewed-by: Dimitris Christodoulou <dimitris.christodoulou@couchbase.com> Tested-by: Build Bot <build@couchbase.com>
1 parent 986e7d6 commit b4b17de

13 files changed

Lines changed: 1265 additions & 426 deletions

File tree

acouchbase/management/collections.py

Lines changed: 189 additions & 150 deletions
Large diffs are not rendered by default.
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# Copyright 2016-2023. Couchbase, Inc.
2+
# All Rights Reserved.
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License")
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
16+
from __future__ import annotations
17+
18+
from asyncio import AbstractEventLoop
19+
from datetime import timedelta
20+
from typing import TYPE_CHECKING, List
21+
22+
from couchbase.management.logic.collection_mgmt_req_builder import CollectionMgmtRequestBuilder
23+
from couchbase.management.logic.collection_mgmt_req_types import (CollectionSpec,
24+
CreateCollectionRequest,
25+
CreateScopeRequest,
26+
DropCollectionRequest,
27+
DropScopeRequest,
28+
GetAllScopesRequest,
29+
ScopeSpec,
30+
UpdateCollectionRequest)
31+
32+
if TYPE_CHECKING:
33+
from acouchbase.logic.client_adapter import AsyncClientAdapter
34+
35+
36+
class AsyncCollectionMgmtImpl:
37+
def __init__(self, client_adapter: AsyncClientAdapter) -> None:
38+
self._client_adapter = client_adapter
39+
self._request_builder = CollectionMgmtRequestBuilder()
40+
41+
@property
42+
def loop(self) -> AbstractEventLoop:
43+
"""**INTERNAL**"""
44+
return self._client_adapter.loop
45+
46+
@property
47+
def request_builder(self) -> CollectionMgmtRequestBuilder:
48+
"""**INTERNAL**"""
49+
return self._request_builder
50+
51+
async def create_collection(self, req: CreateCollectionRequest) -> None:
52+
"""**INTERNAL**"""
53+
await self._client_adapter.execute_mgmt_request(req)
54+
55+
async def create_scope(self, req: CreateScopeRequest) -> None:
56+
"""**INTERNAL**"""
57+
await self._client_adapter.execute_mgmt_request(req)
58+
59+
async def drop_collection(self, req: DropCollectionRequest) -> None:
60+
"""**INTERNAL**"""
61+
await self._client_adapter.execute_mgmt_request(req)
62+
63+
async def drop_scope(self, req: DropScopeRequest) -> None:
64+
"""**INTERNAL**"""
65+
await self._client_adapter.execute_mgmt_request(req)
66+
67+
async def get_all_scopes(self, req: GetAllScopesRequest) -> List[ScopeSpec]:
68+
"""**INTERNAL**"""
69+
res = await self._client_adapter.execute_mgmt_request(req)
70+
scopes = []
71+
raw_scopes = res.raw_result.get('scopes', None)
72+
if raw_scopes:
73+
for s in raw_scopes:
74+
scope = ScopeSpec(s['name'], list())
75+
for c in s['collections']:
76+
scope.collections.append(
77+
CollectionSpec(c['name'],
78+
c['scope_name'],
79+
timedelta(seconds=c['max_expiry']),
80+
history=c.get('history')))
81+
scopes.append(scope)
82+
83+
return scopes
84+
85+
async def update_collection(self, req: UpdateCollectionRequest) -> None:
86+
"""**INTERNAL**"""
87+
await self._client_adapter.execute_mgmt_request(req)

acouchbase/tests/collectionmgmt_t.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@
3636
from ._test_utils import TestEnvironment
3737

3838

39-
@pytest.mark.skip(reason='Skip until PYCBC-1734')
4039
class CollectionManagementTests:
4140

4241
TEST_BUCKET = "test-bucket"

couchbase/management/collections.py

Lines changed: 73 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,23 @@
1515

1616
from __future__ import annotations
1717

18-
from inspect import Parameter, Signature
18+
import sys
1919
from typing import (TYPE_CHECKING,
2020
Any,
21-
Dict,
2221
Iterable,
23-
Optional)
22+
Optional,
23+
overload)
2424

25-
from couchbase._utils import OverloadType
26-
from couchbase.logic.supportability import Supportability
27-
from couchbase.management.logic.collections_logic import (CollectionManagerLogic,
28-
CollectionSpec,
29-
CreateCollectionSettings,
30-
ScopeSpec,
31-
UpdateCollectionSettings)
32-
from couchbase.management.logic.wrappers import BlockingMgmtWrapper, ManagementType
25+
if sys.version_info >= (3, 13):
26+
from warnings import deprecated
27+
else:
28+
from typing_extensions import deprecated
29+
30+
from couchbase.management.logic.collection_mgmt_impl import CollectionMgmtImpl
31+
from couchbase.management.logic.collection_mgmt_req_types import (CollectionSpec,
32+
CreateCollectionSettings,
33+
ScopeSpec,
34+
UpdateCollectionSettings)
3335

3436
# @TODO: lets deprecate import of options from couchbase.management.collections
3537
from couchbase.management.options import (CreateCollectionOptions,
@@ -43,16 +45,16 @@
4345
from couchbase.logic.client_adapter import ClientAdapter
4446

4547

46-
class CollectionManager(CollectionManagerLogic):
48+
class CollectionManager:
4749

4850
def __init__(self, client_adapter: ClientAdapter, bucket_name: str) -> None:
49-
super().__init__(client_adapter.connection, bucket_name)
51+
self._bucket_name = bucket_name
52+
self._impl = CollectionMgmtImpl(client_adapter)
5053

51-
@BlockingMgmtWrapper.block(None, ManagementType.CollectionMgmt, CollectionManagerLogic._ERROR_MAPPING)
5254
def create_scope(self,
5355
scope_name: str,
5456
*options: CreateScopeOptions,
55-
**kwargs: Dict[str, Any]
57+
**kwargs: Any
5658
) -> None:
5759
"""Creates a new scope.
5860
@@ -64,13 +66,16 @@ def create_scope(self,
6466
Raises:
6567
:class:`~couchbase.exceptions.ScopeAlreadyExistsException`: If the scope already exists.
6668
""" # noqa: E501
67-
return super().create_scope(scope_name, *options, **kwargs)
69+
req = self._impl.request_builder.build_create_scope_request(self._bucket_name,
70+
scope_name,
71+
*options,
72+
**kwargs)
73+
self._impl.create_scope(req)
6874

69-
@BlockingMgmtWrapper.block(None, ManagementType.CollectionMgmt, CollectionManagerLogic._ERROR_MAPPING)
7075
def drop_scope(self,
7176
scope_name: str,
7277
*options: DropScopeOptions,
73-
**kwargs: Dict[str, Any]
78+
**kwargs: Any
7479
) -> None:
7580
"""Drops an existing scope.
7681
@@ -82,13 +87,15 @@ def drop_scope(self,
8287
Raises:
8388
:class:`~couchbase.exceptions.ScopeNotFoundException`: If the scope does not exist.
8489
""" # noqa: E501
85-
return super().drop_scope(scope_name, *options, **kwargs)
90+
req = self._impl.request_builder.build_drop_scope_request(self._bucket_name,
91+
scope_name,
92+
*options,
93+
**kwargs)
94+
self._impl.drop_scope(req)
8695

87-
@BlockingMgmtWrapper.block((ScopeSpec, CollectionSpec), ManagementType.CollectionMgmt,
88-
CollectionManagerLogic._ERROR_MAPPING)
8996
def get_all_scopes(self,
9097
*options: GetAllScopesOptions,
91-
**kwargs: Dict[str, Any]
98+
**kwargs: Any
9299
) -> Iterable[ScopeSpec]:
93100
"""Returns all configured scopes along with their collections.
94101
@@ -100,73 +107,37 @@ def get_all_scopes(self,
100107
Returns:
101108
Iterable[:class:`.ScopeSpec`]: A list of all configured scopes.
102109
""" # noqa: E501
103-
return super().get_all_scopes(*options, **kwargs)
110+
req = self._impl.request_builder.build_get_all_scopes_request(self._bucket_name,
111+
*options,
112+
**kwargs)
113+
return self._impl.get_all_scopes(req)
104114

105-
@BlockingMgmtWrapper.block(None,
106-
ManagementType.CollectionMgmt,
107-
CollectionManagerLogic._ERROR_MAPPING,
108-
OverloadType.SECONDARY)
115+
@overload
116+
@deprecated("Use ``create_collection(scope_name, collection_name, settings=None, *options, **kwargs)`` instead.")
109117
def create_collection(self,
110118
collection: CollectionSpec,
111119
*options: CreateCollectionOptions,
112-
**kwargs: Dict[str, Any]
120+
**kwargs: Any
113121
) -> None:
114-
"""
115-
.. deprecated:: 4.1.9
116-
Use ``create_collection(scope_name, collection_name, settings=None, *options, **kwargs)`` instead.
117-
118-
Creates a new collection in a specified scope.
119-
120-
Args:
121-
collection (:class:`.CollectionSpec`): The collection details.
122-
options (:class:`~couchbase.management.options.CreateCollectionOptions`): Optional parameters for this operation.
123-
**kwargs (Dict[str, Any]): keyword arguments that can be used as optional parameters for this operation.
122+
...
124123

125-
Raises:
126-
:class:`~couchbase.exceptions.CollectionAlreadyExistsException`: If the collection already exists.
127-
:class:`~couchbase.exceptions.ScopeNotFoundException`: If the scope does not exist.
128-
""" # noqa: E501
129-
Supportability.method_signature_deprecated(
130-
'create_collection',
131-
Signature(
132-
parameters=[
133-
Parameter('collection', Parameter.POSITIONAL_OR_KEYWORD, annotation=CollectionSpec),
134-
Parameter('options', Parameter.VAR_POSITIONAL, annotation=CreateCollectionOptions),
135-
Parameter('kwargs', Parameter.VAR_KEYWORD, annotation=Dict[str, Any]),
136-
],
137-
return_annotation=None
138-
),
139-
Signature(
140-
parameters=[
141-
Parameter('scope_name', Parameter.POSITIONAL_OR_KEYWORD, annotation=str),
142-
Parameter('collection_name', Parameter.POSITIONAL_OR_KEYWORD, annotation=str),
143-
Parameter('settings', Parameter.POSITIONAL_OR_KEYWORD,
144-
annotation=Optional[CreateCollectionSettings]),
145-
Parameter('options', Parameter.VAR_POSITIONAL, annotation=CreateCollectionOptions),
146-
Parameter('kwargs', Parameter.VAR_KEYWORD, annotation=Dict[str, Any]),
147-
],
148-
return_annotation=None
149-
)
150-
)
151-
settings = None
152-
if collection.max_expiry is not None:
153-
settings = CreateCollectionSettings(max_expiry=collection.max_expiry)
154-
155-
return super().create_collection(collection.scope_name, collection.name, settings, *options, **kwargs)
156-
157-
@BlockingMgmtWrapper.block(None,
158-
ManagementType.CollectionMgmt,
159-
CollectionManagerLogic._ERROR_MAPPING,
160-
OverloadType.DEFAULT)
161-
def create_collection(self, # noqa: F811
124+
@overload
125+
def create_collection(self,
162126
scope_name: str,
163127
collection_name: str,
164128
settings: Optional[CreateCollectionSettings] = None,
165129
*options: CreateCollectionOptions,
166-
**kwargs: Dict[str, Any]
130+
**kwargs: Any
167131
) -> None:
132+
...
133+
134+
def create_collection(self, *args: object, **kwargs: object) -> None:
168135
"""Creates a new collection in a specified scope.
169136
137+
.. note::
138+
The overloaded create_collection method that takes a CollectionSpec is deprecated as of v4.1.9
139+
and will be removed in a future version.
140+
170141
Args:
171142
scope_name (str): The name of the scope the collection will be created in.
172143
collection_name (str): The name of the collection to be created
@@ -178,64 +149,33 @@ def create_collection(self, # noqa: F811
178149
:class:`~couchbase.exceptions.CollectionAlreadyExistsException`: If the collection already exists.
179150
:class:`~couchbase.exceptions.ScopeNotFoundException`: If the scope does not exist.
180151
""" # noqa: E501
181-
return super().create_collection(scope_name, collection_name, settings, *options, **kwargs)
152+
req = self._impl.request_builder.build_create_collection_request(self._bucket_name, *args, **kwargs)
153+
self._impl.create_collection(req)
182154

183-
@BlockingMgmtWrapper.block(None,
184-
ManagementType.CollectionMgmt,
185-
CollectionManagerLogic._ERROR_MAPPING,
186-
OverloadType.SECONDARY)
155+
@overload
156+
@deprecated("Use ``drop_collection(scope_name, collection_name, *options, **kwargs)`` instead.")
187157
def drop_collection(self,
188158
collection: CollectionSpec,
189159
*options: DropCollectionOptions,
190-
**kwargs: Dict[str, Any]
160+
**kwargs: Any
191161
) -> None:
192-
"""
193-
.. deprecated:: 4.1.9
194-
Use ``drop_collection(scope_name, collection_name, *options, **kwargs)`` instead.
195-
196-
Drops a collection from the specified scope.
197-
198-
Args:
199-
collection (:class:`.CollectionSpec`): The collection details.
200-
options (:class:`~couchbase.management.options.DropCollectionOptions`): Optional parameters for this operation.
201-
**kwargs (Dict[str, Any]): keyword arguments that can be used as optional parameters for this operation.
162+
...
202163

203-
Raises:
204-
:class:`~couchbase.exceptions.CollectionNotFoundException`: If the collection does not exist.
205-
""" # noqa: E501
206-
Supportability.method_signature_deprecated(
207-
'drop_collection',
208-
Signature(
209-
parameters=[
210-
Parameter('collection', Parameter.POSITIONAL_OR_KEYWORD, annotation=CollectionSpec),
211-
Parameter('options', Parameter.VAR_POSITIONAL, annotation=DropCollectionOptions),
212-
Parameter('kwargs', Parameter.VAR_KEYWORD, annotation=Dict[str, Any]),
213-
],
214-
return_annotation=None,
215-
),
216-
Signature(
217-
parameters=[
218-
Parameter('scope_name', Parameter.POSITIONAL_OR_KEYWORD, annotation=str),
219-
Parameter('collection_name', Parameter.POSITIONAL_OR_KEYWORD, annotation=str),
220-
Parameter('options', Parameter.VAR_POSITIONAL, annotation=DropCollectionOptions),
221-
Parameter('kwargs', Parameter.VAR_KEYWORD, annotation=Dict[str, Any]),
222-
],
223-
return_annotation=None
224-
)
225-
)
226-
return super().drop_collection(collection.scope_name, collection.name, *options, **kwargs)
227-
228-
@BlockingMgmtWrapper.block(None,
229-
ManagementType.CollectionMgmt,
230-
CollectionManagerLogic._ERROR_MAPPING,
231-
OverloadType.DEFAULT)
232-
def drop_collection(self, # noqa: F811
164+
@overload
165+
def drop_collection(self,
233166
scope_name: str,
234167
collection_name: str,
235168
*options: DropCollectionOptions,
236-
**kwargs: Dict[str, Any]) -> None:
169+
**kwargs: Any) -> None:
170+
...
171+
172+
def drop_collection(self, *args: object, **kwargs: object) -> None:
237173
"""Drops a collection from the specified scope.
238174
175+
.. note::
176+
The overloaded drop_collection method that takes a CollectionSpec is deprecated as of v4.1.9
177+
and will be removed in a future version.
178+
239179
Args:
240180
scope_name (str): The name of the scope the collection is in.
241181
collection_name (str): The name of the collection to be dropped
@@ -245,15 +185,15 @@ def drop_collection(self, # noqa: F811
245185
Raises:
246186
:class:`~couchbase.exceptions.CollectionNotFoundException`: If the collection does not exist.
247187
""" # noqa: E501
248-
return super().drop_collection(scope_name, collection_name, *options, **kwargs)
188+
req = self._impl.request_builder.build_drop_collection_request(self._bucket_name, *args, **kwargs)
189+
self._impl.drop_collection(req)
249190

250-
@BlockingMgmtWrapper.block(None, ManagementType.CollectionMgmt, CollectionManagerLogic._ERROR_MAPPING)
251191
def update_collection(self,
252192
scope_name: str,
253193
collection_name: str,
254194
settings: UpdateCollectionSettings,
255195
*options: UpdateCollectionOptions,
256-
**kwargs: Dict[str, Any]
196+
**kwargs: Any
257197
) -> None:
258198
"""Updates a collection in a specified scope.
259199
@@ -268,4 +208,10 @@ def update_collection(self,
268208
:class:`~couchbase.exceptions.CollectionNotFoundException`: If the collection does not exist.
269209
:class:`~couchbase.exceptions.ScopeNotFoundException`: If the scope does not exist.
270210
""" # noqa: E501
271-
return super().update_collection(scope_name, collection_name, settings, *options, **kwargs)
211+
req = self._impl.request_builder.build_update_collection_request(self._bucket_name,
212+
scope_name,
213+
collection_name,
214+
settings,
215+
*options,
216+
**kwargs)
217+
self._impl.update_collection(req)

0 commit comments

Comments
 (0)