dkg 0.1.0b1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. dkg/__init__.py +3 -0
  2. dkg/asset.py +781 -0
  3. dkg/constants.py +39 -0
  4. dkg/data/interfaces/Assertion.json +131 -0
  5. dkg/data/interfaces/AssertionStorage.json +229 -0
  6. dkg/data/interfaces/CommitManagerV1.json +534 -0
  7. dkg/data/interfaces/CommitManagerV1U1.json +720 -0
  8. dkg/data/interfaces/ContentAsset.json +671 -0
  9. dkg/data/interfaces/ContentAssetStorage.json +706 -0
  10. dkg/data/interfaces/HashingProxy.json +227 -0
  11. dkg/data/interfaces/Hub.json +356 -0
  12. dkg/data/interfaces/Identity.json +193 -0
  13. dkg/data/interfaces/IdentityStorage.json +342 -0
  14. dkg/data/interfaces/ParametersStorage.json +468 -0
  15. dkg/data/interfaces/Profile.json +292 -0
  16. dkg/data/interfaces/ProfileStorage.json +596 -0
  17. dkg/data/interfaces/ProofManagerV1.json +525 -0
  18. dkg/data/interfaces/ProofManagerV1U1.json +546 -0
  19. dkg/data/interfaces/ScoringProxy.json +242 -0
  20. dkg/data/interfaces/ServiceAgreementStorageProxy.json +1299 -0
  21. dkg/data/interfaces/ServiceAgreementStorageV1.json +901 -0
  22. dkg/data/interfaces/ServiceAgreementStorageV1U1.json +1097 -0
  23. dkg/data/interfaces/ServiceAgreementV1.json +741 -0
  24. dkg/data/interfaces/ShardingTable.json +268 -0
  25. dkg/data/interfaces/ShardingTableStorage.json +317 -0
  26. dkg/data/interfaces/Staking.json +456 -0
  27. dkg/data/interfaces/StakingStorage.json +407 -0
  28. dkg/data/interfaces/Token.json +544 -0
  29. dkg/data/interfaces/UnfinalizedStateStorage.json +171 -0
  30. dkg/data/interfaces/WhitelistStorage.json +124 -0
  31. dkg/dataclasses.py +45 -0
  32. dkg/exceptions.py +161 -0
  33. dkg/graph.py +63 -0
  34. dkg/main.py +74 -0
  35. dkg/manager.py +64 -0
  36. dkg/method.py +131 -0
  37. dkg/module.py +63 -0
  38. dkg/node.py +54 -0
  39. dkg/providers/__init__.py +2 -0
  40. dkg/providers/blockchain.py +181 -0
  41. dkg/providers/node_http.py +62 -0
  42. dkg/types/__init__.py +8 -0
  43. dkg/types/blockchain.py +58 -0
  44. dkg/types/dkg_node.py +20 -0
  45. dkg/types/encoding.py +22 -0
  46. dkg/types/evm.py +25 -0
  47. dkg/types/generics.py +21 -0
  48. dkg/types/network.py +20 -0
  49. dkg/types/rdf.py +21 -0
  50. dkg/utils/__init__.py +0 -0
  51. dkg/utils/blockchain_request.py +159 -0
  52. dkg/utils/decorators.py +46 -0
  53. dkg/utils/merkle.py +173 -0
  54. dkg/utils/metadata.py +50 -0
  55. dkg/utils/node_request.py +197 -0
  56. dkg/utils/rdf.py +51 -0
  57. dkg/utils/string_transformations.py +22 -0
  58. dkg/utils/ual.py +41 -0
  59. dkg-0.1.0b1.dist-info/LICENSE +202 -0
  60. dkg-0.1.0b1.dist-info/METADATA +453 -0
  61. dkg-0.1.0b1.dist-info/RECORD +62 -0
  62. dkg-0.1.0b1.dist-info/WHEEL +4 -0
