Skip to content

Commit

Permalink
Improve interpolation
Browse files Browse the repository at this point in the history
- Catch empty `{{ }}` groups and raise an error
- Catch unmatched closing `}}`
  • Loading branch information
wylee committed Jun 25, 2021
1 parent 2fffdbf commit 60e5a9f
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 21 deletions.
49 changes: 28 additions & 21 deletions src/local_settings/loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,34 +254,41 @@ def _inject(self, value, settings):

i = 0
stack = []
stack_push = stack.append
stack_pop = stack.pop
new_value = value

while True:
try:
c = new_value[i]
except IndexError:
if i == len(new_value):
break

try:
d = new_value[i + 1]
except IndexError:
d = " "
c = new_value[i]
d = new_value[i + 1 : i + 2] or ""

if c == "{" and d == "{":
stack.append(i)
stack_push(i)
i += 2
elif c == "}" and d == "}":
# g:h => {{ name }}
g = stack.pop()
h = i + 2

# m:n => name
m = g + 2
n = i

name = new_value[m:n]
elif c == "}" and d == "}":
# s:e => {{ name }}
if stack:
s = stack_pop()
else:
raise ValueError(
"Found closing delimiter without opening "
f"delimiter at position {i}"
)

e = i + 2
group = new_value[s:e]
name = group[2:-2]
name = name.strip()

if not name:
raise ValueError(
f"Found empty interpolation group at position {s}:{e}"
)

try:
v = settings.get_dotted(name)
except KeyError:
Expand All @@ -290,15 +297,15 @@ def _inject(self, value, settings):
if not isinstance(v, str):
v = self.strategy.encode_value(v)

before = new_value[:g]
after = new_value[h:]
before = new_value[:s]
after = new_value[e:]
new_value = "".join((before, v, after))

i = len(before) + len(v)

else:
i += 1

if stack:
raise ValueError("Unclosed {{ ... }} in %s" % value)
raise ValueError(f"Unclosed {{ ... }} in `{value}`")

return new_value, new_value != value
6 changes: 6 additions & 0 deletions tests/test_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import unittest

from local_settings.loader import Loader
from local_settings.settings import Settings
from local_settings.types import EnvSetting, LocalSetting


Expand Down Expand Up @@ -164,6 +165,11 @@ def test_delete(self):

self.assertEqual(settings.LIST1, [2])

def test_bad_interpolation_brackets(self):
settings = Settings()
self.assertRaises(ValueError, self.loader._inject, "{{", settings)
self.assertRaises(ValueError, self.loader._inject, "{{ }}", settings)


class TestLoadTypes(unittest.TestCase):
def setUp(self):
Expand Down

0 comments on commit 60e5a9f

Please sign in to comment.