Skip to content

Commit

Permalink
Handle inline comments, and ignore spaces outside quotes (#475)
Browse files Browse the repository at this point in the history
* handle inline comments, and ignore spaces outside quotes

* fixed codestyle issues

* updated release notes

* fixed new linting issue, improved example in changelog

* included suggestions

---------

Co-authored-by: Serghei Iakovlev <egrep@protonmail.ch>
  • Loading branch information
lvanderree and sergeyklay committed Jul 6, 2023
1 parent 7f31fca commit 2750dd5
Show file tree
Hide file tree
Showing 5 changed files with 32 additions and 6 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.rst
Expand Up @@ -15,11 +15,15 @@ Added
`#463 <https://github.com/joke2k/django-environ/pull/463>`_.
- Added variable expansion
`#468 <https://github.com/joke2k/django-environ/pull/468>`_.
- Added capability to handle comments after #, after quoted values, like ``KEY= 'part1 # part2' # comment``
`#475 <https://github.com/joke2k/django-environ/pull/475>`_.

Changed
+++++++
- Used ``mssql-django`` as engine for SQL Server
`#446 <https://github.com/joke2k/django-environ/pull/446>`_.
- Changed handling bool values, stripping whitespace around value
`#475 <https://github.com/joke2k/django-environ/pull/475>`_.

Removed
+++++++
Expand Down
12 changes: 10 additions & 2 deletions environ/environ.py
Expand Up @@ -473,7 +473,7 @@ def parse_value(cls, value, cast):
try:
value = int(value) != 0
except ValueError:
value = value.lower() in cls.BOOLEAN_TRUE_STRINGS
value = value.lower().strip() in cls.BOOLEAN_TRUE_STRINGS
elif isinstance(cast, list):
value = list(map(cast[0], [x for x in value.split(',') if x]))
elif isinstance(cast, tuple):
Expand Down Expand Up @@ -970,9 +970,17 @@ def _keep_escaped_format_characters(match):
m1 = re.match(r'\A(?:export )?([A-Za-z_0-9]+)=(.*)\Z', line)
if m1:
key, val = m1.group(1), m1.group(2)
m2 = re.match(r"\A'(.*)'\Z", val)
# Look for value in quotes, ignore post-# comments
# (outside quotes)
m2 = re.match(r"\A\s*'(?<!\\)(.*)'\s*(#.*\s*)?\Z", val)
if m2:
val = m2.group(1)
else:
# For no quotes, find value, ignore comments
# after the first #
m2a = re.match(r"\A(.*?)(#.*\s*)?\Z", val)
if m2a:
val = m2a.group(1)
m3 = re.match(r'\A"(.*)"\Z', val)
if m3:
val = re.sub(r'\\(.)', _keep_escaped_format_characters,
Expand Down
7 changes: 6 additions & 1 deletion tests/fixtures.py
Expand Up @@ -38,6 +38,8 @@ class FakeEnv:
@classmethod
def generate_data(cls):
return dict(STR_VAR='bar',
STR_QUOTED_IGNORE_COMMENT='foo',
STR_QUOTED_INCLUDE_HASH='foo # with hash',
MULTILINE_STR_VAR='foo\\nbar',
MULTILINE_QUOTED_STR_VAR='---BEGIN---\\r\\n---END---',
MULTILINE_ESCAPED_STR_VAR='---BEGIN---\\\\n---END---',
Expand All @@ -50,12 +52,14 @@ def generate_data(cls):
BOOL_TRUE_STRING_LIKE_INT='1',
BOOL_TRUE_INT=1,
BOOL_TRUE_STRING_LIKE_BOOL='True',
BOOL_TRUE_STRING_LIKE_BOOL_WITH_COMMENT='True',
BOOL_TRUE_STRING_1='on',
BOOL_TRUE_STRING_2='ok',
BOOL_TRUE_STRING_3='yes',
BOOL_TRUE_STRING_4='y',
BOOL_TRUE_STRING_5='true',
BOOL_TRUE_BOOL=True,
BOOL_TRUE_BOOL_WITH_COMMENT=True,
BOOL_FALSE_STRING_LIKE_INT='0',
BOOL_FALSE_INT=0,
BOOL_FALSE_STRING_LIKE_BOOL='False',
Expand All @@ -65,7 +69,8 @@ def generate_data(cls):
INT_LIST='42,33',
INT_TUPLE='(42,33)',
MIX_TUPLE='(42,Test)',
STR_LIST_WITH_SPACES=' foo, bar',
STR_LIST_WITH_SPACES=' foo, spaces',
STR_LIST_WITH_SPACES_QUOTED="' foo', ' quoted'",
EMPTY_LIST='',
DICT_VAR='foo=bar,test=on',
DICT_WITH_EQ_VAR='key1=sub_key1=sub_value1,key2=value2',
Expand Down
8 changes: 6 additions & 2 deletions tests/test_env.py
Expand Up @@ -112,8 +112,10 @@ def test_float(self, value, variable):
[
(True, 'BOOL_TRUE_STRING_LIKE_INT'),
(True, 'BOOL_TRUE_STRING_LIKE_BOOL'),
(True, 'BOOL_TRUE_STRING_LIKE_BOOL_WITH_COMMENT'),
(True, 'BOOL_TRUE_INT'),
(True, 'BOOL_TRUE_BOOL'),
(True, 'BOOL_TRUE_BOOL_WITH_COMMENT'),
(True, 'BOOL_TRUE_STRING_1'),
(True, 'BOOL_TRUE_STRING_2'),
(True, 'BOOL_TRUE_STRING_3'),
Expand Down Expand Up @@ -175,9 +177,9 @@ def test_mix_tuple_issue_387(self):
)

def test_str_list_with_spaces(self):
assert_type_and_value(list, [' foo', ' bar'],
assert_type_and_value(list, [' foo', ' spaces'],
self.env('STR_LIST_WITH_SPACES', cast=[str]))
assert_type_and_value(list, [' foo', ' bar'],
assert_type_and_value(list, [' foo', ' spaces'],
self.env.list('STR_LIST_WITH_SPACES'))

def test_empty_list(self):
Expand Down Expand Up @@ -339,6 +341,8 @@ def test_path(self):

def test_smart_cast(self):
assert self.env.get_value('STR_VAR', default='string') == 'bar'
assert self.env.get_value('STR_QUOTED_IGNORE_COMMENT', default='string') == 'foo'
assert self.env.get_value('STR_QUOTED_INCLUDE_HASH', default='string') == 'foo # with hash'
assert self.env.get_value('BOOL_TRUE_STRING_LIKE_INT', default=True)
assert not self.env.get_value(
'BOOL_FALSE_STRING_LIKE_INT',
Expand Down
7 changes: 6 additions & 1 deletion tests/test_env.txt
Expand Up @@ -25,6 +25,8 @@ BOOL_TRUE_STRING_3='yes'
BOOL_TRUE_STRING_4='y'
BOOL_TRUE_STRING_5='true'
BOOL_TRUE_BOOL=True
BOOL_TRUE_STRING_LIKE_BOOL_WITH_COMMENT='True' # comment
BOOL_TRUE_BOOL_WITH_COMMENT=True # comment
BOOL_FALSE_STRING_LIKE_INT='0'
BOOL_FALSE_INT=0
BOOL_FALSE_STRING_LIKE_BOOL='False'
Expand All @@ -42,8 +44,11 @@ ESCAPED_VAR=\$baz
EMPTY_LIST=
EMPTY_INT_VAR=
INT_VAR=42
STR_LIST_WITH_SPACES= foo, bar
STR_LIST_WITH_SPACES= foo, spaces
STR_LIST_WITH_SPACES_QUOTED=' foo',' quoted'
STR_VAR=bar
STR_QUOTED_IGNORE_COMMENT= 'foo' # comment
STR_QUOTED_INCLUDE_HASH='foo # with hash' # not comment
MULTILINE_STR_VAR=foo\nbar
MULTILINE_QUOTED_STR_VAR="---BEGIN---\r\n---END---"
MULTILINE_ESCAPED_STR_VAR=---BEGIN---\\n---END---
Expand Down

0 comments on commit 2750dd5

Please sign in to comment.