[lmfit-py] 01/03: Imported Upstream version 0.8.1+dfsg.1

Frédéric-Emmanuel Picca picca at moszumanska.debian.org
Sun Nov 16 20:19:59 UTC 2014


This is an automated email from the git hooks/post-receive script.

picca pushed a commit to branch master
in repository lmfit-py.

commit e70a6e14fc78d91523f450fbbd74930f46df248e
Author: Picca Frédéric-Emmanuel <picca at debian.org>
Date:   Sun Nov 16 21:11:27 2014 +0100

    Imported Upstream version 0.8.1+dfsg.1
---
 .gitattributes            |   1 +
 MANIFEST.in               |   5 +-
 README.rst                |   4 +-
 doc/builtin_models.rst    | 155 ++++++--
 doc/model.rst             |   2 +-
 lmfit/__init__.py         |   6 +-
 lmfit/_version.py         | 183 ++++++++++
 lmfit/astutils.py         | 135 ++++---
 lmfit/lineshapes.py       |   7 +
 lmfit/minimizer.py        |   1 +
 lmfit/model.py            |   9 +-
 lmfit/models.py           |  83 ++++-
 setup.py                  |  16 +-
 tests/test_default_kws.py |  25 ++
 upload_wininst.bat        |   8 +-
 versioneer.py             | 901 ++++++++++++++++++++++++++++++++++++++++++++++
 16 files changed, 1419 insertions(+), 122 deletions(-)

diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..8bde2c9
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1 @@
+lmfit/_version.py export-subst
diff --git a/MANIFEST.in b/MANIFEST.in
index f97651e..0cf6f34 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,8 +1,11 @@
-include README.txt INSTALL LICENSE MANIFEST.in PKG-INFO 
+include README.txt INSTALL LICENSE MANIFEST.in PKG-INFO THANKS.txt
 include setup.py publish_docs.sh
+include requirements.txt
 exclude *.pyc core.* *~ *.pdf
 recursive-include lmfit *.py
 recursive-include tests *.py *.dat
 recursive-include doc *
 recursive-exclude doc/_build *
 recursive-exclude doc *.pdf
+include versioneer.py
+include lmfit/_version.py
diff --git a/README.rst b/README.rst
index 0175924..fb37334 100644
--- a/README.rst
+++ b/README.rst
@@ -4,8 +4,8 @@ LMfit-py
 .. image:: https://travis-ci.org/lmfit/lmfit-py.png
    :target: https://travis-ci.org/lmfit/lmfit-py
 
-.. image:: https://zenodo.org/badge/4185/lmfit/lmfit-py.png
-   :target: http://dx.doi.org/??/zenodo.?
+.. image:: https://zenodo.org/badge/doi/10.5281/zenodo.11813.png
+   :target: http://dx.doi.org/10.5281/zenodo.11813
 
 LMfit-py provides a Least-Squares Minimization routine and class
 with a simple, flexible approach to parameterizing a model for
diff --git a/doc/builtin_models.rst b/doc/builtin_models.rst
index a6d310e..5bb1911 100644
--- a/doc/builtin_models.rst
+++ b/doc/builtin_models.rst
@@ -6,21 +6,20 @@ Built-in Fitting Models in the :mod:`models` module
 
 .. module:: models
 
-
 Lmfit provides several builtin fitting models in the :mod:`models` module.
-These pre-defined models each subclass from the :class:`Model` class of the
+These pre-defined models each subclass from the :class:`model.Model` class of the
 previous chapter and wrap relatively well-known functional forms, such as
 Gaussians, Lorentzian, and Exponentials that are used in a wide range of
 scientific domains.  In fact, all the models are all based on simple, plain
 python functions defined in the :mod:`lineshapes` module.  In addition to
-wrapping a function into a :class:`Model`, these models also provide a
+wrapping a function into a :class:`model.Model`, these models also provide a
 :meth:`guess` method that is intended to give a reasonable
 set of starting values from a data array that closely approximates the
 data to be fit.
 
-As shown in the previous chapter, a key feature of the :class:`Model` class
+As shown in the previous chapter, a key feature of the :class:`mode.Model` class
 is that models can easily be combined to give a composite
-:class:`Model`. Thus while some of the models listed here may seem pretty
+:class:`model.Model`. Thus while some of the models listed here may seem pretty
 trivial (notably, :class:`ConstantModel` and :class:`LinearModel`), the
 main point of having these is to be able to used in composite models.  For
 example,  a Lorentzian plus a linear background might be represented as::
@@ -54,8 +53,7 @@ methods for all of these make a fairly crude guess for the value of
 :class:`GaussianModel`
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-
-.. class:: GaussianModel()
+.. class:: GaussianModel(missing=None[, prefix=''[, name=None[, **kws]]])
 
 A model based on a `Gaussian or normal distribution lineshape
 <http://en.wikipedia.org/wiki/Normal_distribution>`_.  Parameter names:
@@ -75,7 +73,7 @@ Half-Maximum is :math:`2\sigma\sqrt{2\ln{2}}`, approximately
 :class:`LorentzianModel`
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-.. class:: LorentzianModel()
+.. class:: LorentzianModel(missing=None[, prefix=''[, name=None[, **kws]]])
 
 A model based on a `Lorentzian or Cauchy-Lorentz distribution function
 <http://en.wikipedia.org/wiki/Cauchy_distribution>`_.  Parameter names:
@@ -94,7 +92,7 @@ Half-Maximum is :math:`2\sigma`.
 :class:`VoigtModel`
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-.. class:: VoigtModel()
+.. class:: VoigtModel(missing=None[, prefix=''[, name=None[, **kws]]])
 
 A model based on a `Voigt distribution function
 <http://en.wikipedia.org/wiki/Voigt_profile>`_.  Parameter names:
@@ -129,7 +127,7 @@ the full width at half maximum is approximately :math:`3.6013\sigma`.
 :class:`PseudoVoigtModel`
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-.. class:: PseudoVoigtModel()
+.. class:: PseudoVoigtModel(missing=None[, prefix=''[, name=None[, **kws]]])
 
 a model based on a `pseudo-Voigt distribution function
 <http://en.wikipedia.org/wiki/Voigt_profile#Pseudo-Voigt_Approximation>`_,
@@ -150,7 +148,7 @@ value for ``fraction`` of 0.5
 :class:`Pearson7Model`
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-.. class:: Pearson7Model()
+.. class:: Pearson7Model(missing=None[, prefix=''[, name=None[, **kws]]])
 
 A model based on a `Pearson VII distribution
 <http://en.wikipedia.org/wiki/Pearson_distribution#The_Pearson_type_VII_distribution>`_.
@@ -169,7 +167,7 @@ gives a starting value for ``exponent`` of 1.5.
 :class:`StudentsTModel`
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-.. class:: StudentsTModel()
+.. class:: StudentsTModel(missing=None[, prefix=''[, name=None[, **kws]]])
 
 A model based on a `Student's t distribution function
 <http://en.wikipedia.org/wiki/Student%27s_t-distribution>`_, with the usual
@@ -187,7 +185,7 @@ where :math:`\Gamma(x)` is the gamma function.
 :class:`BreitWignerModel`
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-.. class:: BreitWignerModel()
+.. class:: BreitWignerModel(missing=None[, prefix=''[, name=None[, **kws]]])
 
 A model based on a `Breit-Wigner-Fano function
 <http://en.wikipedia.org/wiki/Fano_resonance>`_.  It has the usual
@@ -202,7 +200,7 @@ parameters ``amplitude`` (:math:`A`), ``center`` (:math:`\mu`) and
 :class:`LognormalModel`
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-.. class:: LognormalModel()
+.. class:: LognormalModel(missing=None[, prefix=''[, name=None[, **kws]]])
 
 A model based on the `Log-normal distribution function
 <http://en.wikipedia.org/wiki/Lognormal>`_.
@@ -218,7 +216,7 @@ It has the usual parameters
 :class:`DampedOcsillatorModel`
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-.. class:: DampedOcsillatorModel()
+.. class:: DampedOcsillatorModel(missing=None[, prefix=''[, name=None[, **kws]]])
 
 A model based on the `Damped Harmonic Oscillator Amplitude
 <http://en.wikipedia.org/wiki/Harmonic_oscillator#Amplitude_part>`_.
@@ -233,7 +231,7 @@ It has the usual parameters ``amplitude`` (:math:`A`), ``center`` (:math:`\mu`)
 :class:`ExponentialGaussianModel`
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-.. class:: ExponentialGaussianModel()
+.. class:: ExponentialGaussianModel(missing=None[, prefix=''[, name=None[, **kws]]])
 
 A model of an `Exponentially modified Gaussian distribution
 <http://en.wikipedia.org/wiki/Exponentially_modified_Gaussian_distribution>`_.
@@ -252,7 +250,7 @@ where :func:`erfc` is the complimentary error function.
 :class:`SkewedGaussianModel`
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-.. class:: SkewedGaussianModel()
+.. class:: SkewedGaussianModel(missing=None[, prefix=''[, name=None[, **kws]]])
 
 A variation of the above model, this is a `Skewed normal distribution
 <http://en.wikipedia.org/wiki/Skew_normal_distribution>`_.
@@ -274,7 +272,7 @@ where :func:`erf` is the error function.
 :class:`DonaichModel`
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-.. class:: DonaichModel()
+.. class:: DonaichModel(missing=None[, prefix=''[, name=None[, **kws]]])
 
 A model of an `Doniach Sunjic asymmetric lineshape
 <http://www.casaxps.com/help_manual/line_shapes.htm>`_, used in
@@ -299,7 +297,7 @@ of many components of composite model.
 :class:`ConstantModel`
 ~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-.. class:: ConstantModel()
+.. class:: ConstantModel(missing=None[, prefix=''[, name=None[, **kws]]])
 
    a class that consists of a single value, ``c``.  This is constant in the
    sense of having no dependence on the independent variable ``x``, not in
@@ -309,7 +307,7 @@ of many components of composite model.
 :class:`LinearModel`
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-.. class:: LinearModel()
+.. class:: LinearModel(missing=None[, prefix=''[, name=None[, **kws]]])
 
    a class that gives a linear model:
 
@@ -323,7 +321,7 @@ with parameters ``slope`` for :math:`m` and  ``intercept`` for :math:`b`.
 :class:`QuadraticModel`
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-.. class:: QuadraticModel()
+.. class:: QuadraticModel(missing=None[, prefix=''[, name=None[, **kws]]])
 
 
    a class that gives a quadratic model:
@@ -338,7 +336,7 @@ with parameters ``a``, ``b``, and ``c``.
 :class:`ParabolicModel`
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-.. class:: ParabolicModel()
+.. class:: ParabolicModel(missing=None[, prefix=''[, name=None[, **kws]]])
 
    same as :class:`QuadraticModel`.
 
