|
1 | 1 | '''Replace auto-generated classes with our own, where necessary. |
2 | 2 | ''' |
| 3 | +import sys |
3 | 4 |
|
4 | 5 | from . import _client, _definitions, overrides # isort:skip |
| 6 | +from .old_clients import _client as _2_9_client |
| 7 | +from .old_clients import _definitions as _2_9_definitions |
5 | 8 |
|
6 | 9 | for o in overrides.__all__: |
7 | 10 | if "Facade" not in o: |
|
10 | 13 | # the ref in _client (import shenanigans are fun!) |
11 | 14 | setattr(_definitions, o, getattr(overrides, o)) |
12 | 15 | setattr(_client, o, getattr(overrides, o)) |
| 16 | + setattr(_2_9_definitions, o, getattr(overrides, o)) |
| 17 | + setattr(_2_9_client, o, getattr(overrides, o)) |
13 | 18 | # We shouldn't be overriding Facades! |
14 | 19 | else: |
15 | 20 | raise ValueError( |
|
29 | 34 | for a in dir(o_type): |
30 | 35 | if not a.startswith('_'): |
31 | 36 | setattr(c_type, a, getattr(o_type, a)) |
| 37 | + # This unfortunately needs to be a separate loop |
| 38 | + for old_client_version in _client.OLD_CLIENTS.values(): |
| 39 | + try: |
| 40 | + c_type = getattr(old_client_version, o) |
| 41 | + except AttributeError: |
| 42 | + # Not all the _client<version> modules may have the |
| 43 | + # facade. That's okay -- we just skip over them. |
| 44 | + continue |
| 45 | + o_type = getattr(overrides, o) |
| 46 | + for a in dir(o_type): |
| 47 | + if not a.startswith('_'): |
| 48 | + setattr(c_type, a, getattr(o_type, a)) |
32 | 49 |
|
33 | 50 | from ._client import * # noqa, isort:skip |
| 51 | + |
| 52 | +class ClientModuleClass: |
| 53 | + def __init__(self): |
| 54 | + """ |
| 55 | + new_client (bool): True if we're working with juju>3.0 |
| 56 | + """ |
| 57 | + self.new_client = None |
| 58 | + self.defs = _definitions |
| 59 | + self.client_module = _client |
| 60 | + |
| 61 | + __all__ = list(set(vars().keys()) - {'__module__', '__qualname__'}) |
| 62 | + |
| 63 | + def __getattr__(self, item): |
| 64 | + if self.new_client is None: |
| 65 | + raise RuntimeError("ClientModule version is not yet set. Is it 2.9? Or is it >3.0") |
| 66 | + if 'Facade' in item: |
| 67 | + return getattr(self.client_module, item) |
| 68 | + return getattr(self.defs, item) |
| 69 | + |
| 70 | + def set_new_client(self, server_version): |
| 71 | + self.new_client = server_version.startswith('3.') |
| 72 | + if not self.new_client: |
| 73 | + self.defs = _2_9_definitions |
| 74 | + self.client_module = _2_9_client |
| 75 | + |
| 76 | +""" |
| 77 | +This is basically a hack to turn this module into a dynamic |
| 78 | +binding registry, by replacing this module object with a class |
| 79 | +instance that acts like a module in sys.modules in the runtime. |
| 80 | +
|
| 81 | +Based on the value of the 'new_client' variable |
| 82 | +(True if >3.0, False if 2.9) we dynamically change the modules |
| 83 | +from which we get the actual bindings behind the scenes. |
| 84 | +Theoretically the new_client should only be set once, but we |
| 85 | +have to keep it dynamic since there's no way for libjuju to |
| 86 | +know when and with which juju version a connection will be |
| 87 | +established. |
| 88 | +
|
| 89 | +Bindings for >3.0 are coming from _client & _definitions |
| 90 | +Bindings for 2.9 are coming from _2_9_client & _2_9_client |
| 91 | +""" |
| 92 | +sys.modules[__name__] = ClientModuleClass() |
0 commit comments