[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