Skip to content

Commit 2240e36

Browse files
committed
Better support for using variables which are a Path.
1 parent f51d565 commit 2240e36

File tree

7 files changed

+165
-40
lines changed

7 files changed

+165
-40
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## 0.2.0
4+
5+
- Better support for using variables which are a `Path`.
6+
37
## 0.1.0
48

59
- Load `pyproject.toml` and `django.toml` files and parse them.

README.md

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,36 @@
55
`dj-toml-settings` reads settings from a TOML file. By default, both `pyproject.toml` and `django.toml` files are parsed for settings in the `[tool.django]` namespace.
66

77
```toml
8-
# pyproject.toml
98
[tool.django]
9+
BASE_DIR = { path = "." }
10+
SECRET_KEY = { env = "SECRET_KEY" }
11+
ADMIN_URL_PATH = { env = "ADMIN_URL_PATH", default="admin" }
12+
DEBUG = true
1013
ALLOWED_HOSTS = [
1114
"127.0.0.1",
1215
]
16+
17+
# Implicit dictionaries are supported
18+
# This is equivalent to `COLTRANE = { TITLE = "Example blog" }`
19+
[tool.django.COLTRANE]
20+
TITLE = "Example blog"
21+
22+
# Any app name can be used for organizational purposes
23+
[tool.django.apps.tailwind-cli]
24+
TAILWIND_CLI_USE_DAISY_UI = true
25+
TAILWIND_CLI_SRC_CSS = ".django_tailwind_cli/source.css"
26+
27+
# These settings are included when `ENVIRONMENT` environment variable is "development"
28+
[tool.django.envs.development]
29+
DEBUG = false
30+
ALLOWED_HOSTS = [
31+
"example.localhost",
32+
]
33+
34+
# These settings are included when `ENVIRONMENT` environment variable is "production"
35+
[tool.django.envs.production]
36+
DEBUG = false
37+
ALLOWED_HOSTS = { insert = "example.com" }
1338
```
1439

