or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

index.md

index.mddocs/

0

# pyaml-env

1

2

A Python library that parses YAML configuration files and resolves environment variables, enabling secure configuration management by keeping sensitive data like passwords, API keys, and database credentials out of version control. The library supports custom YAML tags, default value handling, multiple environment variables per line, and provides a BaseConfig class for attribute-style configuration access.

3

4

## Package Information

5

6

- **Package Name**: pyaml-env

7

- **Package Type**: pypi

8

- **Language**: Python

9

- **Installation**: `pip install pyaml-env`

10

11

## Core Imports

12

13

```python

14

from pyaml_env import parse_config, BaseConfig

15

```

16

17

Individual imports:

18

19

```python

20

from pyaml_env import parse_config

21

from pyaml_env import BaseConfig

22

```

23

24

## Basic Usage

25

26

```python

27

from pyaml_env import parse_config, BaseConfig

28

29

# Parse YAML file with environment variable resolution

30

config = parse_config('path/to/config.yaml')

31

32

# Access as dictionary

33

username = config['database']['username']

34

35

# Or use BaseConfig for attribute-style access

36

config_obj = BaseConfig(config)

37

username = config_obj.database.username

38

```

39

40

Example YAML file with environment variables:

41

42

```yaml

43

database:

44

name: test_db

45

username: !ENV ${DB_USER}

46

password: !ENV ${DB_PASS}

47

url: !ENV 'http://${DB_BASE_URL}:${DB_PORT}'

48

```

49

50

With environment variables set:

51

52

```bash

53

export DB_USER=my_user

54

export DB_PASS=my_password

55

export DB_BASE_URL=localhost

56

export DB_PORT=5432

57

```

58

59

## Capabilities

60

61

### YAML Configuration Parsing

62

63

Parse YAML configuration files with automatic environment variable resolution using custom tags.

64

65

```python { .api }

66

def parse_config(

67

path=None,

68

data=None,

69

tag='!ENV',

70

default_sep=':',

71

default_value='N/A',

72

raise_if_na=False,

73

loader=yaml.SafeLoader,

74

encoding='utf-8'

75

):

76

"""

77

Load yaml configuration from path or from the contents of a file (data)

78

and resolve any environment variables. The environment variables

79

must have the tag e.g. !ENV *before* them and be in this format to be

80

parsed: ${VAR_NAME}

81

82

Args:

83

path (str, optional): Path to the yaml file

84

data (str, optional): YAML data itself as a stream

85

tag (str): Tag to look for environment variables (default: '!ENV'). If None, all env variables will be resolved

86

default_sep (str): Separator for default values (default: ':')

87

default_value (str): Default value when no environment variable or default is found (default: 'N/A')

88

raise_if_na (bool): Raise exception if there is no default value set for the env variable (default: False)

89

loader (Type[yaml.loader]): YAML loader to use (default: yaml.SafeLoader)

90

encoding (str): Encoding of the data if a path is specified (default: 'utf-8')

91

92

Returns:

93

dict: Parsed configuration dictionary with resolved environment variables

94

95

Raises:

96

ValueError: If neither path nor data is provided, or if raise_if_na=True and no default value is found for an environment variable

97

"""

98

```

99

100

**Usage Examples:**

101

102

File-based parsing:

103

```python

104

config = parse_config(path='config.yaml')

105

```

106

107

String-based parsing:

108

```python

109

yaml_data = '''

110

database:

111

host: !ENV ${DB_HOST:localhost}

112

port: !ENV ${DB_PORT:5432}

113

'''

114

config = parse_config(data=yaml_data)

115

```

116

117

Custom tag and defaults:

118

```python

119

config = parse_config(

120

path='config.yaml',

121

tag='!CUSTOM',

122

default_sep='|',

123

default_value='missing',

124

raise_if_na=True

125

)

126

```

127

128

**Environment Variable Syntax:**

129

130

Basic environment variable:

131

```yaml

132

username: !ENV ${DB_USER}

133

```

134

135

With default value:

136

```yaml

137

username: !ENV ${DB_USER:default_user}

138

port: !ENV ${DB_PORT:5432}

139

```

140

141

Multiple variables in one line:

142

```yaml

143

url: !ENV 'http://${HOST:localhost}:${PORT:8080}/api'

144

```

145

146

Type conversion with YAML tags:

147

```yaml

148

port: !ENV tag:yaml.org,2002:int ${DB_PORT:5432}

149

enabled: !ENV tag:yaml.org,2002:bool ${FEATURE_ENABLED:false}

150

ratio: !ENV tag:yaml.org,2002:float ${RATIO:1.5}

151

```

152

153

### Attribute-Style Configuration Access

