Skip to content

Commit 1139e3a

Browse files
committed
Remove non-superfluous eval_env argument from ModelDesc.from_formula
1 parent 95361bd commit 1139e3a

File tree

5 files changed

+27
-44
lines changed

5 files changed

+27
-44
lines changed

doc/_examples/add_predictors.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
def add_predictors(base_formula, extra_predictors):
2-
# Interpret formula in caller's environment:
3-
env = EvalEnvironment.capture(1)
4-
desc = ModelDesc.from_formula(base_formula, env)
2+
desc = ModelDesc.from_formula(base_formula)
53
# Using LookupFactor here ensures that everything will work correctly even
64
# if one of the column names in extra_columns is named like "weight.in.kg"
75
# or "sys.exit()" or "LittleBobbyTables()".

doc/formulas.rst

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ formula::
6767

6868
Compare to what you get from parsing the above formula::
6969

70-
ModelDesc.from_formula("y ~ a + a:b + np.log(x)", env)
70+
ModelDesc.from_formula("y ~ a + a:b + np.log(x)")
7171

7272
:class:`ModelDesc` represents an overall formula; it just takes two
7373
lists of :class:`Term` objects, representing the left-hand side and
@@ -326,26 +326,22 @@ you can always ask Patsy how it expands.
326326

327327
Here's some code to try out at the Python prompt to get started::
328328

329-
from patsy import EvalEnvironment, ModelDesc
330-
# This captures the current Python environment. If a factor refers
331-
# to a variable that doesn't exist in the data (like np.log) then it
332-
# will be looked for here.
333-
env = EvalEnvironment.capture()
334-
ModelDesc.from_formula("y ~ x", env)
335-
ModelDesc.from_formula("y ~ x + x + x", env)
336-
ModelDesc.from_formula("y ~ -1 + x", env)
337-
ModelDesc.from_formula("~ -1", env)
338-
ModelDesc.from_formula("y ~ a:b", env)
339-
ModelDesc.from_formula("y ~ a*b", env)
340-
ModelDesc.from_formula("y ~ (a + b + c + d) ** 2", env)
341-
ModelDesc.from_formula("y ~ (a + b)/(c + d)", env)
329+
from patsy import ModelDesc
330+
ModelDesc.from_formula("y ~ x")
331+
ModelDesc.from_formula("y ~ x + x + x")
332+
ModelDesc.from_formula("y ~ -1 + x")
333+
ModelDesc.from_formula("~ -1")
334+
ModelDesc.from_formula("y ~ a:b")
335+
ModelDesc.from_formula("y ~ a*b")
336+
ModelDesc.from_formula("y ~ (a + b + c + d) ** 2")
337+
ModelDesc.from_formula("y ~ (a + b)/(c + d)")
342338
ModelDesc.from_formula("np.log(x1 + x2) "
343-
"+ (x + {6: x3, 8 + 1: x4}[3 * i])", env)
339+
"+ (x + {6: x3, 8 + 1: x4}[3 * i])")
344340

345341
Sometimes it might be easier to read if you put the processed formula
346342
back into formula notation using :meth:`ModelDesc.describe`::
347343

348-
desc = ModelDesc.from_formula("y ~ (a + b + c + d) ** 2", env)
344+
desc = ModelDesc.from_formula("y ~ (a + b + c + d) ** 2")
349345
desc.describe()
350346

351347
.. _formulas-building:

patsy/build.py

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -782,17 +782,13 @@ def subset(self, which_terms):
782782
term_name_to_term = dict(zip(design_info.term_names,
783783
design_info.terms))
784784
if isinstance(which_terms, str):
785-
# We don't use this EvalEnvironment -- all we want to do is to
786-
# find matching terms, and we can't do that use == on Term
787-
# objects, because that calls == on factor objects, which in turn
788-
# compares EvalEnvironments. So all we do with the parsed formula
789-
# is pull out the term *names*, which the EvalEnvironment doesn't
790-
# effect. This is just a placeholder then to allow the ModelDesc
791-
# to be created:
792-
env = EvalEnvironment({})
793-
desc = ModelDesc.from_formula(which_terms, env)
785+
desc = ModelDesc.from_formula(which_terms)
794786
if desc.lhs_termlist:
795787
raise PatsyError("right-hand-side-only formula required")
788+
# Use the term names instead of the term objects themselves,
789+
# because even if my original DesignInfo is using LookupFactors
790+
# or something then it's still unambiguous what naming them in
791+
# this formula means.
796792
which_terms = [term.name() for term in desc.rhs_termlist]
797793
terms = []
798794
evaluators = set()