@@ -0,0 +1,124 @@
1
+ [
2
+ {
3
+ "inputs": [
4
+ {
5
+ "internalType": "address",
6
+ "name": "hubAddress",
7
+ "type": "address"
8
+ }
9
+ ],
10
+ "stateMutability": "nonpayable",
11
+ "type": "constructor"
12
+ },
13
+ {
14
+ "inputs": [
15
+ {
16
+ "internalType": "address",
17
+ "name": "addr",
18
+ "type": "address"
19
+ }
20
+ ],
21
+ "name": "blacklistAddress",
22
+ "outputs": [],
23
+ "stateMutability": "nonpayable",
24
+ "type": "function"
25
+ },
26
+ {
27
+ "inputs": [],
28
+ "name": "disableWhitelist",
29
+ "outputs": [],
30
+ "stateMutability": "nonpayable",
31
+ "type": "function"
32
+ },
33
+ {
34
+ "inputs": [],
35
+ "name": "enableWhitelist",
36
+ "outputs": [],
37
+ "stateMutability": "nonpayable",
38
+ "type": "function"
39
+ },
40
+ {
41
+ "inputs": [],
42
+ "name": "hub",
43
+ "outputs": [
44
+ {
45
+ "internalType": "contract Hub",
46
+ "name": "",
47
+ "type": "address"
48
+ }
49
+ ],
50
+ "stateMutability": "view",
51
+ "type": "function"
52
+ },
53
+ {
54
+ "inputs": [],
55
+ "name": "name",
56
+ "outputs": [
57
+ {
58
+ "internalType": "string",
59
+ "name": "",
60
+ "type": "string"
61
+ }
62
+ ],
63
+ "stateMutability": "pure",
64
+ "type": "function"
65
+ },
66
+ {
67
+ "inputs": [],
68
+ "name": "version",
69
+ "outputs": [
70
+ {
71
+ "internalType": "string",
72
+ "name": "",
73
+ "type": "string"
74
+ }
75
+ ],
76
+ "stateMutability": "pure",
77
+ "type": "function"
78
+ },
79
+ {
80
+ "inputs": [
81
+ {
82
+ "internalType": "address",
83
+ "name": "addr",
84
+ "type": "address"
85
+ }
86
+ ],
87
+ "name": "whitelistAddress",
88
+ "outputs": [],
89
+ "stateMutability": "nonpayable",
90
+ "type": "function"
91
+ },
92
+ {
93
+ "inputs": [
94
+ {
95
+ "internalType": "address",
96
+ "name": "",
97
+ "type": "address"
98
+ }
99
+ ],
100
+ "name": "whitelisted",
101
+ "outputs": [
102
+ {
103
+ "internalType": "bool",
104
+ "name": "",
105
+ "type": "bool"
106
+ }
107
+ ],
108
+ "stateMutability": "view",
109
+ "type": "function"
110
+ },
111
+ {
112
+ "inputs": [],
113
+ "name": "whitelistingEnabled",
114
+ "outputs": [
115
+ {
116
+ "internalType": "bool",
117
+ "name": "",
118
+ "type": "bool"
119
+ }
120
+ ],
121
+ "stateMutability": "view",
122
+ "type": "function"
123
+ }
124
+ ]
dkg/dataclasses.py ADDED
@@ -0,0 +1,45 @@
1
+ # Licensed to the Apache Software Foundation (ASF) under one
2
+ # or more contributor license agreements. See the NOTICE file
3
+ # distributed with this work for additional information
4
+ # regarding copyright ownership. The ASF licenses this file
5
+ # to you under the Apache License, Version 2.0 (the
6
+ # "License"); you may not use this file except in compliance
7
+ # with the License. You may obtain a copy of the License at
8
+
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+
18
+ from enum import Enum
19
+
20
+ import pandas as pd
21
+
22
+
23
+ class BlockchainResponseDict(dict):
24
+ pass
25
+
26
+
27
+ class HTTPRequestMethod(Enum):
28
+ GET = 1
29
+ POST = 2
30
+
31
+
32
+ class NodeResponseDict(dict):
33
+ def to_dataframe(self) -> pd.DataFrame:
34
+ return pd.DataFrame(self)
35
+
36
+
37
+ class KnowledgeAssetEnumStates(Enum):
38
+ LATEST = "LATEST"
39
+ LATEST_FINALIZED = "LATEST_FINALIZED"
40
+
41
+
42
+ class KnowledgeAssetContentVisibility(Enum):
43
+ ALL = "ALL"
44
+ PUBLIC = "PUBLIC"
45
+ PRIVATE = "PRIVATE"
dkg/exceptions.py ADDED
@@ -0,0 +1,161 @@
1
+ # Licensed to the Apache Software Foundation (ASF) under one
2
+ # or more contributor license agreements. See the NOTICE file
3
+ # distributed with this work for additional information
4
+ # regarding copyright ownership. The ASF licenses this file
5
+ # to you under the Apache License, Version 2.0 (the
6
+ # "License"); you may not use this file except in compliance
7
+ # with the License. You may obtain a copy of the License at
8
+
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+
18
+ class DKGException(Exception):
19
+ """
20
+ Exception mixin inherited by all exceptions of dkg.py
21
+ This allows::
22
+ try:
23
+ some_call()
24
+ except DKGException:
25
+ # deal with dkg exception
26
+ except:
27
+ # deal with other exceptions
28
+ """
29
+
30
+
31
+ class NetworkNotSupported(DKGException):
32
+ """
33
+ Raised when blockchain provider is initialized for unsupported network.
34
+ """
35
+
36
+ pass
37
+
38
+
39
+ class InvalidStateOption(DKGException):
40
+ """
41
+ Raised when invalid state option given to the get operation.
42
+ """
43
+
44
+ pass
45
+
46
+
47
+ class MissingKnowledgeAssetState(DKGException):
48
+ """
49
+ Raised when search for the Knowledge Asset state on the network has failed.
50
+ """
51
+
52
+ pass
53
+
54
+
55
+ class ValidationError(DKGException):
56
+ """
57
+ Raised when something does not pass a validation check.
58
+ """
59
+
60
+ pass
61
+
62
+
63
+ class InvalidRequest(DKGException):
64
+ """
65
+ Raised by a manager to signal that blockchain/node request method
66
+ doesn't exist.
67
+ """
68
+
69
+ pass
70
+
71
+
72
+ class HTTPRequestMethodNotSupported(DKGException):
73
+ """
74
+ Raised if used HTTP method isn't supported
75
+ """
76
+
77
+ pass
78
+
79
+
80
+ class NodeRequestError(DKGException):
81
+ """
82
+ Raised by Node HTTP Provider if error occured during request.
83
+ """
84
+
85
+ pass
86
+
87
+
88
+ class OperationNotFinished(DKGException):
89
+ """
90
+ Raised when requested operation result isn't ready.
91
+ """
92
+
93
+ pass
94
+
95
+
96
+ class OperationFailed(DKGException):
97
+ """
98
+ Raised when requested operation status is failed.
99
+ """
100
+
101
+ pass
102
+
103
+
104
+ class AccountMissing(DKGException):
105
+ """
106
+ Raised when trying to perform state-changing blockchain transaction without account
107
+ specified.
108
+ """
109
+
110
+ pass
111
+
112
+
113
+ class InvalidDataset(DKGException):
114
+ """
115
+ Raised when dataset URDNA2015 normalization doesn't result in any quads.
116
+ """
117
+
118
+ pass
119
+
120
+
121
+ class DatasetInputFormatNotSupported(DKGException):
122
+ """
123
+ Raised when trying to normalize RDF dataset with not supported input format.
124
+ """
125
+
126
+ pass
127
+
128
+
129
+ class DatasetOutputFormatNotSupported(DKGException):
130
+ """
131
+ Raised when trying to convert RDF dataset to not supported output format.
132
+ """
133
+
134
+ pass
135
+
136
+
137
+ class InvalidKnowledgeAsset(DKGException):
138
+ """
139
+ Raised when root of the Merkle Tree built from N-Quads isn't the same as the
140
+ assertionId.
141
+ """
142
+
143
+ pass
144
+
145
+
146
+ class InvalidTokenAmount(DKGException):
147
+ """
148
+ Raised when token amount for operation isn't specified and suggested amount is less
149
+ or equal to what is already present in the contract.
150
+ """
151
+
152
+ pass
153
+
154
+
155
+ class LeafNotInTree(DKGException):
156
+ """
157
+ Raised when proof/verification requested for the leaf that is not the part of the
158
+ Merkle Tree.
159
+ """
160
+
161
+ pass
dkg/graph.py ADDED
@@ -0,0 +1,63 @@
1
+ # Licensed to the Apache Software Foundation (ASF) under one
2
+ # or more contributor license agreements. See the NOTICE file
3
+ # distributed with this work for additional information
4
+ # regarding copyright ownership. The ASF licenses this file
5
+ # to you under the Apache License, Version 2.0 (the
6
+ # "License"); you may not use this file except in compliance
7
+ # with the License. You may obtain a copy of the License at
8
+
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+
18
+ from rdflib.plugins.sparql.parser import parseQuery
19
+
20
+ from dkg.dataclasses import NodeResponseDict
21
+ from dkg.exceptions import OperationNotFinished
22
+ from dkg.manager import DefaultRequestManager
23
+ from dkg.method import Method
24
+ from dkg.module import Module
25
+ from dkg.types import NQuads
26
+ from dkg.utils.decorators import retry
27
+ from dkg.utils.node_request import NodeRequest, validate_operation_status
28
+
29
+
30
+ class Graph(Module):
31
+ def __init__(self, manager: DefaultRequestManager):
32
+ self.manager = manager
33
+
34
+ _query = Method(NodeRequest.query)
35
+ _get_operation_result = Method(NodeRequest.get_operation_result)
36
+
37
+ def query(
38
+ self,
39
+ query: str,
40
+ repository: str,
41
+ ) -> NQuads:
42
+ parsed_query = parseQuery(query)
43
+ query_type = parsed_query[1].name.replace("Query", "").upper()
44
+
45
+ operation_id: NodeResponseDict = self._query(query, query_type, repository)[
46
+ "operationId"
47
+ ]
48
+ operation_result = self.get_operation_result(operation_id, "query")
49
+
50
+ return operation_result["data"]
51
+
52
+ @retry(catch=OperationNotFinished, max_retries=5, base_delay=1, backoff=2)
53
+ def get_operation_result(
54
+ self, operation_id: str, operation: str
55
+ ) -> NodeResponseDict:
56
+ operation_result = self._get_operation_result(
57
+ operation_id=operation_id,
58
+ operation=operation,
59
+ )
60
+
61
+ validate_operation_status(operation_result)
62
+
63
+ return operation_result
dkg/main.py ADDED
@@ -0,0 +1,74 @@
1
+ # Licensed to the Apache Software Foundation (ASF) under one
2
+ # or more contributor license agreements. See the NOTICE file
3
+ # distributed with this work for additional information
4
+ # regarding copyright ownership. The ASF licenses this file
5
+ # to you under the Apache License, Version 2.0 (the
6
+ # "License"); you may not use this file except in compliance
7
+ # with the License. You may obtain a copy of the License at
8
+
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+
18
+ from functools import wraps
19
+
20
+ from dkg.asset import ContentAsset
21
+ from dkg.graph import Graph
22
+ from dkg.manager import DefaultRequestManager
23
+ from dkg.module import Module
24
+ from dkg.node import Node
25
+ from dkg.providers import BlockchainProvider, NodeHTTPProvider
26
+ from dkg.types import UAL, Address, ChecksumAddress
27
+ from dkg.utils.ual import format_ual, parse_ual
28
+
29
+
30
+ class DKG(Module):
31
+ asset: ContentAsset
32
+ node: Node
33
+ graph: Graph
34
+
35
+ @staticmethod
36
+ @wraps(format_ual)
37
+ def format_ual(
38
+ blockchain: str, contract_address: Address | ChecksumAddress, token_id: int
39
+ ) -> UAL:
40
+ return format_ual(blockchain, contract_address, token_id)
41
+
42
+ @staticmethod
43
+ @wraps(parse_ual)
44
+ def parse_ual(ual: UAL) -> dict[str, str | Address | int]:
45
+ return parse_ual(ual)
46
+
47
+ def __init__(
48
+ self,
49
+ node_provider: NodeHTTPProvider,
50
+ blockchain_provider: BlockchainProvider,
51
+ ):
52
+ self.manager = DefaultRequestManager(node_provider, blockchain_provider)
53
+ modules = {
54
+ "asset": ContentAsset(self.manager),
55
+ "node": Node(self.manager),
56
+ "graph": Graph(self.manager),
57
+ }
58
+ self._attach_modules(modules)
59
+
60
+ @property
61
+ def node_provider(self) -> NodeHTTPProvider:
62
+ return self.manager.node_provider
63
+
64
+ @node_provider.setter
65
+ def node_provider(self, node_provider: NodeHTTPProvider) -> None:
66
+ self.manager.node_provider = node_provider
67
+
68
+ @property
69
+ def blockchain_provider(self) -> BlockchainProvider:
70
+ return self.manager.blockchain_provider
71
+
72
+ @blockchain_provider.setter
73
+ def blockchain_provider(self, blockchain_provider: BlockchainProvider) -> None:
74
+ self.manager.blockchain_provider = blockchain_provider
dkg/manager.py ADDED
@@ -0,0 +1,64 @@
1
+ # Licensed to the Apache Software Foundation (ASF) under one
2
+ # or more contributor license agreements. See the NOTICE file
3
+ # distributed with this work for additional information
4
+ # regarding copyright ownership. The ASF licenses this file
5
+ # to you under the Apache License, Version 2.0 (the
6
+ # "License"); you may not use this file except in compliance
7
+ # with the License. You may obtain a copy of the License at
8
+
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+
18
+ from typing import Any, Type
19
+
20
+ from dkg.dataclasses import BlockchainResponseDict, NodeResponseDict
21
+ from dkg.exceptions import InvalidRequest
22
+ from dkg.providers import BlockchainProvider, NodeHTTPProvider
23
+ from dkg.utils.blockchain_request import ContractInteraction, JSONRPCRequest
24
+ from dkg.utils.node_request import NodeCall
25
+
26
+
27
+ class DefaultRequestManager:
28
+ def __init__(
29
+ self, node_provider: NodeHTTPProvider, blockchain_provider: BlockchainProvider
30
+ ):
31
+ self._node_provider = node_provider
32
+ self._blockchain_provider = blockchain_provider
33
+
34
+ @property
35
+ def node_provider(self) -> NodeHTTPProvider:
36
+ return self._node_provider
37
+
38
+ @node_provider.setter
39
+ def node_provider(self, node_provider: NodeHTTPProvider) -> None:
40
+ self._node_provider = node_provider
41
+
42
+ @property
43
+ def blockchain_provider(self) -> BlockchainProvider:
44
+ return self._blockchain_provider
45
+
46
+ @blockchain_provider.setter
47
+ def blockchain_provider(self, blockchain_provider: BlockchainProvider) -> None:
48
+ self._blockchain_provider = blockchain_provider
49
+
50
+ def blocking_request(
51
+ self,
52
+ request_type: Type[JSONRPCRequest | ContractInteraction | NodeCall],
53
+ request_params: dict[str, Any],
54
+ ) -> BlockchainResponseDict | NodeResponseDict:
55
+ if issubclass(request_type, JSONRPCRequest):
56
+ return self.blockchain_provider.make_json_rpc_request(**request_params)
57
+ elif issubclass(request_type, ContractInteraction):
58
+ return self.blockchain_provider.call_function(**request_params)
59
+ elif issubclass(request_type, NodeCall):
60
+ return self.node_provider.make_request(**request_params)
61
+ else:
62
+ raise InvalidRequest(
63
+ "Invalid Request. Manager can only process Blockchain/Node requests."
64
+ )
dkg/method.py ADDED
@@ -0,0 +1,131 @@
1
+ # Licensed to the Apache Software Foundation (ASF) under one
2
+ # or more contributor license agreements. See the NOTICE file
3
+ # distributed with this work for additional information
4
+ # regarding copyright ownership. The ASF licenses this file
5
+ # to you under the Apache License, Version 2.0 (the
6
+ # "License"); you may not use this file except in compliance
7
+ # with the License. You may obtain a copy of the License at
8
+
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+
18
+ import itertools
19
+ import re
20
+ from typing import TYPE_CHECKING, Any, Generic, Type
21
+
22
+ from dkg.exceptions import ValidationError
23
+ from dkg.types import TFunc
24
+ from dkg.utils.blockchain_request import (ContractInteraction,
25
+ ContractTransaction, JSONRPCRequest)
26
+ from dkg.utils.node_request import NodeCall
27
+ from dkg.utils.string_transformations import snake_to_camel
28
+
29
+ if TYPE_CHECKING:
30
+ from dkg.module import Module
31
+
32
+
33
+ class Method(Generic[TFunc]):
34
+ def __init__(self, action: JSONRPCRequest | ContractInteraction | NodeCall):
35
+ self.action = action
36
+
37
+ def __get__(
38
+ self, obj: "Module | None" = None, _: Type["Module"] | None = None
39
+ ) -> TFunc:
40
+ if obj is None:
41
+ raise TypeError(
42
+ "Direct calls to methods are not supported. "
43
+ "Methods must be called from a module instance, "
44
+ "usually attached to a dkg instance."
45
+ )
46
+ return obj.retrieve_caller_fn(self)
47
+
48
+ def process_args(self, *args: Any, **kwargs: Any):
49
+ match self.action:
50
+ case JSONRPCRequest():
51
+ return {"args": self._validate_and_map(self.action.args, args, kwargs)}
52
+ case ContractInteraction():
53
+ return {
54
+ "args": self._validate_and_map(self.action.args, args, kwargs),
55
+ "state_changing": isinstance(self.action, ContractTransaction),
56
+ }
57
+ case NodeCall():
58
+ path_placeholders = re.findall(r"\{([^{}]+)?\}", self.action.path)
59
+
60
+ args_in_path = 0
61
+ path_args = []
62
+ path_kwargs = {}
63
+ if len(path_placeholders) > 0:
64
+ for placeholder in path_placeholders:
65
+ if (placeholder != "") and (placeholder in kwargs.keys()):
66
+ path_kwargs[placeholder] = kwargs.pop(placeholder)
67
+ else:
68
+ if len(args) <= args_in_path:
69
+ raise ValidationError(
70
+ "Number of given arguments can't be smaller than "
71
+ "number of path placeholders"
72
+ )
73
+
74
+ if placeholder == "":
75
+ path_args.append(args[args_in_path])
76
+ else:
77
+ path_kwargs[placeholder] = args[args_in_path]
78
+
79
+ args_in_path += 1
80
+
81
+ return {
82
+ "path": self.action.path.format(*path_args, **path_kwargs),
83
+ "params": self._validate_and_map(
84
+ self.action.params, args[args_in_path:], kwargs
85
+ )
86
+ if self.action.params
87
+ else {},
88
+ "data": self._validate_and_map(
89
+ self.action.data, args[args_in_path:], kwargs
90
+ )
91
+ if self.action.data
92
+ else {},
93
+ }
94
+
95
+ case _:
96
+ return {}
97
+
98
+ def _validate_and_map(
99
+ self,
100
+ required_args: dict[str, Type] | Type,
101
+ args: list[Any],
102
+ kwargs: dict[str, Any],
103
+ ) -> dict[str, Any]:
104
+ if not isinstance(required_args, dict):
105
+ if (len(args) + len(kwargs)) != 1:
106
+ raise ValidationError("Exactly one argument must be provided.")
107
+
108
+ if len(args) == 1:
109
+ return args[0]
110
+ else:
111
+ return list(kwargs.values())[0]
112
+
113
+ if len(args) > len(required_args):
114
+ raise ValidationError(
115
+ "Number of positional arguments can't be bigger than "
116
+ "number of required arguments"
117
+ )
118
+
119
+ args_mapped = dict(zip(itertools.islice(required_args.keys(), len(args)), args))
120
+ camel_kwargs = {snake_to_camel(key): value for key, value in kwargs.items()}
121
+
122
+ processed_args = {}
123
+ processed_args.update(args_mapped)
124
+ processed_args.update(camel_kwargs)
125
+
126
+ if any(missing_params := (arg not in processed_args for arg in required_args)):
127
+ raise ValidationError(
128
+ f"Missing required arg(s): {', '.join(missing_params)}"
129
+ )
130
+
131
+ return processed_args