@@ -347,7 +345,7 @@ with parameters ``a``, ``b``, and ``c``.
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 
-.. class:: PolynomialModel(degree)
+.. class:: PolynomialModel(degree, missing=None[, prefix=''[, name=None[, **kws]]])
 
    a class that gives a polynomial model up to ``degree`` (with maximum
    value of 7).
@@ -365,11 +363,12 @@ will specify how many of these are actual variable parameters.  This uses
 Step-like models
 -----------------------------------------------
 
+Two models represent step-like functions, and share many characteristics.
 
 :class:`StepModel`
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-.. class:: StepModel(form='linear')
+.. class:: StepModel(form='linear'[, missing=None[, prefix=''[, name=None[, **kws]]]])
 
 A model based on a Step function, with four choices for functional form.
 The step function starts with a value 0, and ends with a value of :math:`A`
@@ -396,7 +395,7 @@ where :math:`\alpha  = (x - \mu)/{\sigma}`.
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 
-.. class:: RectangleModel(form='linear')
+.. class:: RectangleModel(form='linear'[, missing=None[, prefix=''[, name=None[, **kws]]]])
 
 A model based on a Step-up and Step-down function of the same form.  The
 same choices for functional form as for :class:`StepModel` are supported,
@@ -426,7 +425,7 @@ Exponential and Power law models
 :class:`ExponentialModel`
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-.. class:: ExponentialModel()
+.. class:: ExponentialModel(missing=None[, prefix=''[, name=None[, **kws]]])
 
 A model based on an `exponential decay function
 <http://en.wikipedia.org/wiki/Exponential_decay>`_. With parameters named
@@ -440,7 +439,7 @@ A model based on an `exponential decay function
 :class:`PowerLawModel`
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-.. class:: PowerLawModel()
+.. class:: PowerLawModel(missing=None[, prefix=''[, name=None[, **kws]]])
 
 A model based on a `Power Law <http://en.wikipedia.org/wiki/Power_law>`_.
 With parameters
@@ -452,6 +451,102 @@ form:
    f(x; A, k) = A x^k
 
 
+User-defined Models
+----------------------------
+
+.. _asteval: http://newville.github.io/asteval/
+
+As shown in the previous chapter (:ref:`model_chapter`), it is fairly
+straightforward to build fitting models from parametrized python functions.
+The number of model classes listed so far in the present chapter should
+make it clear that this process is not too difficult.  Still, it is
+sometimes desirable to build models from a user-supplied function.  This
+may be especially true if model-building is built-in to some larger library
+or application for fitting in which the user may not be able to easily
+build and use a new model from python code.
+
+
+The :class:`ExpressionModel` allows a model to be built from a
+user-supplied expression.  This uses the `asteval`_ module also used for
+mathematical constraints as discussed in :ref:`constraints_chapter`.
+
+
+:class:`ExpressionModel`
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. class:: ExpressionModel(expr, independent_vars=None, init_script=None, missing=None, prefix='', name=None, **kws)
+
+    A model using the user-supplied mathematical expression, which can be nearly any valid Python expresion.
+
+    :param expr: expression use to build model
+    :type expr: string
+    :param init_script: python script to run before parsing and evaluating expression.
+    :type init_script: ``None`` (default) or string
+    :param independent_vars: list of argument names to ``func`` that are independent variables.
+    :type independent_vars: ``None`` (default) or list of strings for independent variables.
+
+with other parameters passed to :class:`model.Model`.
+
+Since the point of this model is that an arbitrary expression will be
+supplied, the determination of what are the parameter names for the model
+happens when the model is created.  To do this, the expression is parsed,
+and all symbol names are found.  Names that are already known (there are
+over 500 function and value names in the asteval namespace, including most
+python builtins, more than 200 functions inherited from numpy, and more
+than 20 common lineshapes defined in the :mod:`lineshapes` module) are not
+converted to parameters.  Unrecognized name are expected to be names either
+of parameters or independent variables.  If `independent_vars` is the
+default value of ``None``, and if the expression contains a variable named
+`x`, that will be used as the independent variable.  Otherwise,
+`independent_vars` must be given.
+
+For example, if one creates an :class:`ExpressionModel` as::
+
+    >>> mod = ExpressionModel('off + amp * exp(-x/x0) * sin(x*phase)')
+
+The name `exp` will be recognized as the exponent function, so the model
+will be interpreted to have parameters named `off`, `amp`, `x0` and
+`phase`, and `x` will be assumed to be the sole independent variable.
+In general, there is no obvious way to set default parameter values or
+parameter hints for bounds, so this will have to be handled explicitly.
+
+To evaluate this model, you might do the following::
+
+    >>> x = numpy.linspace(0, 10, 501)
+    >>> params = mod.make_params(off=0.25, amp=1.0, x0=2.0, phase=0.04)
+    >>> y = mod.eval(params, x=x)
+
+
+While many custom models can be built with a single line expression
+(especially since the names of the lineshapes like `gaussian`, `lorentzian`
+and so on, as well as many numpy functions, are available), more complex
+models will inevitably require multiple line functions.  You can include
+such Python code with the `init_script` argument.  The text of this script
+is evaluated when the model is initialized (and before the actual
+expression is parsed), so that you can define functions to be used
+in your expression.
+
+As a probably unphysical example, to make a model that is the derivative of
+a Gaussian function times the logarithm of a Lorenztian function you may
+could to define this in a script::
+
+    >>> script = """
+    def mycurve(x, amp, cen, sig):
+        loren = lorentzian(x, amplitude=amp, center=cen, sigma=sig)
+        gauss = gaussian(x, amplitude=ampa, center=cen, sigma=sig)
+        return log(loren)*gradient(gauss)/gradient(x)
+    """
+
+and then use this with :class:`ExpressionModel` as::
+
+    >>> mod = ExpressionModel('mycurve(x, height, mid, wid)',
+                              init_script=script,
+                              independent_vars=['x'])
+
+As above, this will interpret the parameter names to be `height`, `mid`,
+and `wid`, and build a model that can be used to fit data.
+
+
 
 Example 1: Fit Peaked data to Gaussian, Lorentzian, and  Voigt profiles
 ------------------------------------------------------------------------
@@ -642,7 +737,7 @@ Example 2: Fit data to a Composite Model with pre-defined models
 ------------------------------------------------------------------
 
 Here, we repeat the point made at the end of the last chapter that instances
-of :class:`Model` class can be added them together to make a *composite
+of :class:`model.Model` class can be added them together to make a *composite
 model*.  But using the large number of built-in models available, this is
 very simple.  An example of a simple fit to a noisy step function plus a
 constant:
@@ -694,7 +789,7 @@ Example 3: Fitting Multiple Peaks -- and using Prefixes
 As shown above, many of the models have similar parameter names.  For
 composite models, this could lead to a problem of having parameters for
 different parts of the model having the same name.  To overcome this, each
