Skip to content

Commit

Permalink
Features/python3.8 (#245)
Browse files Browse the repository at this point in the history
make it work in python 3.8
  • Loading branch information
darthbear authored Oct 10, 2020
1 parent 3f635be commit c2fba83
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 21 deletions.
23 changes: 21 additions & 2 deletions pyhocon/config_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,35 @@
import socket
import sys
from datetime import timedelta
from glob import glob

import pyparsing

from pyparsing import (Forward, Group, Keyword, Literal, Optional,
ParserElement, ParseSyntaxException, QuotedString,
Regex, SkipTo, StringEnd, Suppress, TokenConverter,
Word, ZeroOrMore, alphanums, alphas8bit, col, lineno,
replaceWith)

# Fix deepcopy issue with pyparsing
if sys.version_info >= (3, 8):
def fixed_get_attr(self, item):
if item == '__deepcopy__':
raise AttributeError(item)
try:
return self[item]
except KeyError:
return ""

pyparsing.ParseResults.__getattr__ = fixed_get_attr

import asset
from pyhocon.config_tree import (ConfigInclude, ConfigList, ConfigQuotedString,
ConfigSubstitution, ConfigTree,
ConfigUnquotedString, ConfigValues, NoneValue)
from pyhocon.exceptions import (ConfigException, ConfigMissingException,
ConfigSubstitutionException)


use_urllib2 = False
try:
# For Python 3.0 and later
Expand All @@ -46,6 +60,8 @@ def glob(pathname, recursive=False):
warnings.warn('This version of python (%s) does not support recursive import' % sys.version)
from glob import glob as _glob
return _glob(pathname)
else:
from glob import glob

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -350,6 +366,7 @@ def include_config(instring, loc, token):

def _make_prefix(path):
return ('<root>' if path is None else '[%s]' % path).ljust(55).replace('\\', '/')

_prefix = _make_prefix(path)

def _load(path):
Expand All @@ -376,7 +393,9 @@ def _merge(a, b):
elif isinstance(a, list) and isinstance(b, list):
return a + b
else:
raise ConfigException('Unable to make such include (merging unexpected types: {a} and {b}', a=type(a), b=type(b))
raise ConfigException('Unable to make such include (merging unexpected types: {a} and {b}',
a=type(a), b=type(b))

logger.debug('%s Loading following configs: %s', _prefix, paths)
for p in paths:
obj = _merge(obj, _load(p))
Expand Down
18 changes: 10 additions & 8 deletions pyhocon/config_tree.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
from collections import OrderedDict
from pyparsing import lineno
from pyparsing import col
from pyparsing import col, lineno
import re
import copy
from pyhocon.exceptions import ConfigException, ConfigWrongTypeException, ConfigMissingException

try:
basestring
except NameError: # pragma: no cover
basestring = str
unicode = str

import re
import copy
from pyhocon.exceptions import ConfigException, ConfigWrongTypeException, ConfigMissingException


class UndefinedKey(object):
pass
Expand Down Expand Up @@ -148,7 +147,8 @@ def _get(self, key_path, key_index=0, default=UndefinedKey):

if elt is UndefinedKey:
if default is UndefinedKey:
raise ConfigMissingException(u"No configuration setting found for key {key}".format(key='.'.join(key_path[:key_index + 1])))
raise ConfigMissingException(
u"No configuration setting found for key {key}".format(key='.'.join(key_path[:key_index + 1])))
else:
return default

Expand Down Expand Up @@ -181,7 +181,8 @@ def parse_key(string):
:return:
"""
special_characters = '$}[]:=+#`^?!@*&.'
tokens = re.findall(r'"[^"]+"|[^{special_characters}]+'.format(special_characters=re.escape(special_characters)), string)
tokens = re.findall(
r'"[^"]+"|[^{special_characters}]+'.format(special_characters=re.escape(special_characters)), string)

def contains_special_character(token):
return any((c in special_characters) for c in token)
Expand Down Expand Up @@ -414,6 +415,7 @@ def as_plain_ordered_dict(self):
:return: this config as an OrderedDict
:type return: OrderedDict
"""

def plain_value(v):
if isinstance(v, list):
return [plain_value(e) for e in v]
Expand Down
7 changes: 1 addition & 6 deletions pyhocon/converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
basestring
except NameError:
basestring = str
unicode = str


class HOCONConverter(object):
Expand All @@ -33,13 +34,7 @@ def to_json(cls, config, compact=False, indent=2, level=0):
bet_lines = []
for key, item in config.items():
new_key = key.strip('"') # for dotted keys enclosed with "" to not be interpreted as nested key
if isinstance(new_key, unicode):
new_key = new_key.encode('utf-8')

new_value = cls.to_json(item, compact, indent, level + 1)
if isinstance(new_value, unicode):
new_value = new_value.encode('utf-8')

bet_lines.append('{indent}"{key}": {value}'.format(
indent=''.rjust((level + 1) * indent, ' '),
key=new_key,
Expand Down
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ def run_tests(self):
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8'
],
packages=[
'pyhocon',
Expand Down
14 changes: 9 additions & 5 deletions tests/test_config_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import tempfile
from collections import OrderedDict
from datetime import timedelta

from pyparsing import ParseBaseException, ParseException, ParseSyntaxException
import asset
import mock
Expand All @@ -13,7 +14,6 @@
from pyhocon.exceptions import (ConfigException, ConfigMissingException,
ConfigWrongTypeException)


try:
from dateutil.relativedelta import relativedelta as period
except Exception:
Expand Down Expand Up @@ -1085,9 +1085,13 @@ def test_include_glob_list_from_samples(self):
config = ConfigFactory.parse_file("samples/all_bars.conf")
bars = config.get_list('bars')
assert len(bars) == 10
assert bars[0].get('name') == 'Bloody Mary'
assert bars[5].get('name') == 'Homer\'s favorite coffee'
assert bars[9].get('type') == 'milk'

names = {bar['name'] for bar in bars}
types = {bar['type'] for bar in bars if 'type' in bar}
print(types, '(((((')
assert 'Bloody Mary' in names
assert 'Homer\'s favorite coffee' in names
assert 'milk' in types

def test_list_of_dicts(self):
config = ConfigFactory.parse_string(
Expand Down Expand Up @@ -1269,10 +1273,10 @@ def test_include_asset_file(self, monkeypatch):
fdin.flush()

def load(*args, **kwargs):

class File(object):
def __init__(self, filename):
self.filename = filename

return File(fdin.name)

monkeypatch.setattr(asset, "load", load)
Expand Down

0 comments on commit c2fba83

Please sign in to comment.