|
1 | | -""" |
2 | | -Polywrap Python Client. |
3 | | -
|
4 | | -The ClientConfigBuilder Package provides a simple interface for building a ClientConfig object, |
5 | | -which is used to configure the Polywrap Client and its sub-components. You can use the |
6 | | -ClientConfigBuilder to set the wrappers, packages, and other configuration options for the |
7 | | -Polywrap Client. |
8 | | -
|
9 | | -docs.polywrap.io |
10 | | -Copyright 2022 Polywrap |
11 | | -""" |
12 | | - |
13 | | -from abc import ABC, abstractmethod |
14 | | -from dataclasses import dataclass |
15 | | -from typing import Any, Dict, List, Union |
16 | | - |
17 | | -from polywrap_core import Env, Uri, UriPackage, UriWrapper |
18 | | - |
19 | | -UriResolverLike = Union[Uri, UriPackage, UriWrapper, List["UriResolverLike"]] |
20 | | - |
21 | | - |
22 | | -@dataclass(slots=True, kw_only=True) |
23 | | -class ClientConfig: |
24 | | - """ |
25 | | - Abstract class used to configure the polywrap client before it executes a call. |
26 | | -
|
27 | | - The ClientConfig class is created and modified with the ClientConfigBuilder module. |
28 | | - """ |
29 | | - |
30 | | - envs: Dict[Uri, Dict[str, Any]] |
31 | | - interfaces: Dict[Uri, List[Uri]] |
32 | | - wrappers: List[UriWrapper] |
33 | | - packages: List[UriPackage] |
34 | | - resolver: List[UriResolverLike] |
35 | | - redirects: Dict[Uri, Uri] |
36 | | - |
37 | | - |
38 | | -class BaseClientConfigBuilder(ABC): |
39 | | - """ |
40 | | - An abstract base class of the `ClientConfigBuilder`. |
41 | | -
|
42 | | - It uses the ABC module to define the methods that can be used to |
43 | | - configure the `ClientConfig` object. |
| 1 | +"""This module provides a simple builder for building a ClientConfig object.""" |
| 2 | + |
| 3 | +from typing import Any, Dict, List, Optional, cast |
| 4 | + |
| 5 | +from polywrap_core import ( |
| 6 | + Env, |
| 7 | + Uri, |
| 8 | + UriPackage, |
| 9 | + UriWrapper, |
| 10 | + UriPackageOrWrapper, |
| 11 | + Wrapper, |
| 12 | + WrapPackage, |
| 13 | + UriResolver, |
| 14 | +) |
| 15 | +from polywrap_client import PolywrapClientConfig |
| 16 | + |
| 17 | +from polywrap_uri_resolvers import ( |
| 18 | + RecursiveResolver, |
| 19 | + RequestSynchronizerResolver, |
| 20 | + WrapperCacheResolver, |
| 21 | + PackageToWrapperResolver, |
| 22 | + StaticResolver, |
| 23 | + ExtendableUriResolver, |
| 24 | + InMemoryWrapperCache, |
| 25 | + UriResolverAggregator, |
| 26 | +) |
| 27 | + |
| 28 | +from .types import BuilderConfig, BuildOptions |
| 29 | + |
| 30 | + |
| 31 | +class ClientConfigBuilder: |
| 32 | + """Defines a simple builder for building a ClientConfig object. |
| 33 | +
|
| 34 | + The ClientConfigBuilder is used to create a ClientConfig object, which is used to configure |
| 35 | + the Polywrap Client and its sub-components. ClientConfigBuilder provides a simple interface |
| 36 | + for setting the redirects, wrappers, packages, and other configuration options for the Polywrap Client. |
44 | 37 | """ |
45 | 38 |
|
46 | 39 | def __init__(self): |
47 | 40 | """Initialize the builder's config attributes with empty values.""" |
48 | | - self.config = ClientConfig( |
49 | | - envs={}, interfaces={}, resolver=[], wrappers=[], packages=[], redirects={} |
| 41 | + self.config = BuilderConfig( |
| 42 | + envs={}, interfaces={}, resolvers=[], wrappers={}, packages={}, redirects={} |
50 | 43 | ) |
51 | 44 |
|
52 | | - @abstractmethod |
53 | | - def build(self) -> ClientConfig: |
54 | | - """Return a sanitized config object from the builder's config.""" |
| 45 | + def build(self, options: Optional[BuildOptions] = None) -> PolywrapClientConfig: |
| 46 | + """Build the ClientConfig object from the builder's config.""" |
| 47 | + resolver = ( |
| 48 | + options.resolver |
| 49 | + if options and options.resolver |
| 50 | + else RecursiveResolver( |
| 51 | + RequestSynchronizerResolver( |
| 52 | + WrapperCacheResolver( |
| 53 | + PackageToWrapperResolver( |
| 54 | + UriResolverAggregator( |
| 55 | + [ |
| 56 | + StaticResolver(self.config.redirects), |
| 57 | + StaticResolver(self.config.wrappers), |
| 58 | + StaticResolver(self.config.packages), |
| 59 | + *self.config.resolvers, |
| 60 | + ExtendableUriResolver(), |
| 61 | + ] |
| 62 | + ) |
| 63 | + ), |
| 64 | + options.wrapper_cache |
| 65 | + if options and options.wrapper_cache |
| 66 | + else InMemoryWrapperCache(), |
| 67 | + ) |
| 68 | + ) |
| 69 | + ) |
| 70 | + ) |
55 | 71 |
|
56 | | - def add(self, new_config: ClientConfig): |
57 | | - """ |
58 | | - Return a sanitized config object from the builder's config. |
| 72 | + return PolywrapClientConfig( |
| 73 | + envs=self.config.envs, |
| 74 | + interfaces=self.config.interfaces, |
| 75 | + resolver=resolver, |
| 76 | + ) |
59 | 77 |
|
60 | | - Input is a partial `ClientConfig` object. |
61 | | - """ |
62 | | - if new_config.envs: |
63 | | - self.config.envs.update(new_config.envs) |
64 | | - if new_config.interfaces: |
65 | | - self.config.interfaces.update(new_config.interfaces) |
66 | | - if new_config.resolver: |
67 | | - self.config.resolver.extend(new_config.resolver) |
68 | | - if new_config.wrappers: |
69 | | - self.config.wrappers.extend(new_config.wrappers) |
70 | | - if new_config.packages: |
71 | | - self.config.packages.extend(new_config.packages) |
| 78 | + def add(self, config: BuilderConfig): |
| 79 | + """Add the values from the given config to the builder's config.""" |
| 80 | + if config.envs: |
| 81 | + self.config.envs.update(config.envs) |
| 82 | + if config.interfaces: |
| 83 | + self.config.interfaces.update(config.interfaces) |
| 84 | + if config.redirects: |
| 85 | + self.config.redirects.update(config.redirects) |
| 86 | + if config.resolvers: |
| 87 | + self.config.resolvers.extend(config.resolvers) |
| 88 | + if config.wrappers: |
| 89 | + self.config.wrappers.update(config.wrappers) |
| 90 | + if config.packages: |
| 91 | + self.config.packages.update(config.packages) |
72 | 92 | return self |
73 | 93 |
|
74 | 94 | def get_envs(self) -> Dict[Uri, Dict[str, Any]]: |
75 | | - """Return the envs dictionary from the builder's config.""" |
| 95 | + """Return the envs from the builder's config.""" |
76 | 96 | return self.config.envs |
77 | 97 |
|
78 | | - def set_env(self, env: Env, uri: Uri): |
79 | | - """Set the envs dictionary in the builder's config, overiding any existing values.""" |
| 98 | + def set_env(self, uri: Uri, env: Env): |
| 99 | + """Set the env by uri in the builder's config, overiding any existing values.""" |
80 | 100 | self.config.envs[uri] = env |
81 | 101 | return self |
82 | 102 |
|
83 | | - def add_env(self, env: Env, uri: Uri): |
84 | | - """ |
85 | | - Add an environment (in the form of an `Env`) for a given uri. |
| 103 | + def set_envs(self, uri_envs: Dict[Uri, Env]): |
| 104 | + """Set the envs in the builder's config, overiding any existing values.""" |
| 105 | + self.config.envs.update(uri_envs) |
| 106 | + return self |
86 | 107 |
|
87 | | - Note it is not overwriting existing environments, unless the |
88 | | - env key already exists in the environment, then it will overwrite the existing value. |
| 108 | + def add_env(self, uri: Uri, env: Env): |
| 109 | + """Add an env for the given uri. |
| 110 | +
|
| 111 | + If an Env is already associated with the uri, it is modified. |
89 | 112 | """ |
90 | | - if uri in self.config.envs.keys(): |
91 | | - for key in env.keys(): |
| 113 | + if self.config.envs.get(uri): |
| 114 | + for key in self.config.envs[uri]: |
92 | 115 | self.config.envs[uri][key] = env[key] |
93 | 116 | else: |
94 | 117 | self.config.envs[uri] = env |
95 | 118 | return self |
96 | 119 |
|
97 | | - def add_envs(self, envs: List[Env], uri: Uri = None): |
98 | | - """Add a list of environments (each in the form of an `Env`) for a given uri.""" |
99 | | - for env in envs: |
100 | | - self.add_env(env, uri) |
| 120 | + def add_envs(self, uri_envs: Dict[Uri, Env]): |
| 121 | + """Add a list of envs to the builder's config.""" |
| 122 | + for uri, env in uri_envs.items(): |
| 123 | + self.add_env(uri, env) |
101 | 124 | return self |
102 | 125 |
|
103 | 126 | def add_interface_implementations( |
104 | 127 | self, interface_uri: Uri, implementations_uris: List[Uri] |
105 | 128 | ): |
106 | | - """Add a list of implementations (each in the form of an `Uri`) for a given interface.""" |
107 | | - if interface_uri is None: |
108 | | - raise ValueError() |
| 129 | + """Add a list of implementation URIs for the given interface URI to the builder's config.""" |
109 | 130 | if interface_uri in self.config.interfaces.keys(): |
110 | | - self.config.interfaces[interface_uri] = ( |
111 | | - self.config.interfaces[interface_uri] + implementations_uris |
112 | | - ) |
| 131 | + self.config.interfaces[interface_uri].extend(implementations_uris) |
113 | 132 | else: |
114 | 133 | self.config.interfaces[interface_uri] = implementations_uris |
115 | 134 | return self |
116 | 135 |
|
117 | | - def add_wrapper(self, wrapper_uri: UriWrapper): |
118 | | - """Add a wrapper to the list of wrappers.""" |
119 | | - self.config.wrappers.append(wrapper_uri) |
| 136 | + def add_wrapper(self, uri: Uri, wrapper: Wrapper[UriPackageOrWrapper]): |
| 137 | + """Add a wrapper by its URI to the builder's config""" |
| 138 | + self.config.wrappers[uri] = wrapper |
120 | 139 | return self |
121 | 140 |
|
122 | | - def add_wrappers(self, wrappers_uris: List[UriWrapper]): |
123 | | - """Add a list of wrappers to the list of wrappers.""" |
124 | | - for wrapper_uri in wrappers_uris: |
125 | | - self.add_wrapper(wrapper_uri) |
| 141 | + def add_wrappers(self, uri_wrappers: List[UriWrapper[UriPackageOrWrapper]]): |
| 142 | + """Add a list of URI-wrapper pairs to the builder's config.""" |
| 143 | + for uri_wrapper in uri_wrappers: |
| 144 | + self.add_wrapper(cast(Uri, uri_wrapper), uri_wrapper.wrapper) |
126 | 145 | return self |
127 | 146 |
|
128 | | - def remove_wrapper(self, wrapper_uri: UriWrapper): |
129 | | - """Remove a wrapper from the list of wrappers.""" |
130 | | - self.config.wrappers.remove(wrapper_uri) |
| 147 | + def remove_wrapper(self, uri: Uri): |
| 148 | + """Remove a wrapper by its URI from the builder's config.""" |
| 149 | + del self.config.wrappers[uri] |
131 | 150 | return self |
132 | 151 |
|
133 | | - def set_package(self, uri_package: UriPackage): |
134 | | - """Set the package in the builder's config, overiding any existing values.""" |
135 | | - self.config.packages = [uri_package] |
| 152 | + def remove_wrappers(self, uris: List[Uri]): |
| 153 | + """Remove a list of wrappers by its URIs""" |
| 154 | + for uri in uris: |
| 155 | + self.remove_wrapper(uri) |
136 | 156 | return self |
137 | 157 |
|
138 | | - def add_package(self, uri_package: UriPackage): |
139 | | - """Add a package to the list of packages.""" |
140 | | - self.config.packages.append(uri_package) |
| 158 | + def add_package(self, uri: Uri, package: WrapPackage[UriPackageOrWrapper]): |
| 159 | + """Add a package by its URI to the builder's config.""" |
| 160 | + self.config.packages[uri] = package |
141 | 161 | return self |
142 | 162 |
|
143 | | - def add_packages(self, uri_packages: List[UriPackage]): |
144 | | - """Add a list of packages to the list of packages.""" |
| 163 | + def add_packages(self, uri_packages: List[UriPackage[UriPackageOrWrapper]]): |
| 164 | + """Add a list of URI-package pairs to the builder's config.""" |
145 | 165 | for uri_package in uri_packages: |
146 | | - self.add_package(uri_package) |
| 166 | + self.add_package(cast(Uri, uri_package), uri_package.package) |
147 | 167 | return self |
148 | 168 |
|
149 | | - def remove_package(self, uri_package: UriPackage): |
150 | | - """Remove a package from the list of packages.""" |
151 | | - self.config.packages.remove(uri_package) |
| 169 | + def remove_package(self, uri: Uri): |
| 170 | + """Remove a package by its URI from the builder's config.""" |
| 171 | + del self.config.packages[uri] |
152 | 172 | return self |
153 | 173 |
|
154 | | - def set_resolver(self, uri_resolver: UriResolverLike): |
155 | | - """Set a single resolver for the `ClientConfig` object.""" |
156 | | - self.config.resolver = [uri_resolver] |
| 174 | + def remove_packages(self, uris: List[Uri]): |
| 175 | + """Remove a list of packages by its URIs from the builder's config.""" |
| 176 | + for uri in uris: |
| 177 | + self.remove_package(uri) |
157 | 178 | return self |
158 | 179 |
|
159 | | - def add_resolver(self, resolver: UriResolverLike): |
160 | | - """Add a resolver to the list of resolvers.""" |
161 | | - if self.config.resolver is None: |
162 | | - raise ValueError( |
163 | | - "This resolver is not set. Please set a resolver before adding resolvers." |
164 | | - ) |
165 | | - self.config.resolver.append(resolver) |
| 180 | + def add_resolver(self, resolver: UriResolver): |
| 181 | + """Add a resolver to the builder's config.""" |
| 182 | + self.config.resolvers.append(resolver) |
166 | 183 | return self |
167 | 184 |
|
168 | | - def add_resolvers(self, resolvers_list: List[UriResolverLike]): |
169 | | - """Add a list of resolvers to the list of resolvers.""" |
| 185 | + def add_resolvers(self, resolvers_list: List[UriResolver]): |
| 186 | + """Add a list of resolvers to the builder's config.""" |
170 | 187 | for resolver in resolvers_list: |
171 | 188 | self.add_resolver(resolver) |
172 | 189 | return self |
173 | 190 |
|
174 | | - def set_uri_redirect(self, uri_from: Uri, uri_to: Uri): |
175 | | - """ |
176 | | - Set an uri redirect, from one uri to another. |
177 | | -
|
178 | | - If there was a redirect previously listed, it's changed to the new one. |
179 | | - """ |
180 | | - self.config.redirects[uri_from] = uri_to |
| 191 | + def add_redirect(self, from_uri: Uri, to_uri: Uri): |
| 192 | + """Add a URI redirect from `from_uri` to `to_uri`.""" |
| 193 | + self.config.redirects[from_uri] = to_uri |
181 | 194 | return self |
182 | 195 |
|
183 | | - def remove_uri_redirect(self, uri_from: Uri): |
184 | | - """Remove an uri redirect, from one uri to another.""" |
185 | | - self.config.redirects.pop(uri_from) |
| 196 | + def remove_redirect(self, from_uri: Uri): |
| 197 | + """Remove a URI redirect by `from_uri`.""" |
| 198 | + del self.config.redirects[from_uri] |
186 | 199 | return self |
187 | 200 |
|
188 | | - def set_uri_redirects(self, redirects: List[Dict[Uri, Uri]]): |
189 | | - """Set various Uri redirects from a list simultaneously.""" |
190 | | - count = 0 |
191 | | - for redir in redirects: |
192 | | - for key, value in redir.items(): |
193 | | - self.set_uri_redirect(key, value) |
194 | | - count += 1 |
| 201 | + def add_redirects(self, redirects: Dict[Uri, Uri]): |
| 202 | + """Add a list of URI redirects to the builder's config.""" |
| 203 | + self.config.redirects.update(redirects) |
195 | 204 | return self |
196 | | - |
197 | | - |
198 | | -class ClientConfigBuilder(BaseClientConfigBuilder): |
199 | | - """ |
200 | | - A class that can build the `ClientConfig` object. |
201 | | -
|
202 | | - This class inherits the `BaseClientConfigBuilder` class, |
203 | | - and adds the `build` method |
204 | | - """ |
205 | | - |
206 | | - def build(self) -> ClientConfig: |
207 | | - """Return a sanitized config object from the builder's config.""" |
208 | | - return self.config |
0 commit comments