1540
## Features 🤩
@@ -19,7 +44,6 @@ ALLOWED_HOSTS = [
1944
Use `${SOME_VARIABLE_NAME}` to use an existing setting as a value.
2045

2146
```toml
22-
# pyproject.toml
2347
[tool.django]
2448
GOOD_IPS = ["127.0.0.1"]
2549
ALLOWED_HOSTS = ${GOOD_IPS}
@@ -30,10 +54,6 @@ ALLOWED_HOSTS = ${GOOD_IPS}
3054
`[tool.django.apps.{ANY_NAME_HERE}]` sections of the TOML file can be used to group settings together. They can be named anything. They will override any settings in `[tool.django]`.
3155

3256
```toml
33-
# pyproject.toml
34-
[tool.django]
35-
ALLOWED_HOSTS = ["127.0.0.1"]
36-
3757
[tool.django.apps.tailwind-cli]
3858
TAILWIND_CLI_USE_DAISY_UI = true
3959
TAILWIND_CLI_SRC_CSS = ".django_tailwind_cli/source.css"
@@ -44,7 +64,6 @@ TAILWIND_CLI_SRC_CSS = ".django_tailwind_cli/source.css"
4464
The `[tool.django.envs.{ENVIRONMENT_NAME}]` section of the TOML file will be used when `{ENVIRONMENT_NAME}` is set to the `ENVIRONMENT` environment variable. For example, `ENVIRONMENT=production python manage.py runserver` will load all settings in the `[tool.django.envs.production]` section. There settings will override any settings in `[tool.django.apps.*]` or `[tool.django]`.
4565

4666
```toml
47-
# pyproject.toml
4867
[tool.django]
4968
ALLOWED_HOSTS = ["127.0.0.1"]
5069

@@ -59,10 +78,9 @@ ALLOWED_HOSTS = ["example.com"]
5978

6079
### Path
6180

62-
Convert a string to a `Path` object. Handles relative paths based on the TOML file.
81+
Converts a string to a `Path` object. Handles relative paths based on the location of TOML file.
6382

6483
```toml
65-
# pyproject.toml
6684
[tool.django]
6785
BASE_DIR = { path = "." }
6886
PROJECT_DIR = { path = "./your_project_folder" }
@@ -74,7 +92,6 @@ REPOSITORY_DIR = { path = "./.." }
7492
Retrieve variables from the environment by using an `env` key. Specify an optional `default` key for a fallback value.
7593

7694
```toml
77-
# pyproject.toml
7895
[tool.django]
7996
EMAIL_HOST_PASSWORD = { env = 'SECRET_PASSWORD' }
8097
SECRET_KEY = { env = 'SECRET_KEY', default = 'this-is-a-secret' }
@@ -85,7 +102,6 @@ SECRET_KEY = { env = 'SECRET_KEY', default = 'this-is-a-secret' }
85102
Add items to an array by using the `insert` key.
86103

87104
```toml
88-
# pyproject.toml
89105
[tool.django]
90106
ALLOWED_HOSTS = { insert = '127.0.0.1' }
91107
```

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "dj-toml-settings"
3-
version = "0.1.0"
3+
version = "0.2.0"
44
description = "Load Django settings from a TOML file"
55
authors = [
66
{ name = "Adam Hill", email = "adam@adamghill.com" },

src/dj_toml_settings/config.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,16 @@
88

99

1010
@typechecked
11-
def get_toml_settings(base_dir: Path, data: dict | None = None, toml_settings_files: list | None = None) -> dict:
11+
def get_toml_settings(base_dir: Path, data: dict | None = None, toml_settings_files: list[str] | None = None) -> dict:
1212
"""Gets the Django settings from the TOML files.
1313
1414
TOML files to look in for settings:
1515
- pyproject.toml
1616
- django.toml
1717
"""
18-
toml_settings_files = toml_settings_files or TOML_SETTINGS_FILES
1918

20-
if data is None:
21-
data = {}
19+
toml_settings_files = toml_settings_files or TOML_SETTINGS_FILES
20+
data = data or {}
2221

2322
for settings_file_name in toml_settings_files:
2423
settings_path = base_dir / settings_file_name

src/dj_toml_settings/toml_parser.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,17 @@ def parse_key_value(data: dict, key: str, value: Any, path: Path) -> dict:
105105
elif isinstance(value, str):
106106
# Handle variable substitution
107107
for match in re.finditer(r"\$\{[A-Z_0-9]+\}", value):
108-
if variable := data.get(value[2:-1]):
109-
value = value.replace(match.string, variable)
108+
data_key = value[match.start() : match.end()][2:-1]
109+
110+
if variable := data.get(data_key):
111+
if isinstance(variable, Path):
112+
# Take whatever is before/after the variable and put it together into a new Path
113+
start = value[: match.start()]
114+
ending = value[match.end() :]
115+
116+
value = Path(start + str(variable) + ending)
117+
else:
118+
value = value.replace(match.string, str(variable))
110119
else:
111120
logger.warning(f"Missing variable substitution {value}")
112121

tests/test_config/test_get_toml_settings.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,3 +94,34 @@ def test_no_files(tmp_path):
9494
actual = get_toml_settings(base_dir=tmp_path)
9595

9696
assert expected == actual
97+
98+
99+
def test_data(tmp_path):
100+
expected = {"DEBUG": False}
101+
102+
actual = get_toml_settings(base_dir=tmp_path, data={"DEBUG": False})
103+
104+
assert expected == actual
105+
106+
107+
def test_data_is_none(tmp_path):
108+
expected = {}
109+
110+
actual = get_toml_settings(base_dir=tmp_path, data=None)
111+
112+
assert expected == actual
113+
114+
115+
def test_specified_file(tmp_path):
116+
expected = {
117+
"DEBUG": True,
118+
}
119+
120+
(tmp_path / "blob.toml").write_text("""
121+
[tool.django]
122+
DEBUG = true
123+
""")
124+
125+
actual = get_toml_settings(base_dir=tmp_path, toml_settings_files=["blob.toml"])
126+
127+
assert expected == actual

0 commit comments

Comments
 (0)