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.bsmbsm 这两个变量.

 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()