-:class:`Model` can have a ``prefix`` attribute (normally set to a blank
+:class:`model.Model` can have a ``prefix`` attribute (normally set to a blank
 string) that will be put at the beginning of each parameter name.  To
 illustrate, we fit one of the classic datasets from the `NIST StRD`_ suite
 involving a decaying exponential and two gaussians.
@@ -823,5 +918,3 @@ and without any bounds on parameters at all::
 This example is in the file ``doc_nistgauss2.py`` in the examples folder,
 and the fit result shown on the right above shows an improved initial
 estimate of the data.
-
-
diff --git a/doc/model.rst b/doc/model.rst
index 7ece86d..82551db 100644
--- a/doc/model.rst
+++ b/doc/model.rst
@@ -4,6 +4,7 @@
 Modeling Data and Curve Fitting
 =================================================
 
+.. module:: model
 
 A common use of least-squares minimization is *curve fitting*, where one
 has a parametrized model function meant to explain some phenomena and wants
@@ -945,4 +946,3 @@ we can do similarly::
 
 It is evident that assigning names will help to easily distinguish
 the different models.
-
diff --git a/lmfit/__init__.py b/lmfit/__init__.py
index 5329d4c..fe436e8 100644
--- a/lmfit/__init__.py
+++ b/lmfit/__init__.py
@@ -33,7 +33,6 @@ from scipy.optimize.  It has a number of useful enhancements, including:
              Daniel B. Allen, Johns Hopkins University
              Antonino Ingargiola, University of California, Los Angeles
 """
-__version__ = '0.8.0'
 
 from .minimizer import minimize, Minimizer, MinimizerException
 from .parameter import Parameter, Parameters
@@ -48,3 +47,8 @@ from . import uncertainties
 from .uncertainties import ufloat, correlated_values
 
 from .ui import Fitter
+
+## versioneer code
+from ._version import get_versions
+__version__ = get_versions()['version']
+del get_versions
diff --git a/lmfit/_version.py b/lmfit/_version.py
new file mode 100644
index 0000000..2edcc4f
--- /dev/null
+++ b/lmfit/_version.py
@@ -0,0 +1,183 @@
+
+# This file helps to compute a version number in source trees obtained from
+# git-archive tarball (such as those provided by githubs download-from-tag
+# feature). Distribution tarballs (built by setup.py sdist) and build
+# directories (produced by setup.py build) will contain a much shorter file
+# that just contains the computed version number.
+
+# This file is released into the public domain. Generated by
+# versioneer-0.12 (https://github.com/warner/python-versioneer)
+
+# these strings will be replaced by git during git-archive
+git_refnames = " (HEAD, tag: 0.8.1, master)"
+git_full = "0e2ad768ce26589b95f61e92ba4bac60cbba2bc3"
+
+# these strings are filled in when 'setup.py versioneer' creates _version.py
+tag_prefix = ""
+parentdir_prefix = "lmfit-"
+versionfile_source = "lmfit/_version.py"
+
+import os, sys, re, subprocess, errno
+
+def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False):
+    assert isinstance(commands, list)
+    p = None
+    for c in commands:
+        try:
+            # remember shell=False, so use git.cmd on windows, not just git
+            p = subprocess.Popen([c] + args, cwd=cwd, stdout=subprocess.PIPE,
+                                 stderr=(subprocess.PIPE if hide_stderr
+                                         else None))
+            break
+        except EnvironmentError:
+            e = sys.exc_info()[1]
+            if e.errno == errno.ENOENT:
+                continue
+            if verbose:
+                print("unable to run %s" % args[0])
+                print(e)
+            return None
+    else:
+        if verbose:
+            print("unable to find command, tried %s" % (commands,))
+        return None
+    stdout = p.communicate()[0].strip()
+    if sys.version >= '3':
+        stdout = stdout.decode()
+    if p.returncode != 0:
+        if verbose:
+            print("unable to run %s (error)" % args[0])
+        return None
+    return stdout
+
+
+def versions_from_parentdir(parentdir_prefix, root, verbose=False):
+    # Source tarballs conventionally unpack into a directory that includes
+    # both the project name and a version string.
+    dirname = os.path.basename(root)
+    if not dirname.startswith(parentdir_prefix):
+        if verbose:
+            print("guessing rootdir is '%s', but '%s' doesn't start with prefix '%s'" %
+                  (root, dirname, parentdir_prefix))
+        return None
+    return {"version": dirname[len(parentdir_prefix):], "full": ""}
+
+def git_get_keywords(versionfile_abs):
+    # the code embedded in _version.py can just fetch the value of these
+    # keywords. When used from setup.py, we don't want to import _version.py,
+    # so we do it with a regexp instead. This function is not used from
+    # _version.py.
+    keywords = {}
+    try:
+        f = open(versionfile_abs,"r")
+        for line in f.readlines():
+            if line.strip().startswith("git_refnames ="):
+                mo = re.search(r'=\s*"(.*)"', line)
+                if mo:
+                    keywords["refnames"] = mo.group(1)
+            if line.strip().startswith("git_full ="):
+                mo = re.search(r'=\s*"(.*)"', line)
+                if mo:
+                    keywords["full"] = mo.group(1)
+        f.close()
+    except EnvironmentError:
+        pass
+    return keywords
+
+def git_versions_from_keywords(keywords, tag_prefix, verbose=False):
+    if not keywords:
+        return {} # keyword-finding function failed to find keywords
+    refnames = keywords["refnames"].strip()
+    if refnames.startswith("$Format"):
+        if verbose:
+            print("keywords are unexpanded, not using")
+        return {} # unexpanded, so not in an unpacked git-archive tarball
+    refs = set([r.strip() for r in refnames.strip("()").split(",")])
+    # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of
+    # just "foo-1.0". If we see a "tag: " prefix, prefer those.
+    TAG = "tag: "
+    tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)])
+    if not tags:
+        # Either we're using git < 1.8.3, or there really are no tags. We use
+        # a heuristic: assume all version tags have a digit. The old git %d
+        # expansion behaves like git log --decorate=short and strips out the
+        # refs/heads/ and refs/tags/ prefixes that would let us distinguish
+        # between branches and tags. By ignoring refnames without digits, we
+        # filter out many common branch names like "release" and
+        # "stabilization", as well as "HEAD" and "master".
+        tags = set([r for r in refs if re.search(r'\d', r)])
+        if verbose:
+            print("discarding '%s', no digits" % ",".join(refs-tags))
+    if verbose:
+        print("likely tags: %s" % ",".join(sorted(tags)))
+    for ref in sorted(tags):
+        # sorting will prefer e.g. "2.0" over "2.0rc1"
+        if ref.startswith(tag_prefix):
+            r = ref[len(tag_prefix):]
+            if verbose:
+                print("picking %s" % r)
+            return { "version": r,
+                     "full": keywords["full"].strip() }
+    # no suitable tags, so we use the full revision id
+    if verbose:
+        print("no suitable tags, using full revision id")
+    return { "version": keywords["full"].strip(),
+             "full": keywords["full"].strip() }
+
+
+def git_versions_from_vcs(tag_prefix, root, verbose=False):
+    # this runs 'git' from the root of the source tree. This only gets called
+    # if the git-archive 'subst' keywords were *not* expanded, and
+    # _version.py hasn't already been rewritten with a short version string,
+    # meaning we're inside a checked out source tree.
+
+    if not os.path.exists(os.path.join(root, ".git")):
+        if verbose:
+            print("no .git in %s" % root)
+        return {}
+
+    GITS = ["git"]
+    if sys.platform == "win32":
+        GITS = ["git.cmd", "git.exe"]
+    stdout = run_command(GITS, ["describe", "--tags", "--dirty", "--always"],
+                         cwd=root)
+    if stdout is None:
+        return {}
+    if not stdout.startswith(tag_prefix):
+        if verbose:
+            print("tag '%s' doesn't start with prefix '%s'" % (stdout, tag_prefix))
+        return {}
+    tag = stdout[len(tag_prefix):]
+    stdout = run_command(GITS, ["rev-parse", "HEAD"], cwd=root)
+    if stdout is None:
+        return {}
+    full = stdout.strip()
+    if tag.endswith("-dirty"):
+        full += "-dirty"
+    return {"version": tag, "full": full}
+
+
+def get_versions(default={"version": "unknown", "full": ""}, verbose=False):
+    # I am in _version.py, which lives at ROOT/VERSIONFILE_SOURCE. If we have
+    # __file__, we can work backwards from there to the root. Some
+    # py2exe/bbfreeze/non-CPython implementations don't do __file__, in which
+    # case we can only use expanded keywords.
+
+    keywords = { "refnames": git_refnames, "full": git_full }
+    ver = git_versions_from_keywords(keywords, tag_prefix, verbose)
+    if ver:
+        return ver
+
+    try:
+        root = os.path.abspath(__file__)
+        # versionfile_source is the relative path from the top of the source
+        # tree (where the .git directory might live) to this file. Invert
+        # this to find the root from __file__.
+        for i in range(len(versionfile_source.split(os.sep))):
+            root = os.path.dirname(root)
+    except NameError:
+        return default
+
+    return (git_versions_from_vcs(tag_prefix, root, verbose)
+            or versions_from_parentdir(parentdir_prefix, root, verbose)
+            or default)
diff --git a/lmfit/astutils.py b/lmfit/astutils.py
index 7c75dc0..719bf27 100644
--- a/lmfit/astutils.py
+++ b/lmfit/astutils.py
@@ -57,44 +57,34 @@ FROM_MATH = ('acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh',
              'modf', 'pi', 'pow', 'radians', 'sin', 'sinh', 'sqrt', 'tan',
              'tanh', 'trunc')
 
-# inherit these from numpy, if available
-FROM_NUMPY = ('Inf', 'NAN', 'abs', 'absolute', 'add', 'alen', 'all',
-              'allclose', 'alltrue', 'alterdot', 'amax', 'amin', 'angle',
-              'any', 'append', 'apply_along_axis', 'apply_over_axes',
-              'arange', 'arccos', 'arccosh', 'arcsin', 'arcsinh', 'arctan',
-              'arctan2', 'arctanh', 'argmax', 'argmin', 'argsort',
-              'argwhere', 'around', 'array', 'array2string', 'array_equal',
-              'array_equiv', 'array_repr', 'array_split', 'array_str',
-              'asanyarray', 'asarray', 'asarray_chkfinite',
+FROM_NUMPY = ('Inf', 'NAN', 'abs', 'add', 'alen', 'all', 'amax', 'amin',
+              'angle', 'any', 'append', 'arange', 'arccos', 'arccosh',
+              'arcsin', 'arcsinh', 'arctan', 'arctan2', 'arctanh',
+              'argmax', 'argmin', 'argsort', 'argwhere', 'around', 'array',
+              'array2string', 'asanyarray', 'asarray', 'asarray_chkfinite',
               'ascontiguousarray', 'asfarray', 'asfortranarray',
               'asmatrix', 'asscalar', 'atleast_1d', 'atleast_2d',
-              'atleast_3d', 'average', 'bartlett', 'base_repr', 'bench',
-              'binary_repr', 'bincount', 'bitwise_and', 'bitwise_not',
-              'bitwise_or', 'bitwise_xor', 'blackman', 'bmat', 'bool',
-              'bool8', 'broadcast', 'broadcast_arrays', 'byte',
-              'byte_bounds', 'bytes_', 'c_', 'can_cast', 'cast', 'cdouble',
-              'ceil', 'cfloat', 'char', 'character', 'chararray', 'choose',
+              'atleast_3d', 'average', 'bartlett', 'base_repr',
+              'bitwise_and', 'bitwise_not', 'bitwise_or', 'bitwise_xor',
+              'blackman', 'bool', 'broadcast', 'broadcast_arrays', 'byte',
+              'c_', 'cdouble', 'ceil', 'cfloat', 'chararray', 'choose',
               'clip', 'clongdouble', 'clongfloat', 'column_stack',
-              'common_type', 'compare_chararrays', 'compat', 'complex',
-              'complex128', 'complex64', 'complex_', 'complexfloating',
-              'compress', 'concatenate', 'conj', 'conjugate', 'convolve',
-              'copy', 'copysign', 'core', 'corrcoef', 'correlate', 'cos',
-              'cosh', 'cov', 'cross', 'csingle', 'ctypeslib', 'cumprod',
-              'cumproduct', 'cumsum', 'datetime_data', 'deg2rad',
-              'degrees', 'delete', 'diag', 'diag_indices',
-              'diag_indices_from', 'diagflat', 'diagonal', 'diff',
-              'digitize', 'disp', 'divide', 'dot', 'double', 'dsplit',
-              'dstack', 'dtype', 'e', 'ediff1d', 'emath', 'empty',
-              'empty_like', 'equal', 'exp', 'exp2', 'expand_dims', 'expm1',
-              'extract', 'eye', 'fabs', 'fft', 'fill_diagonal',
-              'find_common_type', 'finfo', 'fix', 'flatiter',
-              'flatnonzero', 'flexible', 'fliplr', 'flipud', 'float',
-              'float32', 'float64', 'float_', 'floating', 'floor',
+              'common_type', 'complex', 'complex128', 'complex64',
+              'complex_', 'complexfloating', 'compress', 'concatenate',
+              'conjugate', 'convolve', 'copy', 'copysign', 'corrcoef',
+              'correlate', 'cos', 'cosh', 'cov', 'cross', 'csingle',
+              'cumprod', 'cumsum', 'datetime_data', 'deg2rad', 'degrees',
+              'delete', 'diag', 'diag_indices', 'diag_indices_from',
+              'diagflat', 'diagonal', 'diff', 'digitize', 'divide', 'dot',
+              'double', 'dsplit', 'dstack', 'dtype', 'e', 'ediff1d',
+              'empty', 'empty_like', 'equal', 'exp', 'exp2', 'expand_dims',
+              'expm1', 'extract', 'eye', 'fabs', 'fill_diagonal', 'finfo',
+              'fix', 'flatiter', 'flatnonzero', 'fliplr', 'flipud',
+              'float', 'float32', 'float64', 'float_', 'floating', 'floor',
               'floor_divide', 'fmax', 'fmin', 'fmod', 'format_parser',
               'frexp', 'frombuffer', 'fromfile', 'fromfunction',
               'fromiter', 'frompyfunc', 'fromregex', 'fromstring', 'fv',
-              'generic', 'genfromtxt', 'getbufsize', 'geterr',
-              'geterrcall', 'geterrobj', 'gradient', 'greater',
+              'genfromtxt', 'getbufsize', 'geterr', 'gradient', 'greater',
               'greater_equal', 'hamming', 'hanning', 'histogram',
               'histogram2d', 'histogramdd', 'hsplit', 'hstack', 'hypot',
               'i0', 'identity', 'iinfo', 'imag', 'in1d', 'index_exp',
@@ -104,49 +94,43 @@ FROM_NUMPY = ('Inf', 'NAN', 'abs', 'absolute', 'add', 'alen', 'all',
               'intersect1d', 'intp', 'invert', 'ipmt', 'irr', 'iscomplex',
               'iscomplexobj', 'isfinite', 'isfortran', 'isinf', 'isnan',
               'isneginf', 'isposinf', 'isreal', 'isrealobj', 'isscalar',
-              'issctype', 'issubclass_', 'issubdtype', 'issubsctype',
-              'iterable', 'ix_', 'kaiser', 'kron', 'ldexp', 'left_shift',
-              'less', 'less_equal', 'lexsort', 'lib', 'linalg', 'linspace',
+              'issctype', 'iterable', 'ix_', 'kaiser', 'kron', 'ldexp',
+              'left_shift', 'less', 'less_equal', 'linspace',
               'little_endian', 'load', 'loads', 'loadtxt', 'log', 'log10',
               'log1p', 'log2', 'logaddexp', 'logaddexp2', 'logical_and',
               'logical_not', 'logical_or', 'logical_xor', 'logspace',
               'long', 'longcomplex', 'longdouble', 'longfloat', 'longlong',
-              'lookfor', 'ma', 'mafromtxt', 'mask_indices', 'mat', 'math',
-              'matrix', 'matrixlib', 'max', 'maximum', 'maximum_sctype',
-              'may_share_memory', 'mean', 'median', 'memmap', 'meshgrid',
-              'mgrid', 'min', 'minimum', 'mintypecode', 'mirr', 'mod',
-              'modf', 'msort', 'multiply', 'nan', 'nan_to_num',
-              'nanargmax', 'nanargmin', 'nanmax', 'nanmin', 'nansum',
-              'nbytes', 'ndarray', 'ndenumerate', 'ndfromtxt', 'ndim',
-              'ndindex', 'negative', 'newaxis', 'nextafter', 'nonzero',
-              'not_equal', 'nper', 'npv', 'number', 'obj2sctype', 'object',
-              'object0', 'object_', 'ogrid', 'ones', 'ones_like', 'outer',
-              'packbits', 'percentile', 'pi', 'piecewise', 'pkgload',
-              'place', 'pmt', 'poly', 'poly1d', 'polyadd', 'polyder',
-              'polydiv', 'polyfit', 'polyint', 'polymul', 'polynomial',
-              'polysub', 'polyval', 'power', 'ppmt', 'prod', 'product',
-              'ptp', 'put', 'putmask', 'pv', 'r_', 'rad2deg', 'radians',
-              'random', 'rank', 'rate', 'ravel', 'real', 'real_if_close',
-              'rec', 'recarray', 'recfromcsv', 'recfromtxt', 'reciprocal',
-              'record', 'remainder', 'repeat', 'require', 'reshape',
-              'resize', 'restoredot', 'right_shift', 'rint', 'roll',
-              'rollaxis', 'roots', 'rot90', 'round', 'round_', 'row_stack',
-              's_', 'sctype2char', 'sctypeDict', 'sctypeNA', 'sctypes',
-              'searchsorted', 'select', 'setbufsize', 'setdiff1d',
-              'seterr', 'setxor1d', 'shape', 'short', 'sign', 'signbit',
-              'signedinteger', 'sin', 'sinc', 'single', 'singlecomplex',
-              'sinh', 'size', 'sometrue', 'sort', 'sort_complex', 'source',
-              'spacing', 'split', 'sqrt', 'square', 'squeeze', 'std',
-              'str', 'str_', 'subtract', 'sum', 'swapaxes', 'take', 'tan',
-              'tanh', 'tensordot', 'test', 'testing', 'tile', 'trace',
-              'transpose', 'trapz', 'tri', 'tril', 'tril_indices',
-              'tril_indices_from', 'trim_zeros', 'triu', 'triu_indices',
-              'triu_indices_from', 'true_divide', 'trunc', 'typeDict',
-              'typeNA', 'typecodes', 'typename', 'ubyte', 'ufunc', 'uint',
-              'uint0', 'uint16', 'uint32', 'uint64', 'uint8', 'uintc',
-              'uintp', 'ulonglong', 'union1d', 'unique', 'unravel_index',
-              'unsignedinteger', 'unwrap', 'ushort', 'vander', 'var',
-              'vdot', 'vectorize', 'version', 'void', 'void0', 'vsplit',
+              'mafromtxt', 'mask_indices', 'mat', 'matrix', 'max',
+              'maximum', 'maximum_sctype', 'may_share_memory', 'mean',
+              'median', 'memmap', 'meshgrid', 'mgrid', 'min', 'minimum',
+              'mintypecode', 'mirr', 'mod', 'modf', 'msort', 'multiply',
+              'nan', 'nan_to_num', 'nanargmax', 'nanargmin', 'nanmax',
+              'nanmin', 'nansum', 'ndarray', 'ndenumerate', 'ndfromtxt',
+              'ndim', 'ndindex', 'negative', 'newaxis', 'nextafter',
+              'nonzero', 'not_equal', 'nper', 'npv', 'number',
+              'obj2sctype', 'ogrid', 'ones', 'ones_like', 'outer',
+              'packbits', 'percentile', 'pi', 'piecewise', 'place', 'pmt',
+              'poly', 'poly1d', 'polyadd', 'polyder', 'polydiv', 'polyfit',
+              'polyint', 'polymul', 'polysub', 'polyval', 'power', 'ppmt',
+              'prod', 'product', 'ptp', 'put', 'putmask', 'pv', 'r_',
+              'rad2deg', 'radians', 'rank', 'rate', 'ravel', 'real',
+              'real_if_close', 'reciprocal', 'record', 'remainder',
+              'repeat', 'reshape', 'resize', 'restoredot', 'right_shift',
+              'rint', 'roll', 'rollaxis', 'roots', 'rot90', 'round',
+              'round_', 'row_stack', 's_', 'sctype2char', 'searchsorted',
+              'select', 'setbufsize', 'setdiff1d', 'seterr', 'setxor1d',
+              'shape', 'short', 'sign', 'signbit', 'signedinteger', 'sin',
+              'sinc', 'single', 'singlecomplex', 'sinh', 'size',
+              'sometrue', 'sort', 'sort_complex', 'spacing', 'split',
+              'sqrt', 'square', 'squeeze', 'std', 'str', 'str_',
+              'subtract', 'sum', 'swapaxes', 'take', 'tan', 'tanh',
+              'tensordot', 'tile', 'trace', 'transpose', 'trapz', 'tri',
+              'tril', 'tril_indices', 'tril_indices_from', 'trim_zeros',
+              'triu', 'triu_indices', 'triu_indices_from', 'true_divide',
+              'trunc', 'ubyte', 'uint', 'uint0', 'uint16', 'uint32',
+              'uint64', 'uint8', 'uintc', 'uintp', 'ulonglong', 'union1d',
+              'unique', 'unravel_index', 'unsignedinteger', 'unwrap',
+              'ushort', 'vander', 'var', 'vdot', 'vectorize', 'vsplit',
               'vstack', 'where', 'who', 'zeros', 'zeros_like')
 
 NUMPY_RENAMES = {'ln': 'log', 'asin': 'arcsin', 'acos': 'arccos',
@@ -262,8 +246,13 @@ class NameFinder(ast.NodeVisitor):
         ast.NodeVisitor.__init__(self)
 
     def generic_visit(self, node):
-        nodename = node.__class__.__name__.lower()
-        if nodename == 'name':
+        if node.__class__.__name__ == 'Name':
             if node.ctx.__class__ == ast.Load and node.id not in self.names:
                 self.names.append(node.id)
         ast.NodeVisitor.generic_visit(self, node)
+
+def get_ast_names(astnode):
+    "returns symbol Names from an AST node"
+    finder = NameFinder()
+    finder.generic_visit(astnode)
+    return finder.names
diff --git a/lmfit/lineshapes.py b/lmfit/lineshapes.py
index 87004b2..d99c9be 100644
--- a/lmfit/lineshapes.py
+++ b/lmfit/lineshapes.py
@@ -13,6 +13,13 @@ s2pi = sqrt(2*pi)
 spi  = sqrt(pi)
 s2   = sqrt(2.0)
 
+functions = ('gaussian', 'lorentzian', 'voigt', 'pvoigt', 'pearson7',
+             'breit_wigner', 'damped_oscillator', 'logistic', 'lognormal',
+             'students_t', 'expgaussian', 'donaich', 'skewed_gaussian',
+             'skewed_voigt', 'step', 'rectangle', 'erf', 'erfc', 'wofz',
+             'gamma', 'gammaln', 'exponential', 'powerlaw', 'linear',
+             'parabolic')
+
 def gaussian(x, amplitude=1.0, center=0.0, sigma=1.0):
     """1 dimensional gaussian:
     gaussian(x, amplitude, center, sigma)
diff --git a/lmfit/minimizer.py b/lmfit/minimizer.py
index 11e0b00..9a8f241 100644
--- a/lmfit/minimizer.py
+++ b/lmfit/minimizer.py
@@ -345,6 +345,7 @@ or set  leastsq_kws['maxfev']  to increase this maximum."""
                         maxfun=5000 * (self.nvarys + 1))
 
         fmin_kws.update(kws)
+
         ret = scipy_fmin(self.penalty, self.vars, **fmin_kws)
         xout, fout, niter, funccalls, warnflag, allvecs = ret
         self.nfev = funccalls
diff --git a/lmfit/model.py b/lmfit/model.py
index b08972e..a60fc70 100644
--- a/lmfit/model.py
+++ b/lmfit/model.py
@@ -399,7 +399,7 @@ class Model(object):
         return result
 
     def fit(self, data, params=None, weights=None, method='leastsq',
-            iter_cb=None, scale_covar=True, verbose=True, **kwargs):
+            iter_cb=None, scale_covar=True, verbose=True, fit_kws=None, **kwargs):
         """Fit the model to the data.
 
         Parameters
@@ -413,6 +413,8 @@ class Model(object):
         scale_covar:  bool (default True) whether to auto-scale covariance matrix
         verbose: bool (default True) print a message when a new parameter is
             added because of a hint.
+        fit_kws: dict
+            default fitting options, such as xtol and maxfev, for scipy optimizer
         keyword arguments: optional, named like the arguments of the
             model function, will override params. See examples below.
 
@@ -496,8 +498,11 @@ class Model(object):
             if not np.isscalar(kwargs[var]):
                 kwargs[var] = _align(kwargs[var], mask, data)
 
+        if fit_kws is None:
+            fit_kws = {}
+
         output = ModelFit(self, params, method=method, iter_cb=iter_cb,
-                          scale_covar=scale_covar, fcn_kws=kwargs)
+                          scale_covar=scale_covar, fcn_kws=kwargs, **fit_kws)
         output.fit(data=data, weights=weights)
         return output
 
