Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:smarty12:Python
python-patsy
python-patsy-no-python2.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File python-patsy-no-python2.patch of Package python-patsy
diff --git a/README.md b/README.md index 99e9b20..f2ed7bb 100644 --- a/README.md +++ b/README.md @@ -32,8 +32,7 @@ building design matrices. Patsy brings the convenience of [R](http://www.r-proje ## Dependencies - * Python (2.6, 2.7, or 3.3+) - * six + * Python (3.3+) * numpy * Optional: * pytest/pytest-cov: needed to run tests diff --git a/doc/conf.py b/doc/conf.py index 6e203bc..c9fffff 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -1,27 +1,27 @@ # -*- coding: utf-8 -*- # General information about the project. -project = u'patsy' -copyright = u'2011-2015, Nathaniel J. Smith' +project = 'patsy' +copyright = '2011-2015, Nathaniel J. Smith' import sys -print "python exec:", sys.executable -print "sys.path:", sys.path +print("python exec:", sys.executable) +print("sys.path:", sys.path) try: import numpy - print "numpy: %s, %s" % (numpy.__version__, numpy.__file__) + print("numpy: %s, %s" % (numpy.__version__, numpy.__file__)) except ImportError: - print "no numpy" + print("no numpy") try: import matplotlib - print "matplotlib: %s, %s" % (matplotlib.__version__, matplotlib.__file__) + print("matplotlib: %s, %s" % (matplotlib.__version__, matplotlib.__file__)) except ImportError: - print "no matplotlib" + print("no matplotlib") try: import IPython - print "ipython: %s, %s" % (IPython.__version__, IPython.__file__) + print("ipython: %s, %s" % (IPython.__version__, IPython.__file__)) except ImportError: - print "no ipython" + print("no ipython") # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the diff --git a/doc/overview.rst b/doc/overview.rst index 29ed36a..4316c16 100644 --- a/doc/overview.rst +++ b/doc/overview.rst @@ -82,8 +82,7 @@ Requirements Installing :mod:`patsy` requires: -* `Python <http://python.org/>`_ (version 2.6, 2.7, or 3.3+) -* `Six <https://pypi.python.org/pypi/six>`_ +* `Python <http://python.org/>`_ (version 3.3+) * `NumPy <http://numpy.scipy.org/>`_ Installation diff --git a/doc/py2-versus-py3.rst b/doc/py2-versus-py3.rst deleted file mode 100644 index c38528a..0000000 --- a/doc/py2-versus-py3.rst +++ /dev/null @@ -1,35 +0,0 @@ -.. _py2-versus-py3: - -Python 2 versus Python 3 -======================== - -.. currentmodule:: patsy - -The biggest difference between Python 2 and Python 3 is in their -string handling, and this is particularly relevant to Patsy since -it parses user input. We follow a simple rule: input to Patsy -should always be of type ``str``. That means that on Python 2, you -should pass byte-strings (not unicode), and on Python 3, you should -pass unicode strings (not byte-strings). Similarly, when Patsy -passes text back (e.g. :attr:`DesignInfo.column_names`), it's always -in the form of a ``str``. - -In addition to this being the most convenient for users (you never -need to use any b"weird" u"prefixes" when writing a formula string), -it's actually a necessary consequence of a deeper change in the Python -language: in Python 2, Python code itself is represented as -byte-strings, and that's the only form of input accepted by the -:mod:`tokenize` module. On the other hand, Python 3's tokenizer and -parser use unicode, and since Patsy processes Python code, it has -to follow suit. - -There is one exception to this rule: on Python 2, as a convenience for -those using ``from __future__ import unicode_literals``, the -high-level API functions :func:`dmatrix`, :func:`dmatrices`, -:func:`incr_dbuilders`, and :func:`incr_dbuilder` do accept -``unicode`` strings -- BUT these unicode string objects are still -required to contain only ASCII characters; if they contain any -non-ASCII characters then an error will be raised. If you really need -non-ASCII in your formulas, then you should consider upgrading to -Python 3. Low-level APIs like :meth:`ModelDesc.from_formula` continue -to insist on ``str`` objects only. diff --git a/patsy/__init__.py b/patsy/__init__.py index dc8fb0c..1617052 100644 --- a/patsy/__init__.py +++ b/patsy/__init__.py @@ -6,8 +6,6 @@ design matrices. It is closely inspired by the 'formula' mini-language used in R and S.""" -import sys - from patsy.version import __version__ # Do this first, to make it easy to check for warnings while testing: diff --git a/patsy/build.py b/patsy/build.py index 71806dc..6f9067e 100644 --- a/patsy/build.py +++ b/patsy/build.py @@ -8,7 +8,6 @@ __all__ = ["design_matrix_builders", "build_design_matrices"] import itertools -import six import numpy as np from patsy import PatsyError @@ -357,7 +356,7 @@ def _factors_memorize(factors, data_iter_maker, eval_env): # Now, cycle through the data until all the factors have finished # memorizing everything: memorize_needed = set() - for factor, passes in six.iteritems(passes_needed): + for factor, passes in passes_needed.items(): if passes > 0: memorize_needed.add(factor) which_pass = 0 @@ -459,7 +458,7 @@ def _examine_factor_types(factors, factor_states, data_iter_maker, NA_action): break # Pull out the levels cat_levels_contrasts = {} - for factor, sniffer in six.iteritems(cat_sniffers): + for factor, sniffer in cat_sniffers.items(): cat_levels_contrasts[factor] = sniffer.levels_contrast() return (num_column_counts, cat_levels_contrasts) @@ -726,7 +725,7 @@ def design_matrix_builders(termlists, data_iter_maker, eval_env, for factor in term.factors: this_design_factor_infos[factor] = factor_infos[factor] column_names = [] - for subterms in six.itervalues(term_to_subterm_infos): + for subterms in term_to_subterm_infos.values(): for subterm in subterms: for column_name in _subterm_column_names_iter( factor_infos, subterm): @@ -740,7 +739,7 @@ def _build_design_matrix(design_info, factor_info_to_values, dtype): factor_to_values = {} need_reshape = False num_rows = None - for factor_info, value in six.iteritems(factor_info_to_values): + for factor_info, value in factor_info_to_values.items(): # It's possible that the same factor appears in multiple different # FactorInfo objects (e.g. if someone is simultaneously building two # DesignInfo objects that started out as part of different @@ -761,7 +760,7 @@ def _build_design_matrix(design_info, factor_info_to_values, dtype): shape = (num_rows, len(design_info.column_names)) m = DesignMatrix(np.empty(shape, dtype=dtype), design_info) start_column = 0 - for term, subterms in six.iteritems(design_info.term_codings): + for term, subterms in design_info.term_codings.items(): for subterm in subterms: end_column = start_column + subterm.num_columns m_slice = m[:, start_column:end_column] @@ -883,7 +882,7 @@ def build_design_matrices(design_infos, data, # We look at evaluators rather than factors here, because it might # happen that we have the same factor twice, but with different # memorized state. - for factor_info in six.itervalues(design_info.factor_infos): + for factor_info in design_info.factor_infos.values(): if factor_info not in factor_info_to_values: value, is_NA = _eval_factor(factor_info, data, NA_action) factor_info_to_isNAs[factor_info] = is_NA diff --git a/patsy/categorical.py b/patsy/categorical.py index af7ea5a..b552f42 100644 --- a/patsy/categorical.py +++ b/patsy/categorical.py @@ -34,7 +34,7 @@ # handle the different stages of categorical data munging. import numpy as np -import six + from patsy import PatsyError from patsy.util import (SortAnythingKey, safe_scalar_isnan, @@ -158,7 +158,7 @@ def _categorical_shape_fix(data): # coerce scalars into 1d, which is consistent with what we do for numeric # factors. (See statsmodels/statsmodels#1881) if (not iterable(data) - or isinstance(data, (six.text_type, six.binary_type))): + or isinstance(data, (str, bytes))): data = [data] return data diff --git a/patsy/compat.py b/patsy/compat.py index 476123b..882e13e 100644 --- a/patsy/compat.py +++ b/patsy/compat.py @@ -31,20 +31,12 @@ # 'raise from' available in Python 3+ import sys from patsy import PatsyError + def call_and_wrap_exc(msg, origin, f, *args, **kwargs): try: return f(*args, **kwargs) except Exception as e: - if sys.version_info[0] >= 3: - new_exc = PatsyError("%s: %s: %s" - % (msg, e.__class__.__name__, e), - origin) - # Use 'exec' to hide this syntax from the Python 2 parser: - exec("raise new_exc from e") - else: - # In python 2, we just let the original exception escape -- better - # than destroying the traceback. But if it's a PatsyError, we can - # at least set the origin properly. - if isinstance(e, PatsyError): - e.set_origin(origin) - raise + new_exc = PatsyError("%s: %s: %s" + % (msg, e.__class__.__name__, e), + origin) + raise new_exc from e diff --git a/patsy/constraint.py b/patsy/constraint.py index fb6c829..012b226 100644 --- a/patsy/constraint.py +++ b/patsy/constraint.py @@ -4,8 +4,6 @@ # Interpreting linear constraints like "2*x1 + x2 = 0" -from __future__ import print_function - # These are made available in the patsy.* namespace __all__ = ["LinearConstraint"] @@ -14,7 +12,6 @@ from collections.abc import Mapping except ImportError: from collections import Mapping -import six import numpy as np from patsy import PatsyError from patsy.origin import Origin @@ -376,10 +373,10 @@ def linear_constraint(constraint_like, variable_names): dtype=float) constants = np.zeros(len(constraint_like)) used = set() - for i, (name, value) in enumerate(six.iteritems(constraint_like)): + for i, (name, value) in enumerate(constraint_like.items()): if name in variable_names: idx = variable_names.index(name) - elif isinstance(name, six.integer_types): + elif isinstance(name, int): idx = name else: raise ValueError("unrecognized variable name/index %r" diff --git a/patsy/contrasts.py b/patsy/contrasts.py index 145022a..c3e6921 100644 --- a/patsy/contrasts.py +++ b/patsy/contrasts.py @@ -5,20 +5,16 @@ # http://www.ats.ucla.edu/stat/r/library/contrast_coding.htm # http://www.ats.ucla.edu/stat/sas/webbooks/reg/chapter5/sasreg5.htm -from __future__ import print_function - # These are made available in the patsy.* namespace __all__ = ["ContrastMatrix", "Treatment", "Poly", "Sum", "Helmert", "Diff"] -import sys -import six import numpy as np from patsy import PatsyError from patsy.util import (repr_pretty_delegate, repr_pretty_impl, safe_issubdtype, no_pickling, assert_no_pickling) -class ContrastMatrix(object): +class ContrastMatrix: """A simple container for a matrix used for coding categorical factors. Attributes: @@ -69,16 +65,11 @@ def test_ContrastMatrix(): def _obj_to_readable_str(obj): if isinstance(obj, str): return obj - elif sys.version_info >= (3,) and isinstance(obj, bytes): + elif isinstance(obj, bytes): try: return obj.decode("utf-8") except UnicodeDecodeError: return repr(obj) - elif sys.version_info < (3,) and isinstance(obj, unicode): - try: - return obj.encode("ascii") - except UnicodeEncodeError: - return repr(obj) else: return repr(obj) @@ -90,16 +81,14 @@ def t(obj, expected): t(1, "1") t(1.0, "1.0") t("asdf", "asdf") - t(six.u("asdf"), "asdf") - if sys.version_info >= (3,): - # we can use "foo".encode here b/c this is python 3! - # a utf-8 encoded euro-sign comes out as a real euro sign. - t("\u20ac".encode("utf-8"), six.u("\u20ac")) - # but a iso-8859-15 euro sign can't be decoded, and we fall back on - # repr() - t("\u20ac".encode("iso-8859-15"), "b'\\xa4'") - else: - t(six.u("\u20ac"), "u'\\u20ac'") + t(u"asdf", "asdf") + + # we can use "foo".encode here b/c this is python 3! + # a utf-8 encoded euro-sign comes out as a real euro sign. + t("\u20ac".encode("utf-8"), u"\u20ac") + # but a iso-8859-15 euro sign can't be decoded, and we fall back on + # repr() + t("\u20ac".encode("iso-8859-15"), "b'\\xa4'") def _name_levels(prefix, levels): return ["[%s%s]" % (prefix, _obj_to_readable_str(level)) for level in levels] @@ -113,7 +102,7 @@ def _dummy_code(levels): def _get_level(levels, level_ref): if level_ref in levels: return levels.index(level_ref) - if isinstance(level_ref, six.integer_types): + if isinstance(level_ref, int): if level_ref < 0: level_ref += len(levels) if not (0 <= level_ref < len(levels)): @@ -133,13 +122,8 @@ def test__get_level(): pytest.raises(PatsyError, _get_level, ["a", "b"], -3) pytest.raises(PatsyError, _get_level, ["a", "b"], "c") - if not six.PY3: - assert _get_level(["a", "b", "c"], long(0)) == 0 - assert _get_level(["a", "b", "c"], long(-1)) == 2 - assert _get_level([2, 1, 0], long(0)) == 2 - -class Treatment(object): +class Treatment: """Treatment coding (also known as dummy coding). This is the default coding. diff --git a/patsy/desc.py b/patsy/desc.py index 8842b8b..4545de0 100644 --- a/patsy/desc.py +++ b/patsy/desc.py @@ -6,9 +6,6 @@ # level, as a list of interactions of factors. It also has the code to convert # a formula parse tree (from patsy.parse_formula) into a ModelDesc. -from __future__ import print_function - -import six from patsy import PatsyError from patsy.parse_formula import ParseNode, Token, parse_formula from patsy.eval import EvalEnvironment, EvalFactor @@ -595,7 +592,7 @@ def _assert_terms_match(terms, expected_intercept, expecteds): # pragma: no cove assert term == expected def _do_eval_formula_tests(tests): # pragma: no cover - for code, result in six.iteritems(tests): + for code, result in tests.items(): if len(result) == 2: result = (False, []) + result model_desc = ModelDesc.from_formula(code) diff --git a/patsy/design_info.py b/patsy/design_info.py index 435f2de..e27d382 100644 --- a/patsy/design_info.py +++ b/patsy/design_info.py @@ -17,16 +17,13 @@ # - consider renaming design_matrix_builders (and I guess # build_design_matrices too). Ditto for highlevel dbuilder functions. - -from __future__ import print_function - # These are made available in the patsy.* namespace __all__ = ["DesignInfo", "FactorInfo", "SubtermInfo", "DesignMatrix"] import warnings -import numbers -import six + import numpy as np + from patsy import PatsyError from patsy.util import atleast_2d_column_default from patsy.compat import OrderedDict @@ -37,7 +34,7 @@ from patsy.contrasts import ContrastMatrix from patsy.desc import ModelDesc, Term -class FactorInfo(object): +class FactorInfo: """A FactorInfo object is a simple class that provides some metadata about the role of a factor within a model. :attr:`DesignInfo.factor_infos` is a dictionary which maps factor objects to FactorInfo objects for each @@ -84,7 +81,7 @@ def __init__(self, factor, type, state, % (self.type,)) self.state = state if self.type == "numerical": - if not isinstance(num_columns, six.integer_types): + if not isinstance(num_columns, int): raise ValueError("For numerical factors, num_columns " "must be an integer") if categories is not None: @@ -158,14 +155,8 @@ def test_FactorInfo(): pytest.raises(TypeError, FactorInfo, "asdf", "categorical", {}, categories=1) - # Make sure longs are legal for num_columns - # (Important on python2+win64, where array shapes are tuples-of-longs) - if not six.PY3: - fi_long = FactorInfo("asdf", "numerical", {"a": 1}, - num_columns=long(10)) - assert fi_long.num_columns == 10 -class SubtermInfo(object): +class SubtermInfo: """A SubtermInfo object is a simple metadata container describing a single primitive interaction and how it is coded in our design matrix. Our final design matrix is produced by coding each primitive interaction in order @@ -215,14 +206,14 @@ def __init__(self, factors, contrast_matrices, num_columns): factor_set = frozenset(factors) if not isinstance(contrast_matrices, dict): raise ValueError("contrast_matrices must be dict") - for factor, contrast_matrix in six.iteritems(contrast_matrices): + for factor, contrast_matrix in contrast_matrices.items(): if factor not in factor_set: raise ValueError("Unexpected factor in contrast_matrices dict") if not isinstance(contrast_matrix, ContrastMatrix): raise ValueError("Expected a ContrastMatrix, not %r" % (contrast_matrix,)) self.contrast_matrices = contrast_matrices - if not isinstance(num_columns, six.integer_types): + if not isinstance(num_columns, int): raise ValueError("num_columns must be an integer") self.num_columns = num_columns @@ -243,11 +234,6 @@ def test_SubtermInfo(): assert s.contrast_matrices == {"a": cm} assert s.num_columns == 4 - # Make sure longs are accepted for num_columns - if not six.PY3: - s = SubtermInfo(["a", "x"], {"a": cm}, long(4)) - assert s.num_columns == 4 - # smoke test repr(s) @@ -289,7 +275,7 @@ def __init__(self, column_names, if not isinstance(self.term_codings, OrderedDict): raise ValueError("term_codings must be an OrderedDict") - for term, subterms in six.iteritems(self.term_codings): + for term, subterms in self.term_codings.items(): if not isinstance(term, Term): raise ValueError("expected a Term, not %r" % (term,)) if not isinstance(subterms, list): @@ -308,14 +294,14 @@ def __init__(self, column_names, if all_factors != set(self.factor_infos): raise ValueError("Provided Term objects and factor_infos " "do not match") - for factor, factor_info in six.iteritems(self.factor_infos): + for factor, factor_info in self.factor_infos.items(): if not isinstance(factor_info, FactorInfo): raise ValueError("expected FactorInfo object, not %r" % (factor_info,)) if factor != factor_info.factor: raise ValueError("mismatched factor_info.factor") - for term, subterms in six.iteritems(self.term_codings): + for term, subterms in self.term_codings.items(): for subterm in subterms: exp_cols = 1 cat_factors = set() @@ -348,7 +334,7 @@ def __init__(self, column_names, # Need to derive term information from term_codings self.term_slices = OrderedDict() idx = 0 - for term, subterm_infos in six.iteritems(self.term_codings): + for term, subterm_infos in self.term_codings.items(): term_columns = 0 for subterm_info in subterm_infos: term_columns += subterm_info.num_columns @@ -359,7 +345,7 @@ def __init__(self, column_names, "coded by given terms") self.term_name_slices = OrderedDict( [(term.name(), slice_) - for (term, slice_) in six.iteritems(self.term_slices)]) + for (term, slice_) in self.term_slices.items()]) # Guarantees: # term_name_slices is never None @@ -376,7 +362,7 @@ def __init__(self, column_names, # generate the slices ourselves, but we'll leave them in just to be # safe. covered = 0 - for slice_ in six.itervalues(self.term_name_slices): + for slice_ in self.term_name_slices.values(): start, stop, step = slice_.indices(len(column_names)) assert start == covered assert step == 1 @@ -384,7 +370,7 @@ def __init__(self, column_names, assert covered == len(column_names) # If there is any name overlap between terms and columns, they refer # to the same columns. - for column_name, index in six.iteritems(self.column_name_indexes): + for column_name, index in self.column_name_indexes.items(): if column_name in self.term_name_slices: slice_ = self.term_name_slices[column_name] if slice_ != slice(index, index + 1): @@ -1124,7 +1110,7 @@ def max_width(col): p.begin_group(2, "Terms:") p.breakable("\n" + " " * p.indentation) - for term_name, span in six.iteritems(self.design_info.term_name_slices): + for term_name, span in self.design_info.term_name_slices.items(): if span.start != 0: p.breakable(", ") p.pretty(term_name) diff --git a/patsy/eval.py b/patsy/eval.py index 53511fc..6b4f5ea 100644 --- a/patsy/eval.py +++ b/patsy/eval.py @@ -12,13 +12,12 @@ # These are made available in the patsy.* namespace __all__ = ["EvalEnvironment", "EvalFactor"] -import sys import __future__ +import sys import inspect import tokenize import ast import numbers -import six from patsy import PatsyError from patsy.util import PushbackAdapter, no_pickling, assert_no_pickling from patsy.tokens import (pretty_untokenize, normalize_token_spacing, @@ -91,7 +90,7 @@ def test_VarLookupDict(): assert ds["a"] == 10 assert d1["a"] == 1 assert ds.get("c") is None - assert isinstance(repr(ds), six.string_types) + assert isinstance(repr(ds), str) assert_no_pickling(ds) @@ -103,8 +102,7 @@ def ast_names(code): # Syntax that allows new name bindings to be introduced is tricky to # handle here, so we just refuse to do so. disallowed_ast_nodes = (ast.Lambda, ast.ListComp, ast.GeneratorExp) - if sys.version_info >= (2, 7): - disallowed_ast_nodes += (ast.DictComp, ast.SetComp) + disallowed_ast_nodes += (ast.DictComp, ast.SetComp) for node in ast.walk(ast.parse(code)): if isinstance(node, disallowed_ast_nodes): @@ -128,9 +126,8 @@ def list_ast_names(code): pytest.raises(PatsyError, list_ast_names, "lambda x: x + y") pytest.raises(PatsyError, list_ast_names, "[x + 1 for x in range(10)]") pytest.raises(PatsyError, list_ast_names, "(x + 1 for x in range(10))") - if sys.version_info >= (2, 7): - pytest.raises(PatsyError, list_ast_names, "{x: True for x in range(10)}") - pytest.raises(PatsyError, list_ast_names, "{x + 1 for x in range(10)}") + pytest.raises(PatsyError, list_ast_names, "{x: True for x in range(10)}") + pytest.raises(PatsyError, list_ast_names, "{x + 1 for x in range(10)}") class EvalEnvironment(object): """Represents a Python execution environment. @@ -306,12 +303,9 @@ def test_EvalEnvironment_capture_namespace(): assert_no_pickling(EvalEnvironment.capture()) def test_EvalEnvironment_capture_flags(): - if sys.version_info >= (3,): - # This is the only __future__ feature currently usable in Python - # 3... fortunately it is probably not going anywhere. - TEST_FEATURE = "barry_as_FLUFL" - else: - TEST_FEATURE = "division" + # This is the only __future__ feature currently usable in Python + # 3... fortunately it is probably not going anywhere. + TEST_FEATURE = "barry_as_FLUFL" test_flag = getattr(__future__, TEST_FEATURE).compiler_flag assert test_flag & _ALL_FUTURE_FLAGS source = ("def f():\n" @@ -327,7 +321,7 @@ def test_EvalEnvironment_capture_flags(): "call_capture_1": lambda: EvalEnvironment.capture(1), } env2 = dict(env) - six.exec_(code, env) + exec(code, env) assert env["RETURN_INNER"].namespace["in_f"] == "hi from f" assert env["RETURN_INNER_FROM_OUTER"].namespace["in_f"] == "hi from f" assert "in_f" not in env["RETURN_OUTER"].namespace @@ -338,7 +332,7 @@ def test_EvalEnvironment_capture_flags(): code2 = compile(("from __future__ import %s\n" % (TEST_FEATURE,)) + source, "<test string 2>", "exec", 0, 1) - six.exec_(code2, env2) + exec(code2, env2) assert env2["RETURN_INNER"].namespace["in_f"] == "hi from f" assert env2["RETURN_INNER_FROM_OUTER"].namespace["in_f"] == "hi from f" assert "in_f" not in env2["RETURN_OUTER"].namespace @@ -362,36 +356,23 @@ def test_EvalEnvironment_eval_namespace(): def test_EvalEnvironment_eval_flags(): import pytest - if sys.version_info >= (3,): - # This joke __future__ statement replaces "!=" with "<>": - # http://www.python.org/dev/peps/pep-0401/ - test_flag = __future__.barry_as_FLUFL.compiler_flag - assert test_flag & _ALL_FUTURE_FLAGS - - env = EvalEnvironment([{"a": 11}], flags=0) - assert env.eval("a != 0") == True - pytest.raises(SyntaxError, env.eval, "a <> 0") - assert env.subset(["a"]).flags == 0 - assert env.with_outer_namespace({"b": 10}).flags == 0 - - env2 = EvalEnvironment([{"a": 11}], flags=test_flag) - assert env2.eval("a <> 0") == True - pytest.raises(SyntaxError, env2.eval, "a != 0") - assert env2.subset(["a"]).flags == test_flag - assert env2.with_outer_namespace({"b": 10}).flags == test_flag - else: - test_flag = __future__.division.compiler_flag - assert test_flag & _ALL_FUTURE_FLAGS - - env = EvalEnvironment([{"a": 11}], flags=0) - assert env.eval("a / 2") == 11 // 2 == 5 - assert env.subset(["a"]).flags == 0 - assert env.with_outer_namespace({"b": 10}).flags == 0 - - env2 = EvalEnvironment([{"a": 11}], flags=test_flag) - assert env2.eval("a / 2") == 11 * 1. / 2 != 5 - env2.subset(["a"]).flags == test_flag - assert env2.with_outer_namespace({"b": 10}).flags == test_flag + + # This joke __future__ statement replaces "!=" with "<>": + # http://www.python.org/dev/peps/pep-0401/ + test_flag = __future__.barry_as_FLUFL.compiler_flag + assert test_flag & _ALL_FUTURE_FLAGS + + env = EvalEnvironment([{"a": 11}], flags=0) + assert env.eval("a != 0") == True + pytest.raises(SyntaxError, env.eval, "a <> 0") + assert env.subset(["a"]).flags == 0 + assert env.with_outer_namespace({"b": 10}).flags == 0 + + env2 = EvalEnvironment([{"a": 11}], flags=test_flag) + assert env2.eval("a <> 0") == True + pytest.raises(SyntaxError, env2.eval, "a != 0") + assert env2.subset(["a"]).flags == test_flag + assert env2.with_outer_namespace({"b": 10}).flags == test_flag def test_EvalEnvironment_subset(): env = EvalEnvironment([{"a": 1}, {"b": 2}, {"c": 3}]) @@ -419,7 +400,7 @@ def test_EvalEnvironment_eq(): assert env3 != env4 _builtins_dict = {} -six.exec_("from patsy.builtins import *", {}, _builtins_dict) +exec("from patsy.builtins import *", {}, _builtins_dict) # This is purely to make the existence of patsy.builtins visible to systems # like py2app and py2exe. It's basically free, since the above line guarantees # that patsy.builtins will be present in sys.modules in any case. @@ -678,7 +659,7 @@ def test_EvalFactor_end_to_end(): e.memorize_chunk(state, 1, {"x": np.array([12, -10]), "y": np.array([100, 3])}) e.memorize_finish(state, 1) - for transform in six.itervalues(state["transforms"]): + for transform in state["transforms"].values(): assert transform._memorize_chunk_called == 2 assert transform._memorize_finish_called == 1 # sums: diff --git a/patsy/highlevel.py b/patsy/highlevel.py index 78d2942..2138367 100644 --- a/patsy/highlevel.py +++ b/patsy/highlevel.py @@ -13,8 +13,8 @@ # ModelDesign doesn't work -- need to work with the builder set # want to be able to return either a matrix or a pandas dataframe -import six import numpy as np + from patsy import PatsyError from patsy.design_info import DesignMatrix, DesignInfo from patsy.eval import EvalEnvironment @@ -46,18 +46,6 @@ def _try_incr_builders(formula_like, data_iter_maker, eval_env, raise PatsyError("bad value from %r.__patsy_get_model_desc__" % (formula_like,)) # fallthrough - if not six.PY3 and isinstance(formula_like, unicode): - # Included for the convenience of people who are using py2 with - # __future__.unicode_literals. - try: - formula_like = formula_like.encode("ascii") - except UnicodeEncodeError: - raise PatsyError( - "On Python 2, formula strings must be either 'str' objects, " - "or else 'unicode' objects containing only ascii " - "characters. You passed a unicode string with non-ascii " - "characters. I'm afraid you'll have to either switch to " - "ascii-only, or else upgrade to Python 3.") if isinstance(formula_like, str): formula_like = ModelDesc.from_formula(formula_like) # fallthrough diff --git a/patsy/infix_parser.py b/patsy/infix_parser.py index 7ebf824..fb0ddff 100644 --- a/patsy/infix_parser.py +++ b/patsy/infix_parser.py @@ -28,8 +28,6 @@ # plausible, maybe better ways to write this -- (outcome | group) ~ x1 + x2? # "outcome ~ x1 + x2", group="group"? etc. -from __future__ import print_function - __all__ = ["Token", "ParseNode", "Operator", "parse"] from patsy import PatsyError @@ -37,7 +35,7 @@ from patsy.util import (repr_pretty_delegate, repr_pretty_impl, no_pickling, assert_no_pickling) -class _UniqueValue(object): +class _UniqueValue: def __init__(self, print_as): self._print_as = print_as @@ -46,7 +44,7 @@ def __repr__(self): __getstate__ = no_pickling -class Token(object): +class Token: """A token with possible payload. .. attribute:: type diff --git a/patsy/parse_formula.py b/patsy/parse_formula.py index 4a364ba..afab2d4 100644 --- a/patsy/parse_formula.py +++ b/patsy/parse_formula.py @@ -7,15 +7,13 @@ # uses the machinery in patsy.parse_core to do the heavy-lifting -- its # biggest job is to handle tokenization. -from __future__ import print_function __all__ = ["parse_formula"] # The Python tokenizer import tokenize -import six -from six.moves import cStringIO as StringIO +from io import StringIO from patsy import PatsyError from patsy.origin import Origin @@ -198,7 +196,7 @@ def _compare_trees(got, expected): assert got.token.extra == expected def _do_parse_test(test_cases, extra_operators): - for code, expected in six.iteritems(test_cases): + for code, expected in test_cases.items(): actual = parse_formula(code, extra_operators=extra_operators) print(repr(code), repr(expected)) print(actual) diff --git a/patsy/redundancy.py b/patsy/redundancy.py index 415fa96..c428bdf 100644 --- a/patsy/redundancy.py +++ b/patsy/redundancy.py @@ -40,8 +40,6 @@ # () + a-: reduced to just a-, which is what we code # () + a- + b- + a-:b-: reduced to b- + a-:b-, which is simplified to a+:b-. -from __future__ import print_function - from patsy.util import no_pickling # This should really be a named tuple, but those don't exist until Python diff --git a/patsy/test_build.py b/patsy/test_build.py index dcc46c7..4b112ef 100644 --- a/patsy/test_build.py +++ b/patsy/test_build.py @@ -7,16 +7,13 @@ # still not exhaustive end-to-end tests, though -- for that see # test_highlevel.py.) -from __future__ import print_function - -import six import numpy as np import pytest from patsy import PatsyError from patsy.util import (atleast_2d_column_default, have_pandas, have_pandas_categorical) from patsy.desc import Term, INTERCEPT -from patsy.build import * +from patsy.build import build_design_matrices, design_matrix_builders from patsy.categorical import C from patsy.user_util import balanced, LookupFactor from patsy.design_info import DesignMatrix, DesignInfo @@ -207,7 +204,7 @@ def test_data_types(): basic_dict_unicode = {"a": ["a1", "a2", "a1", "a2"], "x": [1, 2, 3, 4]} basic_dict_unicode = dict(basic_dict) - basic_dict_unicode["a"] = [six.text_type(s) for s in basic_dict_unicode["a"]] + basic_dict_unicode["a"] = [str(s) for s in basic_dict_unicode["a"]] structured_array_bytes = np.array(list(zip(basic_dict["a"], basic_dict["x"])), @@ -693,38 +690,27 @@ def t(which_terms, variables, columns): sub_data[variable] = all_data[variable] sub_matrix = build_design_matrices([sub_design_info], sub_data)[0] sub_full_matrix = full_matrix[:, columns] - if not isinstance(which_terms, six.string_types): + if not isinstance(which_terms, str): assert len(which_terms) == len(sub_design_info.terms) assert np.array_equal(sub_matrix, sub_full_matrix) t("~ 0 + x + y + z", ["x", "y", "z"], slice(None)) t(["x", "y", "z"], ["x", "y", "z"], slice(None)) - # Compatibility: six.PY2 wasn't added until 1.4.0, but six.PY3 exists in - # all versions. - if not six.PY3: - t([unicode("x"), unicode("y"), unicode("z")], - ["x", "y", "z"], slice(None)) t(all_terms, ["x", "y", "z"], slice(None)) t([all_terms[0], "y", all_terms[2]], ["x", "y", "z"], slice(None)) t("~ 0 + x + z", ["x", "z"], [0, 3]) t(["x", "z"], ["x", "z"], [0, 3]) - # Compatibility: six.PY2 wasn't added until 1.4.0, but six.PY3 exists in - # all versions. - if not six.PY3: - t([unicode("x"), unicode("z")], ["x", "z"], [0, 3]) t([all_terms[0], all_terms[2]], ["x", "z"], [0, 3]) t([all_terms[0], "z"], ["x", "z"], [0, 3]) t("~ 0 + z + x", ["x", "z"], [3, 0]) t(["z", "x"], ["x", "z"], [3, 0]) - t([six.text_type("z"), six.text_type("x")], ["x", "z"], [3, 0]) t([all_terms[2], all_terms[0]], ["x", "z"], [3, 0]) t([all_terms[2], "x"], ["x", "z"], [3, 0]) t("~ 0 + y", ["y"], [1, 2]) t(["y"], ["y"], [1, 2]) - t([six.text_type("y")], ["y"], [1, 2]) t([all_terms[1]], ["y"], [1, 2]) # Formula can't have a LHS diff --git a/patsy/test_highlevel.py b/patsy/test_highlevel.py index 807a32a..66c293a 100644 --- a/patsy/test_highlevel.py +++ b/patsy/test_highlevel.py @@ -4,11 +4,9 @@ # Exhaustive end-to-end tests of the top-level API. -import sys -import __future__ -import six import numpy as np import pytest + from patsy import PatsyError from patsy.design_info import DesignMatrix, DesignInfo from patsy.eval import EvalEnvironment @@ -18,7 +16,8 @@ from patsy.user_util import balanced, LookupFactor from patsy.build import (design_matrix_builders, build_design_matrices) -from patsy.highlevel import * +from patsy.highlevel import (dmatrix, dmatrices, + incr_dbuilder, incr_dbuilders) from patsy.util import (have_pandas, have_pandas_categorical, have_pandas_categorical_dtype, @@ -75,7 +74,7 @@ def t(formula_like, data, depth, depth += 1 def data_iter_maker(): return iter([data]) - if (isinstance(formula_like, six.string_types + (ModelDesc, DesignInfo)) + if (isinstance(formula_like, (str, ModelDesc, DesignInfo)) or (isinstance(formula_like, tuple) and isinstance(formula_like[0], DesignInfo)) or hasattr(formula_like, "__patsy_get_model_desc__")): @@ -260,20 +259,6 @@ def __patsy_get_model_desc__(self, data): True, [[1, 3, 1], [1, 4, 2]], ["Intercept", "x", "y"]) - # unicode objects on py2 (must be ascii only) - if not six.PY3: - # ascii is fine - t(unicode("y ~ x"), - {"y": [1, 2], "x": [3, 4]}, 0, - True, - [[1, 3], [1, 4]], ["Intercept", "x"], - [[1], [2]], ["y"]) - # non-ascii is not (even if this would be valid on py3 with its less - # restrict variable naming rules) - eacute = "\xc3\xa9".decode("utf-8") - assert isinstance(eacute, unicode) - pytest.raises(PatsyError, dmatrix, eacute, data={eacute: [1, 2]}) - # ModelDesc desc = ModelDesc([], [Term([LookupFactor("x")])]) t(desc, {"x": [1.5, 2.5, 3.5]}, 0, @@ -588,16 +573,6 @@ def _check_division(expect_true_division): # pragma: no cover else: assert np.allclose(m, [[2]]) -def test_future(): - if __future__.division.getMandatoryRelease() < sys.version_info: - # This is Python 3, where division is already default - return - # no __future__.division in this module's scope - _check_division(False) - # create an execution context where __future__.division is in effect - exec ("from __future__ import division\n" - "_check_division(True)\n") - def test_multicolumn(): data = { "a": ["a1", "a2"], @@ -652,11 +627,8 @@ def raise_patsy_error(x): try: dmatrix("1 + x[1]", {"x": {}}) except Exception as e: - if sys.version_info[0] >= 3: - assert isinstance(e, PatsyError) - assert e.origin == Origin("1 + x[1]", 4, 8) - else: - assert isinstance(e, KeyError) + assert isinstance(e, PatsyError) + assert e.origin == Origin("1 + x[1]", 4, 8) else: assert False diff --git a/patsy/test_state.py b/patsy/test_state.py index 159c00b..3c04611 100644 --- a/patsy/test_state.py +++ b/patsy/test_state.py @@ -2,8 +2,8 @@ # Copyright (C) 2012-2013 Nathaniel Smith <njs@pobox.com> # See file LICENSE.txt for license information. -from __future__ import print_function import numpy as np + from patsy.state import Center, Standardize, center from patsy.util import atleast_2d_column_default diff --git a/patsy/tokens.py b/patsy/tokens.py index 447d5ce..542d464 100644 --- a/patsy/tokens.py +++ b/patsy/tokens.py @@ -10,8 +10,9 @@ # a utility function to replace calls to global functions with calls to # other functions +from io import StringIO + import tokenize -from six.moves import cStringIO as StringIO from patsy import PatsyError from patsy.origin import Origin diff --git a/patsy/util.py b/patsy/util.py index 3116e11..5e446b7 100644 --- a/patsy/util.py +++ b/patsy/util.py @@ -24,9 +24,9 @@ ] import sys +from io import StringIO import numpy as np -import six -from six.moves import cStringIO as StringIO + from .compat import optional_dep_ok try: @@ -343,12 +343,12 @@ def next(self): return self._pushed.pop() else: # May raise StopIteration - return six.advance_iterator(self._it) + return next(self._it) __next__ = next def peek(self): try: - obj = six.advance_iterator(self) + obj = next(self) except StopIteration: raise ValueError("no more data") self.push_back(obj) @@ -365,10 +365,10 @@ def has_more(self): def test_PushbackAdapter(): it = PushbackAdapter(iter([1, 2, 3, 4])) assert it.has_more() - assert six.advance_iterator(it) == 1 + assert next(it) == 1 it.push_back(0) - assert six.advance_iterator(it) == 0 - assert six.advance_iterator(it) == 2 + assert next(it) == 0 + assert next(it) == 2 assert it.peek() == 3 it.push_back(10) assert it.peek() == 10 @@ -733,7 +733,7 @@ def assert_no_pickling(obj): # where 'constraints' might be a string or an array. (If it's an array, then # we can't use == becaues it might broadcast and ugh.) def safe_string_eq(obj, value): - if isinstance(obj, six.string_types): + if isinstance(obj, str): return obj == value else: return False @@ -741,8 +741,4 @@ def safe_string_eq(obj, value): def test_safe_string_eq(): assert safe_string_eq("foo", "foo") assert not safe_string_eq("foo", "bar") - - if not six.PY3: - assert safe_string_eq(unicode("foo"), "foo") - assert not safe_string_eq(np.empty((2, 2)), "foo") diff --git a/setup.py b/setup.py index bba2281..fd102b3 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,5 @@ #!/usr/bin/env python -import sys from setuptools import setup DESC = ("A Python package for describing statistical models and for " @@ -23,7 +22,6 @@ packages=["patsy"], url="https://github.com/pydata/patsy", install_requires=[ - "six", # Possibly we need an even newer numpy than this, but we definitely # need at least 1.4 for triu_indices "numpy >= 1.4", @@ -37,8 +35,6 @@ "Intended Audience :: Science/Research", "Intended Audience :: Financial and Insurance Industry", "License :: OSI Approved :: BSD License", - "Programming Language :: Python :: 2", - "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", diff --git a/tox.ini b/tox.ini index d6b56b2..4e599c0 100644 --- a/tox.ini +++ b/tox.ini @@ -1,9 +1,8 @@ [tox] -envlist = {py27,py36,py37,py38,py39,py310,py311,py312}-{with_pandas,without_pandas} +envlist = {py36,py37,py38,py39,py310,py311,py312}-{with_pandas,without_pandas} [gh-actions] python = - 2.7: py27 3.6: py36 3.7: py37 3.8: py38
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor