BSM Override#
Keywords: boto session manager, bsm, ses
我们有如下代码结构:
/pylib
/__init__.py
/boto_ses.py
/app_code.py
test.py
在 boto_ses.py
中, 我们有一个 BotoSessionFactory
类, 它有一个方法 ``get_workload_bsm``能获得指定的 environment 的 boto session 对象.
它还有一个 cached_property BotoSessionFactory.bsm
, 它一旦被调用过一次, 那它的值就再也不会被改变了. 这个对象是一个 shortcut, 用来获得最常用的 boto session 对象.
并且为了方便使用, 我们把 boto_ses_factory.bsm
的值赋值给了一个变量 bsm
.
1# -*- coding: utf-8 -*-
2
3import dataclasses
4from functools import cached_property
5
6
7@dataclasses.dataclass
8class BotoSesManager:
9 env_name: str
10
11
12@dataclasses.dataclass
13class BotoSessionFactory:
14 default_env_name: str = dataclasses.field(default="sbx")
15
16 def get_workload_bsm(self, env_name: str) -> BotoSesManager:
17 return BotoSesManager(env_name)
18
19 @cached_property
20 def bsm(self) -> BotoSesManager:
21 return self.get_workload_bsm(env_name=self.default_env_name)
22
23
24boto_ses_factory = BotoSessionFactory()
25bsm = boto_ses_factory.bsm
在 app_code.py
的业务逻辑代码中, 我们会 import boto_ses
并引用 boto_ses_factory.bsm
和 bsm
这两个变量.
1# -*- coding: utf-8 -*-
2
3
4from .boto_ses import boto_ses_factory, bsm
5
6
7def print_boto_ses_factory_bsm():
8 print(f"{boto_ses_factory.bsm = }")
9
10
11def print_bsm():
12 print(f"{bsm = }")
现在问题来了, 我们在开发过程中为了方便测试有这个需求, 我们需要能有临时将这个 bsm 的对象替换为指向另一个 environment 的对象. 但是业务逻辑代码已经引用了这个变量, 并且这个变量已经被缓存了. 我们该怎么做呢?
请阅读下面的测试代码中的解决方案以及注释.
1# -*- coding: utf-8 -*-
2
3from pylib import boto_ses
4
5# ------------------------------------------------------------------------------
6# 你可以在 import 业务逻辑代码之前 (注意必须 import 之前, 不然很多逻辑会不可控)
7# 使用下面的代码来替换 cached property
8#
9# 如果正常使用业务代码 (comment out 这个代码块), 输出结果为:
10# === app code ===
11# boto_ses_factory.bsm = BotoSesManager(env_name='prd')
12# bsm = BotoSesManager(env_name='prd')
13#
14# 如果使用下面的代码块, 输出结果为:
15# === app code ===
16# boto_ses_factory.bsm = BotoSesManager(env_name='sbx')
17# bsm = BotoSesManager(env_name='sbx')
18# ------------------------------------------------------------------------------
19# cached_property 的本质是一个特殊属性, 你可以用 del 来删除它, 然后通过修改这个 cached_property
20# 的工厂函数逻辑中所使用的变量的值, 然后再调用一次这个 cached_property, 之后就是新的值了.
21del boto_ses.boto_ses_factory.bsm
22boto_ses.boto_ses_factory.default_env_name = "prd"
23# 而 bsm 本质上是一个模块级别的 variable, 是一个 mutable 的 singleton,
24# 你只要 import 这个模块, 然后用 ${module_name}.${variable_name} 的方式来修改它的值就可以了.
25boto_ses.bsm = boto_ses.boto_ses_factory.get_workload_bsm(env_name="prd")
26
27# ------------------------------------------------------------------------------
28# 调用业务逻辑代码
29# ------------------------------------------------------------------------------
30print("=== app code ===")
31from pylib.app_code import print_boto_ses_factory_bsm, print_bsm
32
33print_boto_ses_factory_bsm()
34print_bsm()