Metadata-Version: 2.4
Name: dynamic-config-nacos
Version: 0.1.0
Summary: Reusable dynamic config provider with YAML fallback and Nacos backends
Author-email: FrankTang <franktz2003@gmail.com>
Maintainer-email: FrankTang <franktz2003@gmail.com>
License-Expression: MIT
Project-URL: PyPI, https://pypi.org/project/dynamic-config-nacos/
Project-URL: Homepage, https://github.com/franktz/dynamic-config-nacos
Project-URL: Documentation, https://github.com/franktz/dynamic-config-nacos
Project-URL: Repository, https://github.com/franktz/dynamic-config-nacos
Project-URL: Issues, https://github.com/franktz/dynamic-config-nacos/issues
Keywords: configuration,yaml,nacos,dynamic-config-nacos
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: System :: Distributed Computing
Requires-Python: >=3.12
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: PyYAML>=6.0
Requires-Dist: requests>=2.31
Requires-Dist: nacos-sdk-python>=2.0
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == "dev"
Requires-Dist: ruff>=0.4; extra == "dev"
Provides-Extra: release
Requires-Dist: build>=1.2; extra == "release"
Requires-Dist: twine>=5.1; extra == "release"
Dynamic: license-file

# dynamic-config-nacos

[English](./README.md) | [简体中文](./README.zh-CN.md)

`dynamic-config-nacos` is a small reusable Python package for dynamic
configuration loading.

Its goal is to give application projects one consistent way to read
configuration, whether the source is a local YAML file or a Nacos server.

Author: FrankTang (<franktz2003@gmail.com>)

License: MIT

## What This Library Does

- Uses local YAML as a fallback configuration source
- Fetches remote configuration from Nacos
- Supports automatic backend selection across `http`, `sdk_v2`, and `sdk_v3`
- Refreshes in-memory configuration on updates on a best-effort basis
- Provides a lightweight `Conf` object for dot-path and index-based access

## Install

```bash
pip install dynamic-config-nacos
```

The Python import name remains `dynamic_config`:

```python
from dynamic_config import DynamicConfigProvider
```

For local workspace development with `uv`, downstream projects can also use a
path dependency to this package.

## Quick Start

```python
from dynamic_config import DynamicConfigProvider

provider = DynamicConfigProvider(local_yaml_path="configs/local.yaml")
provider.load_from_env()

app_name = provider.get("app.name")
```

## Usage

### Local YAML Only

```python
from dynamic_config import DynamicConfigProvider

provider = DynamicConfigProvider(local_yaml_path="configs/local.yaml")
provider.load_initial(None)

debug = provider.get("app.debug", False)
```

### Enable Nacos with Environment Variables

```powershell
$env:NACOS_SERVER_ADDR = "127.0.0.1:8848"
$env:NACOS_DATA_ID = "app.yaml"
$env:NACOS_GROUP = "DEFAULT_GROUP"
```

```python
from dynamic_config import DynamicConfigProvider

provider = DynamicConfigProvider(local_yaml_path="configs/local.yaml")
provider.load_from_env()

app_name = provider.get("app.name")
```

### Override the Local YAML Path

`DynamicConfigProvider` currently requires a `local_yaml_path` value during
construction, but `load_from_env()` will override it if `LOCAL_CONFIG_PATH` is
set.

```powershell
$env:LOCAL_CONFIG_PATH = "configs/dev.local.yaml"
```

After `load_from_env()`, the library will use the path from
`LOCAL_CONFIG_PATH`.

### Read Values Through `Conf`

```python
conf = provider.conf

value1 = conf["a.b[0].c"]
value2 = conf.a.b[0].c
value3 = conf.get("a.x", "fallback")
```

## Logging

This package uses the standard library `logging` module and does not currently
accept a custom logger object from callers.

Internally it uses module-level loggers like this:

```python
logger = logging.getLogger(__name__)
```

That means the host application controls log output, handlers, formatting, and
log levels:

```python
import logging

logging.basicConfig(level=logging.INFO)
```

Typical log events include:

- `warning` when the local YAML file is missing
- `warning` when Nacos returns a non-mapping YAML root
- `warning` for invalid backend or polling interval values
- `info` when a Nacos update has been applied
- `info` when a backend is auto-selected
- `exception` when Nacos fetch, watcher startup, login, or version detection fails

## Does the Local YAML File Need to Exist?

- `local_yaml_path` is currently a required constructor argument
- The file itself does not need to exist
- If the file is missing, the library logs a warning and falls back to an empty
  config `{}`
- If Nacos successfully returns a config, the local YAML file is not used for
  that load

In practice, the path behaves more like a local fallback location than a strict
required input file.

## Internal Design Overview

The library's loading flow looks like this:

1. Create `DynamicConfigProvider` with a local YAML path.
2. Call `load_from_env()` to read Nacos-related environment variables.
3. If `NACOS_SERVER_ADDR` is present, build a `NacosSettings` object.
4. Create a Nacos backend using explicit configuration or auto-detection.
5. Try to fetch YAML content from Nacos first.
6. If Nacos fails, returns empty content, or returns a non-mapping YAML root,
   fall back to the local YAML file.
7. Store the final raw dictionary and wrap it in a `Conf` object.
8. If the backend supports watching, start a watcher and refresh the in-memory
   config on updates.

### Auto Backend Selection

When `backend=AUTO`, the package first tries to detect the Nacos server major
version and then picks a preferred order:

- Nacos 2.x: `sdk_v2` -> `sdk_v3` -> `http`
- Nacos 3.x: `sdk_v3` -> `sdk_v2` -> `http`
- Detection failed: `sdk_v3` -> `sdk_v2` -> `http`

### HTTP Mode

- Fetches config through the Nacos HTTP API
- Optionally logs in first to obtain an `accessToken`
- Starts a background polling thread
- Uses content MD5 to detect changes

### SDK Mode

- Tries multiple SDK import paths
- Tries both `get_config` and `getConfig`
- Tries `add_config_watchers`, `add_config_watcher`, and `add_listener`

## Public API

- `DynamicConfigProvider`
- `Conf`
- `NullConf`
- `NULL`
- `NacosSettings`
- `NacosBackendType`

## Additional Docs

- English usage guide: [how-to-use.md](./how-to-use.md)
- Chinese usage guide: [how-to-use.zh-CN.md](./how-to-use.zh-CN.md)
- Chinese overview: [README.zh-CN.md](./README.zh-CN.md)

## Project Links

- Homepage: <https://github.com/franktz/dynamic-config-nacos>
- Repository: <https://github.com/franktz/dynamic-config-nacos>
- Issues: <https://github.com/franktz/dynamic-config-nacos/issues>

## Author

- FrankTang
- Email: <franktz2003@gmail.com>
- License: MIT