patsy/desc.py

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -145,22 +145,19 @@ def term_code(term):
145145
return result
146146

147147
@classmethod
148-
def from_formula(cls, tree_or_string, factor_eval_env):
148+
def from_formula(cls, tree_or_string):
149149
"""Construct a :class:`ModelDesc` from a formula string.
150150
151151
:arg tree_or_string: A formula string. (Or an unevaluated formula
152152
parse tree, but the API for generating those isn't public yet. Shh,
153153
it can be our secret.)
154-
:arg factor_eval_env: A :class:`EvalEnvironment`, to be used for
155-
constructing :class:`EvalFactor` objects while parsing this
156-
formula.
157154
:returns: A new :class:`ModelDesc`.
158155
"""
159156
if isinstance(tree_or_string, ParseNode):
160157
tree = tree_or_string
161158
else:
162159
tree = parse_formula(tree_or_string)
163-
value = Evaluator(factor_eval_env).eval(tree, require_evalexpr=False)
160+
value = Evaluator().eval(tree, require_evalexpr=False)
164161
assert isinstance(value, cls)
165162
return value
166163

@@ -181,8 +178,7 @@ def test_ModelDesc():
181178

182179
def test_ModelDesc_from_formula():
183180
for input in ("y ~ x", parse_formula("y ~ x")):
184-
eval_env = EvalEnvironment.capture(0)
185-
md = ModelDesc.from_formula(input, eval_env)
181+
md = ModelDesc.from_formula(input)
186182
assert md.lhs_termlist == [Term([EvalFactor("y")]),]
187183
assert md.rhs_termlist == [INTERCEPT, Term([EvalFactor("x")])]
188184

@@ -352,9 +348,8 @@ def _eval_python_expr(evaluator, tree):
352348
return IntermediateExpr(False, None, False, [Term([factor])])
353349

354350
class Evaluator(object):
355-
def __init__(self, factor_eval_env):
351+
def __init__(self):
356352
self._evaluators = {}
357-
self._factor_eval_env = factor_eval_env
358353
self.add_op("~", 2, _eval_any_tilde)
359354
self.add_op("~", 1, _eval_any_tilde)
360355

@@ -592,8 +587,7 @@ def _do_eval_formula_tests(tests): # pragma: no cover
592587
for code, result in six.iteritems(tests):
593588
if len(result) == 2:
594589
result = (False, []) + result
595-
eval_env = EvalEnvironment.capture(0)
596-
model_desc = ModelDesc.from_formula(code, eval_env)
590+
model_desc = ModelDesc.from_formula(code)
597591
print(repr(code))
598592
print(result)
599593
print(model_desc)
@@ -608,13 +602,12 @@ def test_eval_formula():
608602

609603
def test_eval_formula_error_reporting():
610604
from patsy.parse_formula import _parsing_error_test
611-
parse_fn = lambda formula: ModelDesc.from_formula(formula,
612-
EvalEnvironment.capture(0))
605+
parse_fn = lambda formula: ModelDesc.from_formula(formula)
613606
_parsing_error_test(parse_fn, _eval_error_tests)
614607

615608
def test_formula_factor_origin():
616609
from patsy.origin import Origin
617-
desc = ModelDesc.from_formula("a + b", EvalEnvironment.capture(0))
610+
desc = ModelDesc.from_formula("a + b")
618611
assert (desc.rhs_termlist[1].factors[0].origin
619612
== Origin("a + b", 0, 1))
620613
assert (desc.rhs_termlist[2].factors[0].origin

patsy/highlevel.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,10 @@ def _try_incr_builders(formula_like, data_iter_maker, eval_env,
4747
% (formula_like,))
4848
# fallthrough
4949
if isinstance(formula_like, str):
50-
assert isinstance(eval_env, EvalEnvironment)
51-
formula_like = ModelDesc.from_formula(formula_like, eval_env)
50+
formula_like = ModelDesc.from_formula(formula_like)
5251
# fallthrough
5352
if isinstance(formula_like, ModelDesc):
53+
assert isinstance(eval_env, EvalEnvironment)
5454
return design_matrix_builders([formula_like.lhs_termlist,
5555
formula_like.rhs_termlist],
5656
data_iter_maker,

0 commit comments

Comments
 (0)