Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 1 addition & 27 deletions .github/workflows/python-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,33 +20,7 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install pytest coverage pytest-cov six mock
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
pip install -e .
- name: Test with pytest
run: |
python src/tests/configobj_doctests.py
python -m configobj.validate
py.test -c setup.cfg --color=yes --cov=configobj --cov-report=term --cov-report=html --cov-report=xml


build-on-legacy:
runs-on: ubuntu-20.04
strategy:
fail-fast: false
matrix:
python-version: [ "2.7", "3.5", "3.6" ]

steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install pytest coverage pytest-cov six mock
pip install pytest coverage pytest-cov
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
pip install -e .
- name: Test with pytest
Expand Down
8 changes: 7 additions & 1 deletion CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
Changelog
---------

Release 5.0.9
"""""""""""""

* drop support for Python 2 and <3.7
* fix CVE-2023-26112, ReDoS attack

Release 5.0.8
"""""""""""""

Expand Down Expand Up @@ -31,4 +37,4 @@ Older Releases
* Release 4.7.2 fixes several bugs in 4.7.1
* Release 4.7.1 fixes a bug with the deprecated options keyword in 4.7.0.
* Release 4.7.0 improves performance adds features for validation and
fixes some bugs.
fixes some bugs.
1 change: 0 additions & 1 deletion LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

2014
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.

Expand Down
4 changes: 1 addition & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,12 @@
Python 3+ compatible port of the [configobj](https://pypi.python.org/pypi/configobj/) library.

The Github CI/CD Pipeline runs tests on python versions:
- 2.7
- 3.5
- 3.6
- 3.7
- 3.8
- 3.9
- 3.10
- 3.11
- 3.12


## Documentation
Expand Down
6 changes: 6 additions & 0 deletions docs/configobj.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2383,6 +2383,12 @@ CHANGELOG
This is an abbreviated changelog showing the major releases up to version 4.
From version 4 it lists all releases and changes.

2024/09/21 - Version 5.0.9
--------------------------

* drop support for Python 2 and <3.7
* fix CVE-2023-26112, ReDoS attack

2023/01/18 - Version 5.0.8
--------------------------

Expand Down
26 changes: 7 additions & 19 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,9 @@

from setuptools import setup

if sys.version_info < (2, 6):
print('for Python versions < 2.6 use configobj '
'version 4.7.2')
sys.exit(1)
elif sys.version_info < (2, 7):
print('for Python version 2.6 use configobj '
'version 5.0.6')
if sys.version_info[0] < 2:
print('for Python versions < 3 use configobj '
'version 5.0.8')
sys.exit(1)

__here__ = os.path.abspath(os.path.dirname(__file__))
Expand All @@ -40,10 +36,6 @@
DESCRIPTION = 'Config file reading, writing and validation.'
URL = 'https://github.com/DiffSK/configobj'

REQUIRES = """
six
"""

VERSION = ''
with closing(open(os.path.join(__here__, 'src', PACKAGES[0], '_version.py'), 'r')) as handle:
for line in handle.readlines():
Expand Down Expand Up @@ -88,16 +80,13 @@
'Intended Audience :: Developers',
'License :: OSI Approved :: BSD License',
'Programming Language :: Python',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.12',
'Operating System :: OS Independent',
'Topic :: Software Development :: Libraries',
'Topic :: Software Development :: Libraries :: Python Modules',
Expand All @@ -120,12 +109,11 @@
py_modules=MODULES,
package_dir={'': 'src'},
packages=PACKAGES,
install_requires=[i.strip() for i in REQUIRES.splitlines() if i.strip()],
python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*',
python_requires='>=3.7',
classifiers=CLASSIFIERS,
keywords=KEYWORDS,
license='BSD (2 clause)',
license='BSD-3-Clause',
)

if __name__ == '__main__':
setup(**project)
setup(**project)
53 changes: 22 additions & 31 deletions src/configobj/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@

from codecs import BOM_UTF8, BOM_UTF16, BOM_UTF16_BE, BOM_UTF16_LE

import six
from ._version import __version__

# imported lazily to avoid startup performance hit if it isn't used
Expand Down Expand Up @@ -121,10 +120,6 @@ def match_utf8(encoding):
'write_empty_values': False,
}

# this could be replaced if six is used for compatibility, or there are no
# more assertions about items being a string