diff --git a/lmfit/models.py b/lmfit/models.py
index f2242b2..775e371 100644
--- a/lmfit/models.py
+++ b/lmfit/models.py
@@ -8,6 +8,11 @@ from .lineshapes import (gaussian, lorentzian, voigt, pvoigt, pearson7,
                          skewed_voigt, exponential, powerlaw, linear,
                          parabolic)
 
+from . import lineshapes
+
+from .asteval import Interpreter
+from .astutils import get_ast_names
+
 class DimensionalError(Exception):
     pass
 
@@ -74,9 +79,10 @@ missing: None, 'drop', or 'raise'
         silently fall back to numpy.isnan.
     'raise': Raise a (more helpful) exception when data contains null
         or missing values.
-suffix: string to append to paramter names, needed to add two Models that
+prefix: string to prepend to paramter names, needed to add two Models that
     have parameter names in common. None by default.
 """
+
 class ConstantModel(Model):
     __doc__ = "x -> c" + COMMON_DOC
     def __init__(self, *args, **kwargs):
@@ -344,3 +350,78 @@ class RectangleModel(Model):
         pars['%ssigma2' % self.prefix].set(value=(xmax-xmin)/7.0, min=0.0)
         return update_param_vals(pars, self.prefix, **kwargs)
 
+
+class ExpressionModel(Model):
+    """Model from User-supplied expression
+
+%s
+    """ % COMMON_DOC
+
+    idvar_missing  = "No independent variable found in\n %s"
+    idvar_notfound = "Cannot find independent variables '%s' in\n %s"
+    def __init__(self, expr, independent_vars=None, init_script=None,
+                 *args, **kwargs):
+
+        # create ast evaluator, load custom functions
+        self.asteval = Interpreter()
+        for name in lineshapes.functions:
+            self.asteval.symtable[name] = getattr(lineshapes, name, None)
+        if init_script is not None:
+            self.asteval.eval(init_script)
+
+        # save expr as text, parse to ast, save for later use
+        self.expr = expr
+        self.astcode = self.asteval.parse(expr)
+
+        # find all symbol names found in expression
+        sym_names = get_ast_names(self.astcode)
+
+        if independent_vars is None and 'x' in sym_names:
+            independent_vars = ['x']
+        if independent_vars is None:
+            raise ValueError(self.idvar_missing % (self.expr))
+
+        # determine which named symbols are parameter names,
+        # try to find all independent variables
+        idvar_found = [False]*len(independent_vars)
+        param_names = []
+        for name in sym_names:
+            if name in independent_vars:
+                idvar_found[independent_vars.index(name)] = True
+            elif name not in self.asteval.symtable:
+                param_names.append(name)
+
+        # make sure we have all independent parameters
+        if not all(idvar_found):
+            lost = []
+            for ix, found in enumerate(idvar_found):
+                if not found:
+                    lost.append(independent_vars[ix])
+            lost = ', '.join(lost)
+            raise ValueError(self.idvar_notfound % (lost, self.expr))
+
+        kwargs['independent_vars'] = independent_vars
+
+        def _eval(**kwargs):
+            for name, val in kwargs.items():
+                self.asteval.symtable[name] = val
+            return self.asteval.run(self.astcode)
+
+        super(ExpressionModel, self).__init__(_eval, *args, **kwargs)
+
+        # set param names here, and other things normally
+        # set in _parse_params(), which will be short-circuited.
+        self.independent_vars = independent_vars
+        self._func_allargs = independent_vars + param_names
+        self._param_names = set(param_names)
+        self._func_haskeywords = True
+        self.def_vals = {}
+
+    def __repr__(self):
+        return  "<lmfit.ExpressionModel('%s')>" % (self.expr)
+
+    def _parse_params(self):
+        """ExpressionModel._parse_params is over-written (as `pass`)
+        to prevent normal parsing of function for parameter names
+        """
+        pass
diff --git a/setup.py b/setup.py
index 9dad2f1..720f8ec 100644
--- a/setup.py
+++ b/setup.py
@@ -2,8 +2,13 @@
 # from distutils.core import setup
 from setuptools import setup
 
-import lmfit as lmfit
-import numpy, scipy
+import versioneer
+versioneer.VCS = 'git'
+versioneer.versionfile_source = 'lmfit/_version.py'
+versioneer.versionfile_build = 'lmfit/_version.py'
+versioneer.tag_prefix = ''
+versioneer.parentdir_prefix = 'lmfit-'
+
 
 long_desc = """A library for least-squares minimization and data fitting in
 Python.  Built on top of scipy.optimize, lmfit provides a Parameter object
