diff --git a/examples/usage.py b/examples/usage.py index 83cd22a..7b4bcaa 100644 --- a/examples/usage.py +++ b/examples/usage.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # vim: sw=4:ts=4:expandtab """ diff --git a/manage.py b/manage.py index 35f9b33..043c2a5 100755 --- a/manage.py +++ b/manage.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- # vim: sw=4:ts=4:expandtab """ A script to manage development tasks """ diff --git a/meza/__init__.py b/meza/__init__.py index 6b90345..b2320c7 100644 --- a/meza/__init__.py +++ b/meza/__init__.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- # vim: sw=4:ts=4:expandtab """ diff --git a/meza/compat.py b/meza/compat.py index 38e81c6..874bc76 100644 --- a/meza/compat.py +++ b/meza/compat.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- # vim: sw=4:ts=4:expandtab """ diff --git a/meza/convert.py b/meza/convert.py index 7e8bfa9..dfb9594 100644 --- a/meza/convert.py +++ b/meza/convert.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- # vim: sw=4:ts=4:expandtab """ @@ -151,7 +150,7 @@ def to_bool(content, trues=None, falses=None, warn=False, **kwargs): except (TypeError, AttributeError): value = bool(content) elif warn: - raise ValueError("Invalid bool value: `{}`.".format(content)) + raise ValueError(f"Invalid bool value: `{content}`.") else: value = False @@ -196,13 +195,13 @@ def to_int(content, thousand_sep=",", decimal_sep=".", warn=False, **kwargs): int """ if warn and not ft.is_int(content): - raise ValueError("Invalid int value: `{}`.".format(content)) + raise ValueError(f"Invalid int value: `{content}`.") try: value = int(float(ft.strip(content, thousand_sep, decimal_sep))) except ValueError: if warn: - raise ValueError("Invalid int value: `{}`.".format(content)) + raise ValueError(f"Invalid int value: `{content}`.") else: value = 0 @@ -246,7 +245,7 @@ def to_float(content, thousand_sep=",", decimal_sep=".", warn=False, **kwargs): if ft.is_numeric(content): value = float(ft.strip(content, thousand_sep, decimal_sep)) elif warn: - raise ValueError("Invalid float value: `{}`.".format(content)) + raise ValueError(f"Invalid float value: `{content}`.") else: value = 0.0 @@ -303,7 +302,7 @@ def to_decimal(content, thousand_sep=",", decimal_sep=".", **kwargs): if ft.is_numeric(content): decimalized = Decimal(ft.strip(content, thousand_sep, decimal_sep)) elif kwargs.get("warn"): - raise ValueError("Invalid numeric value: `{}`.".format(content)) + raise ValueError(f"Invalid numeric value: `{content}`.") else: decimalized = Decimal(0) @@ -430,7 +429,7 @@ def to_datetime(content, dt_format=None, warn=False, **kwargs): value = NULL_DATETIME if warn and value == NULL_DATETIME: - raise ValueError("Invalid datetime value: `{}`.".format(content)) + raise ValueError(f"Invalid datetime value: `{content}`.") else: datetime = value.strftime(dt_format) if dt_format else value @@ -552,7 +551,7 @@ def to_filepath(filepath, **kwargs): filename = "{}.{}".format(resource_id, filename.split("=")[1]) elif isdir and "." not in filename: ctype = headers.get("content-type") - filename = "{}.{}".format(filename, ctype2ext(ctype)) + filename = f"{filename}.{ctype2ext(ctype)}" return p.join(filepath, filename) if isdir else filepath @@ -993,7 +992,7 @@ def gen_subresults(records, kw): polygon = [[(r[kw.lon], r[kw.lat]) for r in g[1]] for g in groups] yield (polygon, first_row) else: - raise TypeError("Invalid type: {}".format(_type)) + raise TypeError(f"Invalid type: {_type}") def records2geojson(records, **kwargs): diff --git a/meza/dbf.py b/meza/dbf.py index 06226ae..8ab0a50 100644 --- a/meza/dbf.py +++ b/meza/dbf.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- # vim: sw=4:ts=4:expandtab """ @@ -57,7 +56,7 @@ def __init__(self, filepath, **kwargs): """ try: kwargs["recfactory"] = dict - return super(DBF2, self).__init__(filepath, **kwargs) + return super().__init__(filepath, **kwargs) except (AttributeError, TypeError): filename = filepath.name @@ -69,7 +68,7 @@ def __init__(self, filepath, **kwargs): self.filename = ifind(filename) if self.ignorecase else filename if not self.filename: - raise DBFNotFound("could not find file {!r}".format(filename)) + raise DBFNotFound(f"could not find file {filename!r}") self.fields = [] self.field_names = [] diff --git a/meza/fntools.py b/meza/fntools.py index 75cc927..4eda0ef 100644 --- a/meza/fntools.py +++ b/meza/fntools.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- # vim: sw=4:ts=4:expandtab """ @@ -120,7 +119,7 @@ logger = gogo.Gogo(__name__, monolog=True).logger -class Objectify(object): +class Objectify: """Creates an object with dynamically set attributes. Useful for accessing the kwargs of a function as attributes. """ @@ -177,7 +176,7 @@ def __setattr__(self, key, value): if key not in {"data", "func", "keys", "values", "items", "get"}: self.data.__setitem__(key, value) - return super(Objectify, self).__setattr__(key, value) + return super().__setattr__(key, value) def __getattr__(self, name): return self.__getitem__(name) @@ -195,7 +194,7 @@ def iteritems(self): return iter(self.items()) -class Andand(object): +class Andand: """A Ruby inspired null soaking object Examples: @@ -235,14 +234,14 @@ def default(self, obj): encoded = float(obj) elif hasattr(obj, "to_dict"): encoded = obj.to_dict() - elif set(["quantize", "year", "hour"]).intersection(dir(obj)): + elif {"quantize", "year", "hour"}.intersection(dir(obj)): encoded = str(obj) elif hasattr(obj, "union"): encoded = tuple(obj) - elif set(["next", "append"]).intersection(dir(obj)): + elif {"next", "append"}.intersection(dir(obj)): encoded = list(obj) else: - encoded = super(CustomEncoder, self).default(obj) + encoded = super().default(obj) return encoded @@ -254,15 +253,15 @@ class SleepyDict(dict): def __init__(self, *args, **kwargs): self.delay = kwargs.pop("delay", 0) - super(SleepyDict, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) def __len__(self): time.sleep(self.delay) - return super(SleepyDict, self).__len__() + return super().__len__() def get(self, key, default=None): time.sleep(self.delay) - return super(SleepyDict, self).get(key, default) + return super().get(key, default) def underscorify(content): @@ -716,12 +715,10 @@ def get_values(narray): try: yield narray.tounicode() except ValueError: - for y in narray.tolist(): - yield y + yield from narray.tolist() except AttributeError: for n in narray: - for x in get_values(n): - yield x + yield from get_values(n) def xmlize(content): @@ -783,7 +780,7 @@ def afterish(content, separator=","): elif numeric: after = -1 else: - raise ValueError("Not able to coerce {} to a number".format(content)) + raise ValueError(f"Not able to coerce {content} to a number") return after @@ -834,7 +831,7 @@ def get_separators(content): else: logger.debug("after_comma: %s", after_comma) logger.debug("after_decimal: %s", after_decimal) - raise ValueError("Invalid number format for `{}`.".format(content)) + raise ValueError(f"Invalid number format for `{content}`.") return {"thousand_sep": thousand_sep, "decimal_sep": decimal_sep} @@ -867,7 +864,7 @@ def _fuzzy_match(needle, haystack, **kwargs): def _exact_match(*args, **kwargs): - sets = (set(i.lower() for i in arg) for arg in args) + sets = ({i.lower() for i in arg} for arg in args) return iter(reduce(lambda x, y: x.intersection(y), sets)) @@ -1101,10 +1098,9 @@ def flatten(record, prefix=None): """ try: for key, value in record.items(): - newkey = "{}_{}".format(prefix, key) if prefix else key + newkey = f"{prefix}_{key}" if prefix else key - for flattened in flatten(value, newkey): - yield flattened + yield from flatten(value, newkey) except AttributeError: yield (prefix, record) diff --git a/meza/io.py b/meza/io.py index b951671..5a7f462 100644 --- a/meza/io.py +++ b/meza/io.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- # vim: sw=4:ts=4:expandtab """ @@ -54,7 +53,7 @@ ) from xlrd.xldate import xldate_as_datetime as xl2dt -from io import StringIO, TextIOBase, BytesIO, open +from io import StringIO, TextIOBase, BytesIO from . import fntools as ft, process as pr, unicsv as csv, dbf, ENCODING, BOM, DATA_DIR @@ -388,7 +387,7 @@ def get_file_encoding(f, encoding=None, bytes_error=False): if not bytes_error: # Set the encoding to None so that we can detect the correct one. - extra = (" ({})".format(encoding)) if encoding else "" + extra = (f" ({encoding})") if encoding else "" logger.warning("%s was opened with the wrong encoding%s", f, extra) encoding = None @@ -651,7 +650,7 @@ def read_mdb(filepath, table=None, **kwargs): yield return except CalledProcessError: - raise TypeError("{} is not readable by mdbtools".format(filepath)) + raise TypeError(f"{filepath} is not readable by mdbtools") sanitize = kwargs.pop("sanitize", None) dedupe = kwargs.pop("dedupe", False) @@ -757,7 +756,7 @@ def read_sqlite(filepath, table=None): if not table or table not in set(cursor.fetchall()): table = cursor.fetchone()[0] - cursor.execute("SELECT * FROM {}".format(table)) + cursor.execute(f"SELECT * FROM {table}") return map(dict, cursor) @@ -1186,7 +1185,7 @@ def gen_records(_type, record, coords, properties, **kwargs): record["pos"] = pos yield pr.merge([record, properties]) else: - raise TypeError("Invalid geometry type {}.".format(_type)) + raise TypeError(f"Invalid geometry type {_type}.") def read_geojson(filepath, key="id", mode="r", **kwargs): @@ -1247,8 +1246,7 @@ def reader(f, **kwargs): args = (record, coords, properties) - for rec in gen_records(_type, *args, **kwargs): - yield rec + yield from gen_records(_type, *args, **kwargs) return read_any(filepath, reader, mode, **kwargs) @@ -1420,7 +1418,7 @@ def reader(f, **kwargs): names = map(get_text, ths) else: col_nums = range(len(a_row)) - names = ["column_{}".format(i) for i in col_nums] + names = [f"column_{i}" for i in col_nums] uscored = ft.underscorify(names) if sanitize else names header = list(ft.dedupe(uscored) if dedupe else uscored) diff --git a/meza/process.py b/meza/process.py index 2aa7fec..c668ce2 100644 --- a/meza/process.py +++ b/meza/process.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- # vim: sw=4:ts=4:expandtab """ @@ -941,14 +940,14 @@ def get_suffix(cpos, pos, k=None, count=None, chunksize=None): if subchunks and k is None: args = (cpos + 1, pos + 1) - suffix = "{0:02d}_{1:03d}".format(*args) + suffix = "{:02d}_{:03d}".format(*args) elif subchunks: args = (k, cpos + 1, pos + 1) - suffix = "{0}_{1:02d}_{2:03d}".format(*args) + suffix = "{}_{:02d}_{:03d}".format(*args) elif chunksize and k is None: - suffix = "{0:03d}".format(cpos + 1) + suffix = f"{cpos + 1:03d}" elif chunksize: - suffix = "{0}_{1:03d}".format(k, cpos + 1) + suffix = f"{k}_{cpos + 1:03d}" else: suffix = "" if k is None else k diff --git a/meza/stats.py b/meza/stats.py index 7ec9e9d..095385e 100644 --- a/meza/stats.py +++ b/meza/stats.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- # vim: sw=4:ts=4:expandtab """ diff --git a/meza/typetools.py b/meza/typetools.py index 0e27fc9..85b4d2f 100644 --- a/meza/typetools.py +++ b/meza/typetools.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- # vim: sw=4:ts=4:expandtab """ @@ -169,7 +168,7 @@ def guess_type_by_value(record, blanks_as_nulls=True, strip_zeros=False): yield result break else: - raise TypeError("Couldn't guess type of '{}'".format(value)) + raise TypeError(f"Couldn't guess type of '{value}'") def is_date(content): diff --git a/meza/unicsv.py b/meza/unicsv.py index f12a774..949dea5 100644 --- a/meza/unicsv.py +++ b/meza/unicsv.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- # vim: sw=4:ts=4:expandtab """ @@ -45,7 +44,7 @@ def encode_all(f=None, **kwargs): return res -class UnicodeWriter(object): +class UnicodeWriter: """ >>> from io import StringIO >>> diff --git a/setup.cfg b/setup.cfg index d7d473b..2e8e2bc 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,3 +1,6 @@ +[options] +python_requires = >=3.8 + [wheel] universal=1 diff --git a/setup.py b/setup.py index 6a69080..6e9ee04 100644 --- a/setup.py +++ b/setup.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- import sys import pkutils @@ -11,7 +10,6 @@ sys.dont_write_bytecode = True requirements = list(pkutils.parse_requirements("requirements.txt")) -dev_requirements = list(pkutils.parse_requirements("dev-requirements.txt")) readme = pkutils.read("README.rst") changes = pkutils.read(p.join(PARENT_DIR, "docs", "CHANGES.rst")) module = pkutils.parse_module(p.join(PARENT_DIR, "meza", "__init__.py")) @@ -21,14 +19,11 @@ description = module.__description__ user = "reubano" -# Setup requirements -setup_require = [r for r in dev_requirements if "pkutils" in r] - setup( name=project, version=version, description=description, - long_description="%s\n\n%s" % (readme, changes), + long_description="{}\n\n{}".format(readme, changes), author=module.__author__, author_email=module.__email__, url=pkutils.get_url(project, user), @@ -43,10 +38,6 @@ "examples": ["examples/*"], }, install_requires=requirements, - setup_requires=setup_require, - test_suite="nose.collector", - tests_require=dev_requirements, - license=license, zip_safe=False, keywords=[project] + description.split(" "), classifiers=[ @@ -55,9 +46,6 @@ "Natural Language :: English", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Environment :: Console", @@ -67,5 +55,5 @@ "Operating System :: MacOS :: MacOS X", "Operating System :: Microsoft :: Windows", ], - platforms=["MacOS X", "Windows", "Linux"], + platforms=["macOS", "Windows", "Linux"], ) diff --git a/tests/__init__.py b/tests/__init__.py index f2ff07e..69b7cea 100755 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # vim: sw=4:ts=4:expandtab """ tests diff --git a/tests/test_fntools.py b/tests/test_fntools.py index 3c5348c..b458265 100644 --- a/tests/test_fntools.py +++ b/tests/test_fntools.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # vim: sw=4:ts=4:expandtab """ tests.test_fntools @@ -76,7 +75,7 @@ def test_is_null(self): def test_byte_array(self): content = "Iñtërnâtiônàližætiøn" - expected = bytearray("Iñtërnâtiônàližætiøn".encode("utf-8")) + expected = bytearray("Iñtërnâtiônàližætiøn".encode()) assert expected == ft.byte(content) assert expected == ft.byte(iter(content)) assert expected == ft.byte(list(content)) diff --git a/tests/test_io.py b/tests/test_io.py index cd2e788..d9a4825 100644 --- a/tests/test_io.py +++ b/tests/test_io.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # vim: sw=4:ts=4:expandtab """ tests.test_io @@ -11,7 +10,7 @@ from os import path as p from json import loads from tempfile import TemporaryFile -from io import StringIO, BytesIO, open +from io import StringIO, BytesIO from decimal import Decimal from urllib.request import urlopen from contextlib import closing @@ -56,7 +55,7 @@ def test_lines(self): assert bytearray(b" Worldly") == self.phrase.read(8) self.phrase.write(": Iñtërnâtiônàližætiøn") - expected = bytearray(" person: Iñtërnâtiônàližætiøn".encode("utf-8")) + expected = bytearray(" person: Iñtërnâtiônàližætiøn".encode()) assert expected == self.phrase.read() assert bytearray(b"line one") == self.text.readline() @@ -425,7 +424,7 @@ def test_urlopen_utf8(self): """Test for reading utf-8 files""" filepath = p.join(io.DATA_DIR, "utf8.csv") - with closing(urlopen("file://{}".format(filepath))) as response: + with closing(urlopen(f"file://{filepath}")) as response: f = response.fp records = io.read_csv(f) row = next(it.islice(records, 1, 2)) @@ -436,7 +435,7 @@ def test_urlopen_latin1(self): """Test for reading latin-1 files""" filepath = p.join(io.DATA_DIR, "latin1.csv") - with closing(urlopen("file://{}".format(filepath))) as response: + with closing(urlopen(f"file://{filepath}")) as response: f = response.fp records = io.read_csv(f, encoding="latin-1") row = next(it.islice(records, 1, 2)) diff --git a/tests/test_process.py b/tests/test_process.py index cd25389..7b4bed7 100644 --- a/tests/test_process.py +++ b/tests/test_process.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # vim: sw=4:ts=4:expandtab """ tests.test_process @@ -264,6 +263,6 @@ def test_pivot(self): ] result = list(pr.pivot(records, "D", "C", dropna=False)) - expected_set = set(tuple(sorted(r.items())) for r in expected) - result_set = set(tuple(sorted(r.items())) for r in result) + expected_set = {tuple(sorted(r.items())) for r in expected} + result_set = {tuple(sorted(r.items())) for r in result} assert expected_set == result_set diff --git a/tox.ini b/tox.ini index fad0aa6..2ab612c 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist=py{37,38,39,py3}{,-optional,-style} +envlist=py{312,311,310,py3}{,-optional,-style} [testenv]