apollo-pydantic


Nameapollo-pydantic JSON
Version 0.0.2 PyPI version JSON
download
home_pageNone
Summaryapollo client wrapped by pydantic
upload_time2024-07-15 03:07:03
maintainerNone
docs_urlNone
authorNone
requires_python>=3.10
licenseNone
keywords pydantic apollo config distributed configuration settings microservice
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # apollo_pydantic
apollo_pydantic包是一个[apollo](https://www.apolloconfig.com/)的客户端封装,使用pydantic_settings的类型系统自动进行配置解析和类型转换,可以方便的使用apollo配置,可以自动或者手动同步配置。
pydantic_settings详情见[pydantic_settings](https://docs.pydantic.dev/latest/concepts/pydantic_settings/)
当使用apollo作为微服务配置中心时,推荐使用apollo_pydantic。


## 如何安装
`apollo_pydantic`已上传至pypi,可以通过如下命令安装
```bash
pip install apollo_pydantic
```

## 注意事项
1. 建议使用一个`Base`类作为配置类基类,设置apollo的相关链接参数。当使用多个appid和cluster时,需要配置多个基类
2. 每个设置类对应一个namespace, 继承同一个配置基类下的配置类namespace不允许重复
3. 每个设置类对应一个label, 用于apollo的灰度发布使用的label
```python
class Base(ApolloSettings):
    model_config = ApolloSettingsConfigDict(
        # 官方演示地址
        config_server='http://81.68.181.139:8080',
        appid='0001234',
        cluster='dev',
        secret_key='0398e769780c4e6399d9e6f73910e155' # if set
    )

class ApolloSettingsModel(Base):
    __namespace__ = 'application'
    __label__ = None

    ...
```
4. 支持嵌套的配置项,但是要注意嵌套配置项需要继承自`pydantic.BaseModel`,并且要在根配置类前定义, 否则可能有解析失败的情况,具体详情见[pydantic_settings](https://docs.pydantic.dev/latest/concepts/pydantic_settings/)
```python
class Base(ApolloSettings):
    ...

class Nested(BaseModel):
    some_name: str

class ApolloSettingsModel(Base):
    __namespace__ = 'application'

    # 配置项 nested.some_name = xxx
    nested: Nested

await ApolloSettingsModel.refresh() # 主动刷新
print(ApolloSettingsModel().nested.some_name) # xxx
```

5. 支持配置项的`validation_alias`和`alias`属性, 该属性可以为配置项指定别名,如配置项`alias_name = some_value`可以设置`validation_alias = 'alias_name'`或者`alias = 'alias_name'`, 该字段会解析为`some_value`. 注意设置别名时,不要包含`.`符号, 因为`.`符号会被解析为嵌套的配置项
apollo配置如下:
```
some_name = xxx
```
python代码如下:
```python
class Base(ApolloSettings):
    ...
class ApolloSettingsModel(Base):
    __namespace__ = 'application'
    __label__ = None
    # 配置项 some_name = xxx
    some_value: str = Field(alias='some_name')

await ApolloSettingsModel.refresh() # 主动刷新
print(ApolloSettingsModel().some_value) # xxx
```
慎用`AliasPath`, 除非精通`pydantic_settings`的使用。
6. 支持自定义`Field`,相关校验参见[pydantic_settings](https://docs.pydantic.dev/latest/api/fields/)
7. 支持数组类型配置,如配置项`some_name[0] = xxx`和`some_name[1] = yyy`, 该字段会解析为`['xxx', 'yyy']`, 该种方式目前不支持数组中嵌套配置项类。如要使用这种配置项可以直接使用json来实现
```python
class Base(ApolloSettings):
    ...
class ApolloSettingsModel(Base):
    __namespace__ = 'application'
    __label__ = None
    # 配置项
    # some_name[0] = xxx
    # some_name[1] = yyy
    some_name: List[str]

    # 配置项
    # some_value = ["xxx", "yyy"]
    some_json_value: List[str]

await ApolloSettingsModel.refresh() # 主动刷新
print(ApolloSettingsModel().some_name) # ['xxx', 'yyy']
print(ApolloSettingsModel().some_json_value) # ['xxx', 'yyy']
8. 暂不支持同步线程的方式同步配置,后续会有同步线程的支持
```
## 例子
例子详见`apollo_pydantic/examples`目录。
apollo的官方演示地址为`http://81.68.181.139`
### 使用pydantic_settings
```python
import asyncio
import datetime
from typing import List, Optional

from pydantic import AliasPath, BaseModel, Field, HttpUrl

from apollo_pydantic import (ApolloSettings, ApolloSettingsConfigDict,
                             enable_debug)


class Base(ApolloSettings):
    model_config = ApolloSettingsConfigDict(
        # 官方演示地址
        config_server='http://81.68.181.139:8080',
        appid='0001234',
        cluster='dev',
        secret_key='0398e769780c4e6399d9e6f73910e155' # if set
    )

class B(BaseModel):
    bb: List[int]
    cc: int = Field(validation_alias=AliasPath('bb', 0))

class ApolloSettingsModel(Base):
    __namespace__ = 'application'
    __label__ = None

    # apollo 的官方演示地址
    url: HttpUrl = 'http://81.68.181.139:8080'
    key1: str
    white_list: List[int] = Field(default_factory=lambda: ['1', '2', '3'])
    port: int
    redis_port: int
    is_encrypted: bool
    # a.bb[0] = 123
    some_value: Optional[str] = Field(validation_alias=AliasPath('a', 'bb', 0)) # 这里使用AliasPath,需要该配置类必须要有`a`字段
    # c-dd = xxx
    c_dd: str = Field(alias='c-dd')
    a: B
    start: datetime.timedelta = 1
    arr: List

class Abc(Base):
    __label__ = None
    __namespace__ = 'aUQTr9'

    aaa: str = Field(alias='abc')
    abc: int

async def main():
    # enable_debug()
    # 自动更新
    await ApolloSettings.start()
    while True:
        # 手动更新
        # await ApolloSettingsModel.refresh()
        print(ApolloSettingsModel(), datetime.datetime.now())
        print(Abc(), '###' * 20)
        await asyncio.sleep(10)

if __name__ == '__main__':
    # apollo配置如下
    """
    key1 = value1
    white_list = [1, 2, 3,"5",3734985]
    port = 3306
    redis_port = 6379
    is_encrypted = true
    123 = fsfg范德萨gf
    xxx = {"业务编号":"123","通道":"123"} # ignore
    a.bb[0] = 1
    a.bb[1] = 2
    c-dd = fgfg
    arr[0] = 123
    arr[1] = 2
    """
    enable_debug()
    print('##' * 20)
    asyncio.run(main())
```
# 集成fastapi
```python
from fastapi import FastAPI
...
# some imports

class Base(ApolloSettings):
    model_config = ApolloSettingsConfigDict(
        # 官方演示地址
        config_server='http://81.68.181.139:8080',
        appid='0001234',
        cluster='dev',
        secret_key='0398e769780c4e6399d9e6f73910e155' # if set
    )
...
# define your settings

async def sync_settings(app: FastAPI):
    # 自动同步
    await ApolloSettings.start()
    yield app
    await ApolloSettings.stop()

app = FastAPI(lifespan=sync_settings)

if __name__ == '__main__':
    import uvicorn
    uvicorn.run(app, host='0.0.0.0', port=8000)

```
# 功能
- 自动同步配置

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "apollo-pydantic",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.10",
    "maintainer_email": null,
    "keywords": "pydantic, apollo, config, distributed, configuration, settings, microservice",
    "author": null,
    "author_email": "ryanrain2016 <holidaylover2010@gmail.com>",
    "download_url": "https://files.pythonhosted.org/packages/d2/2e/458cb6542e8333ca13ab3ba13e9ca03279c067fbc48c95c7248b5df56f81/apollo_pydantic-0.0.2.tar.gz",
    "platform": null,
    "description": "# apollo_pydantic\r\napollo_pydantic\u5305\u662f\u4e00\u4e2a[apollo](https://www.apolloconfig.com/)\u7684\u5ba2\u6237\u7aef\u5c01\u88c5\uff0c\u4f7f\u7528pydantic_settings\u7684\u7c7b\u578b\u7cfb\u7edf\u81ea\u52a8\u8fdb\u884c\u914d\u7f6e\u89e3\u6790\u548c\u7c7b\u578b\u8f6c\u6362\uff0c\u53ef\u4ee5\u65b9\u4fbf\u7684\u4f7f\u7528apollo\u914d\u7f6e\uff0c\u53ef\u4ee5\u81ea\u52a8\u6216\u8005\u624b\u52a8\u540c\u6b65\u914d\u7f6e\u3002\r\npydantic_settings\u8be6\u60c5\u89c1[pydantic_settings](https://docs.pydantic.dev/latest/concepts/pydantic_settings/)\r\n\u5f53\u4f7f\u7528apollo\u4f5c\u4e3a\u5fae\u670d\u52a1\u914d\u7f6e\u4e2d\u5fc3\u65f6\uff0c\u63a8\u8350\u4f7f\u7528apollo_pydantic\u3002\r\n\r\n\r\n## \u5982\u4f55\u5b89\u88c5\r\n`apollo_pydantic`\u5df2\u4e0a\u4f20\u81f3pypi\uff0c\u53ef\u4ee5\u901a\u8fc7\u5982\u4e0b\u547d\u4ee4\u5b89\u88c5\r\n```bash\r\npip install apollo_pydantic\r\n```\r\n\r\n## \u6ce8\u610f\u4e8b\u9879\r\n1. \u5efa\u8bae\u4f7f\u7528\u4e00\u4e2a`Base`\u7c7b\u4f5c\u4e3a\u914d\u7f6e\u7c7b\u57fa\u7c7b\uff0c\u8bbe\u7f6eapollo\u7684\u76f8\u5173\u94fe\u63a5\u53c2\u6570\u3002\u5f53\u4f7f\u7528\u591a\u4e2aappid\u548ccluster\u65f6\uff0c\u9700\u8981\u914d\u7f6e\u591a\u4e2a\u57fa\u7c7b\r\n2. \u6bcf\u4e2a\u8bbe\u7f6e\u7c7b\u5bf9\u5e94\u4e00\u4e2anamespace\uff0c \u7ee7\u627f\u540c\u4e00\u4e2a\u914d\u7f6e\u57fa\u7c7b\u4e0b\u7684\u914d\u7f6e\u7c7bnamespace\u4e0d\u5141\u8bb8\u91cd\u590d\r\n3. \u6bcf\u4e2a\u8bbe\u7f6e\u7c7b\u5bf9\u5e94\u4e00\u4e2alabel\uff0c \u7528\u4e8eapollo\u7684\u7070\u5ea6\u53d1\u5e03\u4f7f\u7528\u7684label\r\n```python\r\nclass Base(ApolloSettings):\r\n    model_config = ApolloSettingsConfigDict(\r\n        # \u5b98\u65b9\u6f14\u793a\u5730\u5740\r\n        config_server='http://81.68.181.139:8080',\r\n        appid='0001234',\r\n        cluster='dev',\r\n        secret_key='0398e769780c4e6399d9e6f73910e155' # if set\r\n    )\r\n\r\nclass ApolloSettingsModel(Base):\r\n    __namespace__ = 'application'\r\n    __label__ = None\r\n\r\n    ...\r\n```\r\n4. \u652f\u6301\u5d4c\u5957\u7684\u914d\u7f6e\u9879\uff0c\u4f46\u662f\u8981\u6ce8\u610f\u5d4c\u5957\u914d\u7f6e\u9879\u9700\u8981\u7ee7\u627f\u81ea`pydantic.BaseModel`,\u5e76\u4e14\u8981\u5728\u6839\u914d\u7f6e\u7c7b\u524d\u5b9a\u4e49\uff0c \u5426\u5219\u53ef\u80fd\u6709\u89e3\u6790\u5931\u8d25\u7684\u60c5\u51b5,\u5177\u4f53\u8be6\u60c5\u89c1[pydantic_settings](https://docs.pydantic.dev/latest/concepts/pydantic_settings/)\r\n```python\r\nclass Base(ApolloSettings):\r\n    ...\r\n\r\nclass Nested(BaseModel):\r\n    some_name: str\r\n\r\nclass ApolloSettingsModel(Base):\r\n    __namespace__ = 'application'\r\n\r\n    # \u914d\u7f6e\u9879 nested.some_name = xxx\r\n    nested: Nested\r\n\r\nawait ApolloSettingsModel.refresh() # \u4e3b\u52a8\u5237\u65b0\r\nprint(ApolloSettingsModel().nested.some_name) # xxx\r\n```\r\n\r\n5. \u652f\u6301\u914d\u7f6e\u9879\u7684`validation_alias`\u548c`alias`\u5c5e\u6027\uff0c \u8be5\u5c5e\u6027\u53ef\u4ee5\u4e3a\u914d\u7f6e\u9879\u6307\u5b9a\u522b\u540d\uff0c\u5982\u914d\u7f6e\u9879`alias_name = some_value`\u53ef\u4ee5\u8bbe\u7f6e`validation_alias = 'alias_name'`\u6216\u8005`alias = 'alias_name'`\uff0c \u8be5\u5b57\u6bb5\u4f1a\u89e3\u6790\u4e3a`some_value`. \u6ce8\u610f\u8bbe\u7f6e\u522b\u540d\u65f6\uff0c\u4e0d\u8981\u5305\u542b`.`\u7b26\u53f7\uff0c \u56e0\u4e3a`.`\u7b26\u53f7\u4f1a\u88ab\u89e3\u6790\u4e3a\u5d4c\u5957\u7684\u914d\u7f6e\u9879\r\napollo\u914d\u7f6e\u5982\u4e0b:\r\n```\r\nsome_name = xxx\r\n```\r\npython\u4ee3\u7801\u5982\u4e0b:\r\n```python\r\nclass Base(ApolloSettings):\r\n    ...\r\nclass ApolloSettingsModel(Base):\r\n    __namespace__ = 'application'\r\n    __label__ = None\r\n    # \u914d\u7f6e\u9879 some_name = xxx\r\n    some_value: str = Field(alias='some_name')\r\n\r\nawait ApolloSettingsModel.refresh() # \u4e3b\u52a8\u5237\u65b0\r\nprint(ApolloSettingsModel().some_value) # xxx\r\n```\r\n\u614e\u7528`AliasPath`, \u9664\u975e\u7cbe\u901a`pydantic_settings`\u7684\u4f7f\u7528\u3002\r\n6. \u652f\u6301\u81ea\u5b9a\u4e49`Field`\uff0c\u76f8\u5173\u6821\u9a8c\u53c2\u89c1[pydantic_settings](https://docs.pydantic.dev/latest/api/fields/)\r\n7. \u652f\u6301\u6570\u7ec4\u7c7b\u578b\u914d\u7f6e\uff0c\u5982\u914d\u7f6e\u9879`some_name[0] = xxx`\u548c`some_name[1] = yyy`\uff0c \u8be5\u5b57\u6bb5\u4f1a\u89e3\u6790\u4e3a`['xxx', 'yyy']`, \u8be5\u79cd\u65b9\u5f0f\u76ee\u524d\u4e0d\u652f\u6301\u6570\u7ec4\u4e2d\u5d4c\u5957\u914d\u7f6e\u9879\u7c7b\u3002\u5982\u8981\u4f7f\u7528\u8fd9\u79cd\u914d\u7f6e\u9879\u53ef\u4ee5\u76f4\u63a5\u4f7f\u7528json\u6765\u5b9e\u73b0\r\n```python\r\nclass Base(ApolloSettings):\r\n    ...\r\nclass ApolloSettingsModel(Base):\r\n    __namespace__ = 'application'\r\n    __label__ = None\r\n    # \u914d\u7f6e\u9879\r\n    # some_name[0] = xxx\r\n    # some_name[1] = yyy\r\n    some_name: List[str]\r\n\r\n    # \u914d\u7f6e\u9879\r\n    # some_value = [\"xxx\", \"yyy\"]\r\n    some_json_value: List[str]\r\n\r\nawait ApolloSettingsModel.refresh() # \u4e3b\u52a8\u5237\u65b0\r\nprint(ApolloSettingsModel().some_name) # ['xxx', 'yyy']\r\nprint(ApolloSettingsModel().some_json_value) # ['xxx', 'yyy']\r\n8. \u6682\u4e0d\u652f\u6301\u540c\u6b65\u7ebf\u7a0b\u7684\u65b9\u5f0f\u540c\u6b65\u914d\u7f6e\uff0c\u540e\u7eed\u4f1a\u6709\u540c\u6b65\u7ebf\u7a0b\u7684\u652f\u6301\r\n```\r\n## \u4f8b\u5b50\r\n\u4f8b\u5b50\u8be6\u89c1`apollo_pydantic/examples`\u76ee\u5f55\u3002\r\napollo\u7684\u5b98\u65b9\u6f14\u793a\u5730\u5740\u4e3a`http://81.68.181.139`\r\n### \u4f7f\u7528pydantic_settings\r\n```python\r\nimport asyncio\r\nimport datetime\r\nfrom typing import List, Optional\r\n\r\nfrom pydantic import AliasPath, BaseModel, Field, HttpUrl\r\n\r\nfrom apollo_pydantic import (ApolloSettings, ApolloSettingsConfigDict,\r\n                             enable_debug)\r\n\r\n\r\nclass Base(ApolloSettings):\r\n    model_config = ApolloSettingsConfigDict(\r\n        # \u5b98\u65b9\u6f14\u793a\u5730\u5740\r\n        config_server='http://81.68.181.139:8080',\r\n        appid='0001234',\r\n        cluster='dev',\r\n        secret_key='0398e769780c4e6399d9e6f73910e155' # if set\r\n    )\r\n\r\nclass B(BaseModel):\r\n    bb: List[int]\r\n    cc: int = Field(validation_alias=AliasPath('bb', 0))\r\n\r\nclass ApolloSettingsModel(Base):\r\n    __namespace__ = 'application'\r\n    __label__ = None\r\n\r\n    # apollo \u7684\u5b98\u65b9\u6f14\u793a\u5730\u5740\r\n    url: HttpUrl = 'http://81.68.181.139:8080'\r\n    key1: str\r\n    white_list: List[int] = Field(default_factory=lambda: ['1', '2', '3'])\r\n    port: int\r\n    redis_port: int\r\n    is_encrypted: bool\r\n    # a.bb[0] = 123\r\n    some_value: Optional[str] = Field(validation_alias=AliasPath('a', 'bb', 0)) # \u8fd9\u91cc\u4f7f\u7528AliasPath\uff0c\u9700\u8981\u8be5\u914d\u7f6e\u7c7b\u5fc5\u987b\u8981\u6709`a`\u5b57\u6bb5\r\n    # c-dd = xxx\r\n    c_dd: str = Field(alias='c-dd')\r\n    a: B\r\n    start: datetime.timedelta = 1\r\n    arr: List\r\n\r\nclass Abc(Base):\r\n    __label__ = None\r\n    __namespace__ = 'aUQTr9'\r\n\r\n    aaa: str = Field(alias='abc')\r\n    abc: int\r\n\r\nasync def main():\r\n    # enable_debug()\r\n    # \u81ea\u52a8\u66f4\u65b0\r\n    await ApolloSettings.start()\r\n    while True:\r\n        # \u624b\u52a8\u66f4\u65b0\r\n        # await ApolloSettingsModel.refresh()\r\n        print(ApolloSettingsModel(), datetime.datetime.now())\r\n        print(Abc(), '###' * 20)\r\n        await asyncio.sleep(10)\r\n\r\nif __name__ == '__main__':\r\n    # apollo\u914d\u7f6e\u5982\u4e0b\r\n    \"\"\"\r\n    key1 = value1\r\n    white_list = [1, 2, 3,\"5\",3734985]\r\n    port = 3306\r\n    redis_port = 6379\r\n    is_encrypted = true\r\n    123 = fsfg\u8303\u5fb7\u8428gf\r\n    xxx = {\"\u4e1a\u52a1\u7f16\u53f7\":\"123\",\"\u901a\u9053\":\"123\"} # ignore\r\n    a.bb[0] = 1\r\n    a.bb[1] = 2\r\n    c-dd = fgfg\r\n    arr[0] = 123\r\n    arr[1] = 2\r\n    \"\"\"\r\n    enable_debug()\r\n    print('##' * 20)\r\n    asyncio.run(main())\r\n```\r\n# \u96c6\u6210fastapi\r\n```python\r\nfrom fastapi import FastAPI\r\n...\r\n# some imports\r\n\r\nclass Base(ApolloSettings):\r\n    model_config = ApolloSettingsConfigDict(\r\n        # \u5b98\u65b9\u6f14\u793a\u5730\u5740\r\n        config_server='http://81.68.181.139:8080',\r\n        appid='0001234',\r\n        cluster='dev',\r\n        secret_key='0398e769780c4e6399d9e6f73910e155' # if set\r\n    )\r\n...\r\n# define your settings\r\n\r\nasync def sync_settings(app: FastAPI):\r\n    # \u81ea\u52a8\u540c\u6b65\r\n    await ApolloSettings.start()\r\n    yield app\r\n    await ApolloSettings.stop()\r\n\r\napp = FastAPI(lifespan=sync_settings)\r\n\r\nif __name__ == '__main__':\r\n    import uvicorn\r\n    uvicorn.run(app, host='0.0.0.0', port=8000)\r\n\r\n```\r\n# \u529f\u80fd\r\n- \u81ea\u52a8\u540c\u6b65\u914d\u7f6e\r\n",
    "bugtrack_url": null,
    "license": null,
    "summary": "apollo client wrapped by pydantic",
    "version": "0.0.2",
    "project_urls": {
        "Homepage": "https://github.com/ryanrain2016/apollo_pydantic",
        "Issues": "https://github.com/ryanrain2016/apollo_pydantic/issues"
    },
    "split_keywords": [
        "pydantic",
        " apollo",
        " config",
        " distributed",
        " configuration",
        " settings",
        " microservice"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "70f0637cc9b4a07f7ceb61a4d472929feea8e6d0c06819ef23c7d6ce06359d98",
                "md5": "dd4427e978907ca83e67b98272d67cf2",
                "sha256": "1e4668e6a3e966de57a8ec190025a64c7d9689e12d2e85a30b2858a27c1e6409"
            },
            "downloads": -1,
            "filename": "apollo_pydantic-0.0.2-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "dd4427e978907ca83e67b98272d67cf2",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.10",
            "size": 9460,
            "upload_time": "2024-07-15T03:07:01",
            "upload_time_iso_8601": "2024-07-15T03:07:01.767599Z",
            "url": "https://files.pythonhosted.org/packages/70/f0/637cc9b4a07f7ceb61a4d472929feea8e6d0c06819ef23c7d6ce06359d98/apollo_pydantic-0.0.2-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "d22e458cb6542e8333ca13ab3ba13e9ca03279c067fbc48c95c7248b5df56f81",
                "md5": "02fab42c3d2d0aff51001e2c0811c3f5",
                "sha256": "b061db9668f0aab8b97cf071c49e549254d5df16b321af79fe6b42efa9820aee"
            },
            "downloads": -1,
            "filename": "apollo_pydantic-0.0.2.tar.gz",
            "has_sig": false,
            "md5_digest": "02fab42c3d2d0aff51001e2c0811c3f5",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.10",
            "size": 10938,
            "upload_time": "2024-07-15T03:07:03",
            "upload_time_iso_8601": "2024-07-15T03:07:03.613105Z",
            "url": "https://files.pythonhosted.org/packages/d2/2e/458cb6542e8333ca13ab3ba13e9ca03279c067fbc48c95c7248b5df56f81/apollo_pydantic-0.0.2.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-07-15 03:07:03",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "ryanrain2016",
    "github_project": "apollo_pydantic",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "apollo-pydantic"
}
        
Elapsed time: 1.94811s