@@ -25,16 +30,17 @@ questionable. """
 
 
 setup(name = 'lmfit',
-      version = lmfit.__version__,
+      version = versioneer.get_version(),
+      cmdclass = versioneer.get_cmdclass(),
       author = 'LMFit Development Team',
       author_email = 'matt.newville at gmail.com',
       url          = 'http://lmfit.github.io/lmfit-py/',
       download_url = 'http://lmfit.github.io//lmfit-py/',
-      requires = ('numpy', 'scipy'),
+      requires = ['numpy', 'scipy'],
       license = 'BSD',
       description = "Least-Squares Minimization with Bounds and Constraints",
       long_description = long_desc,
-      platforms = ('Windows', 'Linux', 'Mac OS X'),
+      platforms = ['Windows', 'Linux', 'Mac OS X'],
       classifiers=['Intended Audience :: Science/Research',
                    'Operating System :: OS Independent',
                    'Programming Language :: Python',
diff --git a/tests/test_default_kws.py b/tests/test_default_kws.py
new file mode 100644
index 0000000..4d58f03
--- /dev/null
+++ b/tests/test_default_kws.py
@@ -0,0 +1,25 @@
+import numpy as np
+from nose.tools import assert_true
+from lmfit.lineshapes import gaussian
+from lmfit.models import GaussianModel
+
+
+def test_default_inputs_gauss():
+
+    area = 1
+    cen = 0
+    std = 0.2
+    x = np.arange(-3, 3, 0.01)
+    y = gaussian(x, area, cen, std)
+
+    g = GaussianModel()
+
+    fit_option1 = {'maxfev': 5000, 'xtol': 1e-2}
+    result1 = g.fit(y, x=x, amplitude=1, center=0, sigma=0.5, fit_kws=fit_option1)
+
+    fit_option2 = {'maxfev': 5000, 'xtol': 1e-6}
+    result2 = g.fit(y, x=x, amplitude=1, center=0, sigma=0.5, fit_kws=fit_option2)
+
+    assert_true(result1.values!=result2.values)
+
+    return
\ No newline at end of file
diff --git a/upload_wininst.bat b/upload_wininst.bat
index ebfe392..ffc60b9 100644
--- a/upload_wininst.bat
+++ b/upload_wininst.bat
@@ -2,17 +2,15 @@ REM
 REM  %HOME%\.pypirc must be setup with PyPI info.
 REM
 SET HOME=M:\
-SET PATH=C:\Python26;%PATH%
-python setup.py install
-python setup.py bdist_wininst --target-version=2.6 upload
 
 SET PATH=C:\Python27;%PATH%
 python setup.py install
 python setup.py bdist_wininst --target-version=2.7 upload
 
-SET PATH=C:\Python32;%PATH%
+
+SET PATH=C:\Python34;%PATH%
 python setup.py install
-python setup.py bdist_wininst --target-version=3.2 upload
+python setup.py bdist_wininst --target-version=3.4 upload
 
 
 
diff --git a/versioneer.py b/versioneer.py
new file mode 100644
index 0000000..481180d
--- /dev/null
+++ b/versioneer.py
@@ -0,0 +1,901 @@
+
+# Version: 0.12
+
+"""
+The Versioneer
+==============
+
+* like a rocketeer, but for versions!
+* https://github.com/warner/python-versioneer
+* Brian Warner
+* License: Public Domain
+* Compatible With: python2.6, 2.7, 3.2, 3.3, 3.4, and pypy
+
+[![Build Status](https://travis-ci.org/warner/python-versioneer.png?branch=master)](https://travis-ci.org/warner/python-versioneer)
+
+This is a tool for managing a recorded version number in distutils-based
+python projects. The goal is to remove the tedious and error-prone "update
+the embedded version string" step from your release process. Making a new
+release should be as easy as recording a new tag in your version-control
+system, and maybe making new tarballs.
+
+
+## Quick Install
+
+* `pip install versioneer` to somewhere to your $PATH
+* run `versioneer-installer` in your source tree: this installs `versioneer.py`
+* follow the instructions below (also in the `versioneer.py` docstring)
+
+## Version Identifiers
+
+Source trees come from a variety of places:
+
+* a version-control system checkout (mostly used by developers)
+* a nightly tarball, produced by build automation
+* a snapshot tarball, produced by a web-based VCS browser, like github's
+  "tarball from tag" feature
+* a release tarball, produced by "setup.py sdist", distributed through PyPI
+
+Within each source tree, the version identifier (either a string or a number,
+this tool is format-agnostic) can come from a variety of places:
+
+* ask the VCS tool itself, e.g. "git describe" (for checkouts), which knows
+  about recent "tags" and an absolute revision-id
+* the name of the directory into which the tarball was unpacked
+* an expanded VCS keyword ($Id$, etc)
+* a `_version.py` created by some earlier build step
+
+For released software, the version identifier is closely related to a VCS
+tag. Some projects use tag names that include more than just the version
+string (e.g. "myproject-1.2" instead of just "1.2"), in which case the tool
+needs to strip the tag prefix to extract the version identifier. For
+unreleased software (between tags), the version identifier should provide
+enough information to help developers recreate the same tree, while also
+giving them an idea of roughly how old the tree is (after version 1.2, before
+version 1.3). Many VCS systems can report a description that captures this,
+for example 'git describe --tags --dirty --always' reports things like
+"0.7-1-g574ab98-dirty" to indicate that the checkout is one revision past the
+0.7 tag, has a unique revision id of "574ab98", and is "dirty" (it has
+uncommitted changes.
+
+The version identifier is used for multiple purposes:
+
+* to allow the module to self-identify its version: `myproject.__version__`
+* to choose a name and prefix for a 'setup.py sdist' tarball
+
+## Theory of Operation
+
+Versioneer works by adding a special `_version.py` file into your source
+tree, where your `__init__.py` can import it. This `_version.py` knows how to
+dynamically ask the VCS tool for version information at import time. However,
+when you use "setup.py build" or "setup.py sdist", `_version.py` in the new
+copy is replaced by a small static file that contains just the generated
+version data.
+
+`_version.py` also contains `$Revision$` markers, and the installation
+process marks `_version.py` to have this marker rewritten with a tag name
+during the "git archive" command. As a result, generated tarballs will
+contain enough information to get the proper version.
+
+
+## Installation
+
+First, decide on values for the following configuration variables:
+
+* `VCS`: the version control system you use. Currently accepts "git".
+
+* `versionfile_source`:
+
+  A project-relative pathname into which the generated version strings should
+  be written. This is usually a `_version.py` next to your project's main
+  `__init__.py` file, so it can be imported at runtime. If your project uses
+  `src/myproject/__init__.py`, this should be `src/myproject/_version.py`.
+  This file should be checked in to your VCS as usual: the copy created below
+  by `setup.py versioneer` will include code that parses expanded VCS
+  keywords in generated tarballs. The 'build' and 'sdist' commands will
+  replace it with a copy that has just the calculated version string.
+
+  This must be set even if your project does not have any modules (and will
+  therefore never import `_version.py`), since "setup.py sdist" -based trees
+  still need somewhere to record the pre-calculated version strings. Anywhere
+  in the source tree should do. If there is a `__init__.py` next to your
+  `_version.py`, the `setup.py versioneer` command (described below) will
+  append some `__version__`-setting assignments, if they aren't already
+  present.
+
+*  `versionfile_build`:
+
+  Like `versionfile_source`, but relative to the build directory instead of
+  the source directory. These will differ when your setup.py uses
+  'package_dir='. If you have `package_dir={'myproject': 'src/myproject'}`,
+  then you will probably have `versionfile_build='myproject/_version.py'` and
+  `versionfile_source='src/myproject/_version.py'`.
+
+  If this is set to None, then `setup.py build` will not attempt to rewrite
+  any `_version.py` in the built tree. If your project does not have any
+  libraries (e.g. if it only builds a script), then you should use
+  `versionfile_build = None` and override `distutils.command.build_scripts`
+  to explicitly insert a copy of `versioneer.get_version()` into your
+  generated script.
+
+* `tag_prefix`:
+
+  a string, like 'PROJECTNAME-', which appears at the start of all VCS tags.
+  If your tags look like 'myproject-1.2.0', then you should use
+  tag_prefix='myproject-'. If you use unprefixed tags like '1.2.0', this
+  should be an empty string.
+
+* `parentdir_prefix`:
+
+  a string, frequently the same as tag_prefix, which appears at the start of
+  all unpacked tarball filenames. If your tarball unpacks into
+  'myproject-1.2.0', this should be 'myproject-'.
+
+This tool provides one script, named `versioneer-installer`. That script does
+one thing: write a copy of `versioneer.py` into the current directory.
+
+To versioneer-enable your project:
+
+* 1: Run `versioneer-installer` to copy `versioneer.py` into the top of your
+  source tree.
+
+* 2: add the following lines to the top of your `setup.py`, with the
+  configuration values you decided earlier:
+
+        import versioneer
+        versioneer.VCS = 'git'
+        versioneer.versionfile_source = 'src/myproject/_version.py'
+        versioneer.versionfile_build = 'myproject/_version.py'
+        versioneer.tag_prefix = '' # tags are like 1.2.0
+        versioneer.parentdir_prefix = 'myproject-' # dirname like 'myproject-1.2.0'
+
+* 3: add the following arguments to the setup() call in your setup.py:
+
+        version=versioneer.get_version(),
+        cmdclass=versioneer.get_cmdclass(),
+
+* 4: now run `setup.py versioneer`, which will create `_version.py`, and will
+  modify your `__init__.py` (if one exists next to `_version.py`) to define
+  `__version__` (by calling a function from `_version.py`). It will also
+  modify your `MANIFEST.in` to include both `versioneer.py` and the generated
+  `_version.py` in sdist tarballs.
+
+* 5: commit these changes to your VCS. To make sure you won't forget,
+  `setup.py versioneer` will mark everything it touched for addition.
+
+## Post-Installation Usage
+
+Once established, all uses of your tree from a VCS checkout should get the
+current version string. All generated tarballs should include an embedded
+version string (so users who unpack them will not need a VCS tool installed).
+
+If you distribute your project through PyPI, then the release process should
+boil down to two steps:
+
+* 1: git tag 1.0
+* 2: python setup.py register sdist upload
+
+If you distribute it through github (i.e. users use github to generate
+tarballs with `git archive`), the process is:
+
+* 1: git tag 1.0
+* 2: git push; git push --tags
+
+Currently, all version strings must be based upon a tag. Versioneer will
+report "unknown" until your tree has at least one tag in its history. This
+restriction will be fixed eventually (see issue #12).
+
+## Version-String Flavors
+
+Code which uses Versioneer can learn about its version string at runtime by
+importing `_version` from your main `__init__.py` file and running the
+`get_versions()` function. From the "outside" (e.g. in `setup.py`), you can
+import the top-level `versioneer.py` and run `get_versions()`.
+
+Both functions return a dictionary with different keys for different flavors
+of the version string:
+
+* `['version']`: condensed tag+distance+shortid+dirty identifier. For git,
+  this uses the output of `git describe --tags --dirty --always` but strips
+  the tag_prefix. For example "0.11-2-g1076c97-dirty" indicates that the tree
+  is like the "1076c97" commit but has uncommitted changes ("-dirty"), and
+  that this commit is two revisions ("-2-") beyond the "0.11" tag. For
+  released software (exactly equal to a known tag), the identifier will only
+  contain the stripped tag, e.g. "0.11".
+
+* `['full']`: detailed revision identifier. For Git, this is the full SHA1
+  commit id, followed by "-dirty" if the tree contains uncommitted changes,
+  e.g. "1076c978a8d3cfc70f408fe5974aa6c092c949ac-dirty".
+
+Some variants are more useful than others. Including `full` in a bug report
+should allow developers to reconstruct the exact code being tested (or
+indicate the presence of local changes that should be shared with the
+developers). `version` is suitable for display in an "about" box or a CLI
+`--version` output: it can be easily compared against release notes and lists
+of bugs fixed in various releases.
+
+In the future, this will also include a
+[PEP-0440](http://legacy.python.org/dev/peps/pep-0440/) -compatible flavor
+(e.g. `1.2.post0.dev123`). This loses a lot of information (and has no room
+for a hash-based revision id), but is safe to use in a `setup.py`
+"`version=`" argument. It also enables tools like *pip* to compare version
+strings and evaluate compatibility constraint declarations.
+
+The `setup.py versioneer` command adds the following text to your
+`__init__.py` to place a basic version in `YOURPROJECT.__version__`:
+
+    from ._version import get_versions
+    __version__ = get_versions()['version']
+    del get_versions
+
+## Updating Versioneer
+
+To upgrade your project to a new release of Versioneer, do the following:
+
+* install the new Versioneer (`pip install -U versioneer` or equivalent)
+* re-run `versioneer-installer` in your source tree to replace your copy of
+  `versioneer.py`
+* edit `setup.py`, if necessary, to include any new configuration settings
+  indicated by the release notes
+* re-run `setup.py versioneer` to replace `SRC/_version.py`
+* commit any changed files
+
+### Upgrading from 0.10 to 0.11
+
+You must add a `versioneer.VCS = "git"` to your `setup.py` before re-running
+`setup.py versioneer`. This will enable the use of additional version-control
+systems (SVN, etc) in the future.
+
+### Upgrading from 0.11 to 0.12
+
+Nothing special.
+
+## Future Directions
+
+This tool is designed to make it easily extended to other version-control
+systems: all VCS-specific components are in separate directories like
+src/git/ . The top-level `versioneer.py` script is assembled from these
+components by running make-versioneer.py . In the future, make-versioneer.py
+will take a VCS name as an argument, and will construct a version of
+`versioneer.py` that is specific to the given VCS. It might also take the
+configuration arguments that are currently provided manually during
+installation by editing setup.py . Alternatively, it might go the other
+direction and include code from all supported VCS systems, reducing the
+number of intermediate scripts.
+
+
+## License
+
+To make Versioneer easier to embed, all its code is hereby released into the
+public domain. The `_version.py` that it creates is also in the public
+domain.
+
+"""
+
+import os, sys, re, subprocess, errno
+from distutils.core import Command
+from distutils.command.sdist import sdist as _sdist
+from distutils.command.build import build as _build
+
+# these configuration settings will be overridden by setup.py after it
+# imports us
+versionfile_source = None
+versionfile_build = None
+tag_prefix = None
+parentdir_prefix = None
+VCS = None
+
+# these dictionaries contain VCS-specific tools
+LONG_VERSION_PY = {}
+
+def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False):
+    assert isinstance(commands, list)
+    p = None
+    for c in commands:
+        try:
+            # remember shell=False, so use git.cmd on windows, not just git
+            p = subprocess.Popen([c] + args, cwd=cwd, stdout=subprocess.PIPE,
+                                 stderr=(subprocess.PIPE if hide_stderr
+                                         else None))
+            break
+        except EnvironmentError:
+            e = sys.exc_info()[1]
+            if e.errno == errno.ENOENT:
+                continue
+            if verbose:
+                print("unable to run %s" % args[0])
+                print(e)
+            return None
+    else:
+        if verbose:
+            print("unable to find command, tried %s" % (commands,))
+        return None
+    stdout = p.communicate()[0].strip()
+    if sys.version >= '3':
+        stdout = stdout.decode()
+    if p.returncode != 0:
+        if verbose:
+            print("unable to run %s (error)" % args[0])
+        return None
+    return stdout
+
+LONG_VERSION_PY['git'] = '''
+# This file helps to compute a version number in source trees obtained from
+# git-archive tarball (such as those provided by githubs download-from-tag
+# feature). Distribution tarballs (built by setup.py sdist) and build
+# directories (produced by setup.py build) will contain a much shorter file
+# that just contains the computed version number.
+
+# This file is released into the public domain. Generated by
+# versioneer-0.12 (https://github.com/warner/python-versioneer)
+
+# these strings will be replaced by git during git-archive
+git_refnames = "%(DOLLAR)sFormat:%%d%(DOLLAR)s"
+git_full = "%(DOLLAR)sFormat:%%H%(DOLLAR)s"
+
+# these strings are filled in when 'setup.py versioneer' creates _version.py
+tag_prefix = "%(TAG_PREFIX)s"
+parentdir_prefix = "%(PARENTDIR_PREFIX)s"
+versionfile_source = "%(VERSIONFILE_SOURCE)s"
+
+import os, sys, re, subprocess, errno
+
+def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False):
+    assert isinstance(commands, list)
+    p = None
+    for c in commands:
+        try:
+            # remember shell=False, so use git.cmd on windows, not just git
+            p = subprocess.Popen([c] + args, cwd=cwd, stdout=subprocess.PIPE,
+                                 stderr=(subprocess.PIPE if hide_stderr
+                                         else None))
+            break
+        except EnvironmentError:
+            e = sys.exc_info()[1]
+            if e.errno == errno.ENOENT:
+                continue
+            if verbose:
+                print("unable to run %%s" %% args[0])
+                print(e)
+            return None
+    else:
+        if verbose:
+            print("unable to find command, tried %%s" %% (commands,))
+        return None
+    stdout = p.communicate()[0].strip()
+    if sys.version >= '3':
+        stdout = stdout.decode()
+    if p.returncode != 0:
+        if verbose:
+            print("unable to run %%s (error)" %% args[0])
+        return None
+    return stdout
+
+
+def versions_from_parentdir(parentdir_prefix, root, verbose=False):
+    # Source tarballs conventionally unpack into a directory that includes
+    # both the project name and a version string.
+    dirname = os.path.basename(root)
+    if not dirname.startswith(parentdir_prefix):
+        if verbose:
+            print("guessing rootdir is '%%s', but '%%s' doesn't start with prefix '%%s'" %%
+                  (root, dirname, parentdir_prefix))
+        return None
+    return {"version": dirname[len(parentdir_prefix):], "full": ""}
+
+def git_get_keywords(versionfile_abs):
+    # the code embedded in _version.py can just fetch the value of these
+    # keywords. When used from setup.py, we don't want to import _version.py,
+    # so we do it with a regexp instead. This function is not used from
+    # _version.py.
+    keywords = {}
+    try:
+        f = open(versionfile_abs,"r")
+        for line in f.readlines():
+            if line.strip().startswith("git_refnames ="):
+                mo = re.search(r'=\s*"(.*)"', line)
+                if mo:
+                    keywords["refnames"] = mo.group(1)
+            if line.strip().startswith("git_full ="):
+                mo = re.search(r'=\s*"(.*)"', line)
+                if mo:
+                    keywords["full"] = mo.group(1)
+        f.close()
+    except EnvironmentError:
+        pass
+    return keywords
+
+def git_versions_from_keywords(keywords, tag_prefix, verbose=False):
+    if not keywords:
+        return {} # keyword-finding function failed to find keywords
+    refnames = keywords["refnames"].strip()
+    if refnames.startswith("$Format"):
+        if verbose:
+            print("keywords are unexpanded, not using")
+        return {} # unexpanded, so not in an unpacked git-archive tarball
+    refs = set([r.strip() for r in refnames.strip("()").split(",")])
+    # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of
+    # just "foo-1.0". If we see a "tag: " prefix, prefer those.
+    TAG = "tag: "
+    tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)])
+    if not tags:
+        # Either we're using git < 1.8.3, or there really are no tags. We use
+        # a heuristic: assume all version tags have a digit. The old git %%d
+        # expansion behaves like git log --decorate=short and strips out the
+        # refs/heads/ and refs/tags/ prefixes that would let us distinguish
+        # between branches and tags. By ignoring refnames without digits, we
+        # filter out many common branch names like "release" and
+        # "stabilization", as well as "HEAD" and "master".
+        tags = set([r for r in refs if re.search(r'\d', r)])
+        if verbose:
+            print("discarding '%%s', no digits" %% ",".join(refs-tags))
+    if verbose:
+        print("likely tags: %%s" %% ",".join(sorted(tags)))
+    for ref in sorted(tags):
+        # sorting will prefer e.g. "2.0" over "2.0rc1"
+        if ref.startswith(tag_prefix):
+            r = ref[len(tag_prefix):]
+            if verbose:
+                print("picking %%s" %% r)
+            return { "version": r,
+                     "full": keywords["full"].strip() }
+    # no suitable tags, so we use the full revision id
+    if verbose:
+        print("no suitable tags, using full revision id")
+    return { "version": keywords["full"].strip(),
+             "full": keywords["full"].strip() }
+
+
+def git_versions_from_vcs(tag_prefix, root, verbose=False):
+    # this runs 'git' from the root of the source tree. This only gets called
+    # if the git-archive 'subst' keywords were *not* expanded, and
+    # _version.py hasn't already been rewritten with a short version string,
+    # meaning we're inside a checked out source tree.
+
+    if not os.path.exists(os.path.join(root, ".git")):
+        if verbose:
+            print("no .git in %%s" %% root)
+        return {}
+
+    GITS = ["git"]
+    if sys.platform == "win32":
+        GITS = ["git.cmd", "git.exe"]
+    stdout = run_command(GITS, ["describe", "--tags", "--dirty", "--always"],
+                         cwd=root)
+    if stdout is None:
+        return {}
+    if not stdout.startswith(tag_prefix):
+        if verbose:
+            print("tag '%%s' doesn't start with prefix '%%s'" %% (stdout, tag_prefix))
+        return {}
+    tag = stdout[len(tag_prefix):]
+    stdout = run_command(GITS, ["rev-parse", "HEAD"], cwd=root)
+    if stdout is None:
+        return {}
+    full = stdout.strip()
+    if tag.endswith("-dirty"):
+        full += "-dirty"
+    return {"version": tag, "full": full}
+
+
+def get_versions(default={"version": "unknown", "full": ""}, verbose=False):
+    # I am in _version.py, which lives at ROOT/VERSIONFILE_SOURCE. If we have
+    # __file__, we can work backwards from there to the root. Some
+    # py2exe/bbfreeze/non-CPython implementations don't do __file__, in which
+    # case we can only use expanded keywords.
+
+    keywords = { "refnames": git_refnames, "full": git_full }
+    ver = git_versions_from_keywords(keywords, tag_prefix, verbose)
+    if ver:
+        return ver
+
+    try:
+        root = os.path.abspath(__file__)
+        # versionfile_source is the relative path from the top of the source
+        # tree (where the .git directory might live) to this file. Invert
+        # this to find the root from __file__.
+        for i in range(len(versionfile_source.split(os.sep))):
+            root = os.path.dirname(root)
+    except NameError:
+        return default
+
+    return (git_versions_from_vcs(tag_prefix, root, verbose)
+            or versions_from_parentdir(parentdir_prefix, root, verbose)
+            or default)
+'''
+
+def git_get_keywords(versionfile_abs):
+    # the code embedded in _version.py can just fetch the value of these
+    # keywords. When used from setup.py, we don't want to import _version.py,
+    # so we do it with a regexp instead. This function is not used from
+    # _version.py.
+    keywords = {}
+    try:
+        f = open(versionfile_abs,"r")
+        for line in f.readlines():
+            if line.strip().startswith("git_refnames ="):
+                mo = re.search(r'=\s*"(.*)"', line)
+                if mo:
+                    keywords["refnames"] = mo.group(1)
+            if line.strip().startswith("git_full ="):
+                mo = re.search(r'=\s*"(.*)"', line)
+                if mo:
+                    keywords["full"] = mo.group(1)
+        f.close()
+    except EnvironmentError:
+        pass
+    return keywords
+
+def git_versions_from_keywords(keywords, tag_prefix, verbose=False):
+    if not keywords:
+        return {} # keyword-finding function failed to find keywords
+    refnames = keywords["refnames"].strip()
+    if refnames.startswith("$Format"):
+        if verbose:
+            print("keywords are unexpanded, not using")
+        return {} # unexpanded, so not in an unpacked git-archive tarball
+    refs = set([r.strip() for r in refnames.strip("()").split(",")])
+    # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of
+    # just "foo-1.0". If we see a "tag: " prefix, prefer those.
+    TAG = "tag: "
+    tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)])
+    if not tags:
+        # Either we're using git < 1.8.3, or there really are no tags. We use
+        # a heuristic: assume all version tags have a digit. The old git %d
+        # expansion behaves like git log --decorate=short and strips out the
+        # refs/heads/ and refs/tags/ prefixes that would let us distinguish
+        # between branches and tags. By ignoring refnames without digits, we
+        # filter out many common branch names like "release" and
+        # "stabilization", as well as "HEAD" and "master".
+        tags = set([r for r in refs if re.search(r'\d', r)])
+        if verbose:
+            print("discarding '%s', no digits" % ",".join(refs-tags))
+    if verbose:
+        print("likely tags: %s" % ",".join(sorted(tags)))
+    for ref in sorted(tags):
+        # sorting will prefer e.g. "2.0" over "2.0rc1"
+        if ref.startswith(tag_prefix):
+            r = ref[len(tag_prefix):]
+            if verbose:
+                print("picking %s" % r)
+            return { "version": r,
+                     "full": keywords["full"].strip() }
+    # no suitable tags, so we use the full revision id
+    if verbose:
+        print("no suitable tags, using full revision id")
+    return { "version": keywords["full"].strip(),
+             "full": keywords["full"].strip() }
+
+
+def git_versions_from_vcs(tag_prefix, root, verbose=False):
+    # this runs 'git' from the root of the source tree. This only gets called
+    # if the git-archive 'subst' keywords were *not* expanded, and
+    # _version.py hasn't already been rewritten with a short version string,
+    # meaning we're inside a checked out source tree.
+
+    if not os.path.exists(os.path.join(root, ".git")):
+        if verbose:
+            print("no .git in %s" % root)
+        return {}
+
+    GITS = ["git"]
+    if sys.platform == "win32":
+        GITS = ["git.cmd", "git.exe"]
+    stdout = run_command(GITS, ["describe", "--tags", "--dirty", "--always"],
+                         cwd=root)
+    if stdout is None:
+        return {}
+    if not stdout.startswith(tag_prefix):
+        if verbose:
+            print("tag '%s' doesn't start with prefix '%s'" % (stdout, tag_prefix))
+        return {}
+    tag = stdout[len(tag_prefix):]
+    stdout = run_command(GITS, ["rev-parse", "HEAD"], cwd=root)
+    if stdout is None:
+        return {}
+    full = stdout.strip()
+    if tag.endswith("-dirty"):
+        full += "-dirty"
+    return {"version": tag, "full": full}
+
+
+def do_vcs_install(manifest_in, versionfile_source, ipy):
+    GITS = ["git"]
+    if sys.platform == "win32":
+        GITS = ["git.cmd", "git.exe"]
+    files = [manifest_in, versionfile_source]
+    if ipy:
+        files.append(ipy)
+    try:
+        me = __file__
+        if me.endswith(".pyc") or me.endswith(".pyo"):
+            me = os.path.splitext(me)[0] + ".py"
+        versioneer_file = os.path.relpath(me)
+    except NameError:
+        versioneer_file = "versioneer.py"
+    files.append(versioneer_file)
+    present = False
+    try:
+        f = open(".gitattributes", "r")
+        for line in f.readlines():
+            if line.strip().startswith(versionfile_source):
+                if "export-subst" in line.strip().split()[1:]:
+                    present = True
+        f.close()
+    except EnvironmentError:
+        pass
+    if not present:
+        f = open(".gitattributes", "a+")
+        f.write("%s export-subst\n" % versionfile_source)
+        f.close()
+        files.append(".gitattributes")
+    run_command(GITS, ["add", "--"] + files)
+
+def versions_from_parentdir(parentdir_prefix, root, verbose=False):
+    # Source tarballs conventionally unpack into a directory that includes
+    # both the project name and a version string.
+    dirname = os.path.basename(root)
+    if not dirname.startswith(parentdir_prefix):
+        if verbose:
+            print("guessing rootdir is '%s', but '%s' doesn't start with prefix '%s'" %
+                  (root, dirname, parentdir_prefix))
+        return None
+    return {"version": dirname[len(parentdir_prefix):], "full": ""}
+
+SHORT_VERSION_PY = """
+# This file was generated by 'versioneer.py' (0.12) from
+# revision-control system data, or from the parent directory name of an
+# unpacked source archive. Distribution tarballs contain a pre-generated copy
+# of this file.
+
+version_version = '%(version)s'
+version_full = '%(full)s'
+def get_versions(default={}, verbose=False):
+    return {'version': version_version, 'full': version_full}
+
+"""
+
+DEFAULT = {"version": "unknown", "full": "unknown"}
+
+def versions_from_file(filename):
+    versions = {}
+    try:
+        with open(filename) as f:
+            for line in f.readlines():
+                mo = re.match("version_version = '([^']+)'", line)
+                if mo:
+                    versions["version"] = mo.group(1)
+                mo = re.match("version_full = '([^']+)'", line)
+                if mo:
+                    versions["full"] = mo.group(1)
+    except EnvironmentError:
+        return {}
+
+    return versions
+
+def write_to_version_file(filename, versions):
+    with open(filename, "w") as f:
+        f.write(SHORT_VERSION_PY % versions)
+
+    print("set %s to '%s'" % (filename, versions["version"]))
+
+
+def get_root():
+    try:
+        return os.path.dirname(os.path.abspath(__file__))
+    except NameError:
+        return os.path.dirname(os.path.abspath(sys.argv[0]))
+
+def vcs_function(vcs, suffix):
+    return getattr(sys.modules[__name__], '%s_%s' % (vcs, suffix), None)
+
+def get_versions(default=DEFAULT, verbose=False):
+    # returns dict with two keys: 'version' and 'full'
+    assert versionfile_source is not None, "please set versioneer.versionfile_source"
+    assert tag_prefix is not None, "please set versioneer.tag_prefix"
+    assert parentdir_prefix is not None, "please set versioneer.parentdir_prefix"
+    assert VCS is not None, "please set versioneer.VCS"
+
+    # I am in versioneer.py, which must live at the top of the source tree,
+    # which we use to compute the root directory. py2exe/bbfreeze/non-CPython
+    # don't have __file__, in which case we fall back to sys.argv[0] (which
+    # ought to be the setup.py script). We prefer __file__ since that's more
+    # robust in cases where setup.py was invoked in some weird way (e.g. pip)
+    root = get_root()
+    versionfile_abs = os.path.join(root, versionfile_source)
+
+    # extract version from first of _version.py, VCS command (e.g. 'git
+    # describe'), parentdir. This is meant to work for developers using a
+    # source checkout, for users of a tarball created by 'setup.py sdist',
+    # and for users of a tarball/zipball created by 'git archive' or github's
+    # download-from-tag feature or the equivalent in other VCSes.
+
+    get_keywords_f = vcs_function(VCS, "get_keywords")
+    versions_from_keywords_f = vcs_function(VCS, "versions_from_keywords")
+    if get_keywords_f and versions_from_keywords_f:
+        vcs_keywords = get_keywords_f(versionfile_abs)
+        ver = versions_from_keywords_f(vcs_keywords, tag_prefix)
+        if ver:
+            if verbose: print("got version from expanded keyword %s" % ver)
+            return ver
+
+    ver = versions_from_file(versionfile_abs)
+    if ver:
+        if verbose: print("got version from file %s %s" % (versionfile_abs,ver))
+        return ver
+
+    versions_from_vcs_f = vcs_function(VCS, "versions_from_vcs")
+    if versions_from_vcs_f:
+        ver = versions_from_vcs_f(tag_prefix, root, verbose)
+        if ver:
+            if verbose: print("got version from VCS %s" % ver)
+            return ver
+
+    ver = versions_from_parentdir(parentdir_prefix, root, verbose)
+    if ver:
+        if verbose: print("got version from parentdir %s" % ver)
+        return ver
+
+    if verbose: print("got version from default %s" % default)
+    return default
+
+def get_version(verbose=False):
+    return get_versions(verbose=verbose)["version"]
+
+class cmd_version(Command):
+    description = "report generated version string"
+    user_options = []
+    boolean_options = []
+    def initialize_options(self):
+        pass
+    def finalize_options(self):
+        pass
+    def run(self):
+        ver = get_version(verbose=True)
+        print("Version is currently: %s" % ver)
+
+
+class cmd_build(_build):
+    def run(self):
+        versions = get_versions(verbose=True)
+        _build.run(self)
+        # now locate _version.py in the new build/ directory and replace it
+        # with an updated value
+        if versionfile_build:
+            target_versionfile = os.path.join(self.build_lib, versionfile_build)
+            print("UPDATING %s" % target_versionfile)
+            os.unlink(target_versionfile)
+            with open(target_versionfile, "w") as f:
+                f.write(SHORT_VERSION_PY % versions)
+
+if 'cx_Freeze' in sys.modules:  # cx_freeze enabled?
+    from cx_Freeze.dist import build_exe as _build_exe
+
+    class cmd_build_exe(_build_exe):
+        def run(self):
+            versions = get_versions(verbose=True)
+            target_versionfile = versionfile_source
+            print("UPDATING %s" % target_versionfile)
+            os.unlink(target_versionfile)
+            with open(target_versionfile, "w") as f:
+                f.write(SHORT_VERSION_PY % versions)
+
+            _build_exe.run(self)
+            os.unlink(target_versionfile)
+            with open(versionfile_source, "w") as f:
+                assert VCS is not None, "please set versioneer.VCS"
+                LONG = LONG_VERSION_PY[VCS]
+                f.write(LONG % {"DOLLAR": "$",
+                                "TAG_PREFIX": tag_prefix,
+                                "PARENTDIR_PREFIX": parentdir_prefix,
+                                "VERSIONFILE_SOURCE": versionfile_source,
+                                })
+
+class cmd_sdist(_sdist):
+    def run(self):
+        versions = get_versions(verbose=True)
+        self._versioneer_generated_versions = versions
+        # unless we update this, the command will keep using the old version
+        self.distribution.metadata.version = versions["version"]
+        return _sdist.run(self)
+
+    def make_release_tree(self, base_dir, files):
+        _sdist.make_release_tree(self, base_dir, files)
+        # now locate _version.py in the new base_dir directory (remembering
+        # that it may be a hardlink) and replace it with an updated value
+        target_versionfile = os.path.join(base_dir, versionfile_source)
+        print("UPDATING %s" % target_versionfile)
+        os.unlink(target_versionfile)
+        with open(target_versionfile, "w") as f:
+            f.write(SHORT_VERSION_PY % self._versioneer_generated_versions)
+
+INIT_PY_SNIPPET = """
+from ._version import get_versions
+__version__ = get_versions()['version']
+del get_versions
+"""
+
+class cmd_update_files(Command):
+    description = "install/upgrade Versioneer files: __init__.py SRC/_version.py"
+    user_options = []
+    boolean_options = []
+    def initialize_options(self):
+        pass
+    def finalize_options(self):
+        pass
+    def run(self):
+        print(" creating %s" % versionfile_source)
+        with open(versionfile_source, "w") as f:
+            assert VCS is not None, "please set versioneer.VCS"
+            LONG = LONG_VERSION_PY[VCS]
+            f.write(LONG % {"DOLLAR": "$",
+                            "TAG_PREFIX": tag_prefix,
+                            "PARENTDIR_PREFIX": parentdir_prefix,
+                            "VERSIONFILE_SOURCE": versionfile_source,
+                            })
+
+        ipy = os.path.join(os.path.dirname(versionfile_source), "__init__.py")
+        if os.path.exists(ipy):
+            try:
+                with open(ipy, "r") as f:
+                    old = f.read()
+            except EnvironmentError:
+                old = ""
+            if INIT_PY_SNIPPET not in old:
+                print(" appending to %s" % ipy)
+                with open(ipy, "a") as f:
+                    f.write(INIT_PY_SNIPPET)
+            else:
+                print(" %s unmodified" % ipy)
+        else:
+            print(" %s doesn't exist, ok" % ipy)
+            ipy = None
+
+        # Make sure both the top-level "versioneer.py" and versionfile_source
+        # (PKG/_version.py, used by runtime code) are in MANIFEST.in, so
+        # they'll be copied into source distributions. Pip won't be able to
+        # install the package without this.
+        manifest_in = os.path.join(get_root(), "MANIFEST.in")
+        simple_includes = set()
+        try:
+            with open(manifest_in, "r") as f:
+                for line in f:
+                    if line.startswith("include "):
+                        for include in line.split()[1:]:
+                            simple_includes.add(include)
+        except EnvironmentError:
+            pass
+        # That doesn't cover everything MANIFEST.in can do
+        # (http://docs.python.org/2/distutils/sourcedist.html#commands), so
+        # it might give some false negatives. Appending redundant 'include'
+        # lines is safe, though.
+        if "versioneer.py" not in simple_includes:
+            print(" appending 'versioneer.py' to MANIFEST.in")
+            with open(manifest_in, "a") as f:
+                f.write("include versioneer.py\n")
+        else:
+            print(" 'versioneer.py' already in MANIFEST.in")
+        if versionfile_source not in simple_includes:
+            print(" appending versionfile_source ('%s') to MANIFEST.in" %
+                  versionfile_source)
+            with open(manifest_in, "a") as f:
+                f.write("include %s\n" % versionfile_source)
+        else:
+            print(" versionfile_source already in MANIFEST.in")
+
+        # Make VCS-specific changes. For git, this means creating/changing
+        # .gitattributes to mark _version.py for export-time keyword
+        # substitution.
+        do_vcs_install(manifest_in, versionfile_source, ipy)
+
+def get_cmdclass():
+    cmds = {'version': cmd_version,
+            'versioneer': cmd_update_files,
+            'build': cmd_build,
+            'sdist': cmd_sdist,
+            }
+    if 'cx_Freeze' in sys.modules:  # cx_freeze enabled?
+        cmds['build_exe'] = cmd_build_exe
+        del cmds['build']
+
+    return cmds

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/lmfit-py.git



More information about the debian-science-commits mailing list