154

155

Provides attribute-style access to configuration dictionaries, allowing dot notation for nested configuration access.

156

157

```python { .api }

158

class BaseConfig:

159

"""

160

A base Config class providing attribute-style access to configuration dictionaries.

161

Recursively converts nested dictionaries to BaseConfig objects.

162

"""

163

164

def __init__(self, config_dict):

165

"""

166

Initialize BaseConfig with a configuration dictionary.

167

Copies existing class attributes, updates with config_dict,

168

and recursively converts nested dictionaries to BaseConfig objects.

169

170

Args:

171

config_dict (dict): Configuration dictionary to wrap

172

"""

173

174

def __getattr__(self, field_name: str) -> Any:

175

"""

176

Provides attribute-style access to configuration values.

177

178

Args:

179

field_name (str): Name of the configuration field

180

181

Returns:

182

Any: The configuration value

183

"""

184

185

@property

186

def errors(self):

187

"""

188

Returns:

189

list: List of validation errors

190

"""

191

192

@property

193

def _is_validated(self):

194

"""

195

Returns:

196

bool: Whether validation has been performed

197

"""

198

199

@property

200

def _is_valid(self):

201

"""

202

Returns:

203

bool: Whether configuration passed validation

204

"""

205

206

@property

207

def _errors(self):

208

"""

209

Returns:

210

list: Internal list of validation errors

211

"""

212

213

def validate(self):

214

"""

215

Abstract method for configuration validation (must be implemented by subclasses).

216

217

Raises:

218

NotImplementedError: This method must be implemented in subclasses

219

"""

220

```

221

222

**Usage Examples:**

223

224

Basic attribute access:

225

```python

226

from pyaml_env import parse_config, BaseConfig

227

228

config = BaseConfig(parse_config('config.yaml'))

229

230

# Dot notation access instead of dictionary syntax

231

host = config.database.host

232

port = config.database.port

233

username = config.database.username

234

```

235

236

Nested configuration access:

237

```python

238

# YAML:

239

# app:

240

# database:

241

# primary:

242

# host: !ENV ${PRIMARY_DB_HOST}

243

# port: !ENV ${PRIMARY_DB_PORT:5432}

244

# cache:

245

# redis_url: !ENV ${REDIS_URL}

246

247

config = BaseConfig(parse_config('config.yaml'))

248

primary_host = config.app.database.primary.host

249

redis_url = config.app.database.cache.redis_url

250

```

251

252

Custom validation (subclass implementation):

253

```python

254

class DatabaseConfig(BaseConfig):

255

def validate(self):

256

if not hasattr(self, 'host'):

257

self._errors.append("Missing required field: host")

258

if hasattr(self, 'port') and not isinstance(self.port, int):

259

self._errors.append("Port must be an integer")

260

self._is_validated = True

261

self._is_valid = len(self._errors) == 0

262

263

db_config = DatabaseConfig(parse_config('db_config.yaml'))

264

db_config.validate()

265

if not db_config._is_valid:

266

print("Configuration errors:", db_config.errors)

267

```

268

269

## Advanced Features

270

271

### Custom YAML Loaders

272

273

Support for different YAML loaders including UnsafeLoader for serialized Python objects:

274

275

```python

276

import yaml

277

from pyaml_env import parse_config

278

279

# Using UnsafeLoader for Python objects

280

config = parse_config(path='config.yaml', loader=yaml.UnsafeLoader)

281

282

# Using FullLoader

283

config = parse_config(path='config.yaml', loader=yaml.FullLoader)

284

```

285

286

### Error Handling Modes

287

288

Control behavior when environment variables are missing:

289

290

```python

291

# Strict mode - raise exception if no default provided

292

try:

293

config = parse_config('config.yaml', raise_if_na=True)

294

except ValueError as e:

295

print(f"Missing environment variable: {e}")

296

297

# Permissive mode - use default_value for missing variables

298

config = parse_config('config.yaml', default_value='MISSING')

299

```

300

301

### Environment Variable Resolution Rules

302

303

1. **Tag Resolution**: Only values with the specified tag (default `!ENV`) are processed

304

2. **Variable Extraction**: Variables must use `${VARIABLE_NAME}` syntax

305

3. **Default Handling**: Use separator (default `:`) for defaults: `${VAR:default}`

306

4. **Fallback Chain**: Environment variable → default value → global default_value

307

5. **Type Conversion**: Support for YAML type tags like `tag:yaml.org,2002:int`

308

309

## Types

310

311

```python { .api }

312

from typing import Any, Type

313

import yaml

314

315

# Type aliases for function parameters

316

LoaderType = Type[yaml.loader]

317

ConfigDict = dict

318

```