def getObj(s):
global compiler
if compiler is None:
Expand Down Expand Up @@ -553,11 +548,11 @@ def __getitem__(self, key):
"""Fetch the item and do string interpolation."""
val = dict.__getitem__(self, key)
if self.main.interpolation:
if isinstance(val, six.string_types):
if isinstance(val, str):
return self._interpolate(key, val)
if isinstance(val, list):
def _check(entry):
if isinstance(entry, six.string_types):
if isinstance(entry, str):
return self._interpolate(key, entry)
return entry
new = [_check(entry) for entry in val]
Expand All @@ -580,7 +575,7 @@ def __setitem__(self, key, value, unrepr=False):
``unrepr`` must be set when setting a value to a dictionary, without
creating a new sub-section.
"""
if not isinstance(key, six.string_types):
if not isinstance(key, str):
raise ValueError('The key "%s" is not a string.' % key)

# add the comment
Expand Down Expand Up @@ -614,11 +609,11 @@ def __setitem__(self, key, value, unrepr=False):
if key not in self:
self.scalars.append(key)
if not self.main.stringify:
if isinstance(value, six.string_types):
if isinstance(value, str):
pass
elif isinstance(value, (list, tuple)):
for entry in value:
if not isinstance(entry, six.string_types):
if not isinstance(entry, str):
raise TypeError('Value is not a string "%s".' % entry)
else:
raise TypeError('Value is not a string "%s".' % value)
Expand Down Expand Up @@ -959,7 +954,7 @@ def as_bool(self, key):
return False
else:
try:
if not isinstance(val, six.string_types):
if not isinstance(val, str):
# TODO: Why do we raise a KeyError here?
raise KeyError()
else:
Expand Down Expand Up @@ -1230,7 +1225,7 @@ def __init__(self, infile=None, options=None, configspec=None, encoding=None,


def _load(self, infile, configspec):
if isinstance(infile, six.string_types):
if isinstance(infile, str):
self.filename = infile
if os.path.isfile(infile):
with open(infile, 'rb') as h:
Expand Down Expand Up @@ -1298,7 +1293,7 @@ def set_section(in_section, this_section):
break
break

assert all(isinstance(line, six.string_types) for line in content), repr(content)
assert all(isinstance(line, str) for line in content), repr(content)
content = [line.rstrip('\r\n') for line in content]

self._parse(content)
Expand Down Expand Up @@ -1403,7 +1398,7 @@ def _handle_bom(self, infile):
else:
line = infile

if isinstance(line, six.text_type):
if isinstance(line, str):
# it's already decoded and there's no need to do anything
# else, just use the _decode utility method to handle
# listifying appropriately
Expand Down Expand Up @@ -1448,7 +1443,7 @@ def _handle_bom(self, infile):

# No encoding specified - so we need to check for UTF8/UTF16
for BOM, (encoding, final_encoding) in list(BOMS.items()):
if not isinstance(line, six.binary_type) or not line.startswith(BOM):
if not isinstance(line, bytes) or not line.startswith(BOM):
# didn't specify a BOM, or it's not a bytestring
continue
else:
Expand All @@ -1464,30 +1459,26 @@ def _handle_bom(self, infile):
else:
infile = newline
# UTF-8
if isinstance(infile, six.text_type):
if isinstance(infile, str):
return infile.splitlines(True)
elif isinstance(infile, six.binary_type):
elif isinstance(infile, bytes):
return infile.decode('utf-8').splitlines(True)
else:
return self._decode(infile, 'utf-8')
# UTF16 - have to decode
return self._decode(infile, encoding)


if six.PY2 and isinstance(line, str):
# don't actually do any decoding, since we're on python 2 and
# returning a bytestring is fine
return self._decode(infile, None)
# No BOM discovered and no encoding specified, default to UTF-8
if isinstance(infile, six.binary_type):
if isinstance(infile, bytes):
return infile.decode('utf-8').splitlines(True)
else:
return self._decode(infile, 'utf-8')


def _a_to_u(self, aString):
"""Decode ASCII strings to unicode if a self.encoding is specified."""
if isinstance(aString, six.binary_type) and self.encoding:
if isinstance(aString, bytes) and self.encoding:
return aString.decode(self.encoding)
else:
return aString
Expand All @@ -1499,9 +1490,9 @@ def _decode(self, infile, encoding):

if is a string, it also needs converting to a list.
"""
if isinstance(infile, six.string_types):
if isinstance(infile, str):
return infile.splitlines(True)
if isinstance(infile, six.binary_type):
if isinstance(infile, bytes):
# NOTE: Could raise a ``UnicodeDecodeError``
if encoding:
return infile.decode(encoding).splitlines(True)
Expand All @@ -1510,7 +1501,7 @@ def _decode(self, infile, encoding):

if encoding:
for i, line in enumerate(infile):
if isinstance(line, six.binary_type):
if isinstance(line, bytes):
# NOTE: The isinstance test here handles mixed lists of unicode/string
# NOTE: But the decode will break on any non-string values
# NOTE: Or could raise a ``UnicodeDecodeError``
Expand All @@ -1520,7 +1511,7 @@ def _decode(self, infile, encoding):

def _decode_element(self, line):
"""Decode element to unicode if necessary."""
if isinstance(line, six.binary_type) and self.default_encoding:
if isinstance(line, bytes) and self.default_encoding:
return line.decode(self.default_encoding)
else:
return line
Expand All @@ -1532,7 +1523,7 @@ def _str(self, value):
Used by ``stringify`` within validate, to turn non-string values
into strings.
"""
if not isinstance(value, six.string_types):
if not isinstance(value, str):
# intentially 'str' because it's just whatever the "normal"
# string type is for the python version we're dealing with
return str(value)
Expand Down Expand Up @@ -1786,7 +1777,7 @@ def _quote(self, value, multiline=True):
return self._quote(value[0], multiline=False) + ','
return ', '.join([self._quote(val, multiline=False)
for val in value])
if not isinstance(value, six.string_types):
if not isinstance(value, str):
if self.stringify:
# intentially 'str' because it's just whatever the "normal"
# string type is for the python version we're dealing with
Expand Down Expand Up @@ -2111,7 +2102,7 @@ def write(self, outfile=None, section=None):
if not output.endswith(newline):
output += newline

if isinstance(output, six.binary_type):
if isinstance(output, bytes):
output_bytes = output
else:
output_bytes = output.encode(self.encoding or
Expand Down Expand Up @@ -2353,7 +2344,7 @@ def reload(self):
This method raises a ``ReloadError`` if the ConfigObj doesn't have
a filename attribute pointing to a file.
"""
if not isinstance(self.filename, six.string_types):
if not isinstance(self.filename, str):
raise ReloadError()

filename = self.filename
Expand Down
2 changes: 1 addition & 1 deletion src/configobj/_version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '5.0.8'
__version__ = '5.0.9'
Loading
Loading