diffpy.srfit 3.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- diffpy/__init__.py +15 -0
- diffpy/srfit/__init__.py +41 -0
- diffpy/srfit/equation/__init__.py +31 -0
- diffpy/srfit/equation/builder.py +702 -0
- diffpy/srfit/equation/equationmod.py +213 -0
- diffpy/srfit/equation/literals/__init__.py +71 -0
- diffpy/srfit/equation/literals/abcs.py +81 -0
- diffpy/srfit/equation/literals/argument.py +76 -0
- diffpy/srfit/equation/literals/literal.py +69 -0
- diffpy/srfit/equation/literals/operators.py +380 -0
- diffpy/srfit/equation/visitors/__init__.py +94 -0
- diffpy/srfit/equation/visitors/argfinder.py +62 -0
- diffpy/srfit/equation/visitors/printer.py +120 -0
- diffpy/srfit/equation/visitors/swapper.py +142 -0
- diffpy/srfit/equation/visitors/validator.py +113 -0
- diffpy/srfit/equation/visitors/visitor.py +62 -0
- diffpy/srfit/exceptions.py +29 -0
- diffpy/srfit/fitbase/__init__.py +53 -0
- diffpy/srfit/fitbase/calculator.py +110 -0
- diffpy/srfit/fitbase/configurable.py +57 -0
- diffpy/srfit/fitbase/constraint.py +117 -0
- diffpy/srfit/fitbase/fitcontribution.py +351 -0
- diffpy/srfit/fitbase/fithook.py +227 -0
- diffpy/srfit/fitbase/fitrecipe.py +826 -0
- diffpy/srfit/fitbase/fitresults.py +674 -0
- diffpy/srfit/fitbase/parameter.py +314 -0
- diffpy/srfit/fitbase/parameterset.py +110 -0
- diffpy/srfit/fitbase/profile.py +405 -0
- diffpy/srfit/fitbase/profilegenerator.py +168 -0
- diffpy/srfit/fitbase/profileparser.py +179 -0
- diffpy/srfit/fitbase/recipeorganizer.py +1074 -0
- diffpy/srfit/fitbase/restraint.py +117 -0
- diffpy/srfit/fitbase/simplerecipe.py +230 -0
- diffpy/srfit/fitbase/validatable.py +59 -0
- diffpy/srfit/interface/__init__.py +33 -0
- diffpy/srfit/interface/interface.py +180 -0
- diffpy/srfit/pdf/__init__.py +24 -0
- diffpy/srfit/pdf/basepdfgenerator.py +296 -0
- diffpy/srfit/pdf/characteristicfunctions.py +432 -0
- diffpy/srfit/pdf/debyepdfgenerator.py +115 -0
- diffpy/srfit/pdf/pdfcontribution.py +311 -0
- diffpy/srfit/pdf/pdfgenerator.py +77 -0
- diffpy/srfit/pdf/pdfparser.py +226 -0
- diffpy/srfit/sas/__init__.py +30 -0
- diffpy/srfit/sas/prcalculator.py +139 -0
- diffpy/srfit/sas/sasgenerator.py +70 -0
- diffpy/srfit/sas/sasimport.py +66 -0
- diffpy/srfit/sas/sasparameter.py +70 -0
- diffpy/srfit/sas/sasparser.py +133 -0
- diffpy/srfit/sas/sasprofile.py +94 -0
- diffpy/srfit/structure/__init__.py +60 -0
- diffpy/srfit/structure/basestructureparset.py +62 -0
- diffpy/srfit/structure/bvsrestraint.py +101 -0
- diffpy/srfit/structure/cctbxparset.py +292 -0
- diffpy/srfit/structure/diffpyparset.py +303 -0
- diffpy/srfit/structure/objcrystparset.py +1552 -0
- diffpy/srfit/structure/sgconstraints.py +761 -0
- diffpy/srfit/structure/srrealparset.py +92 -0
- diffpy/srfit/util/__init__.py +50 -0
- diffpy/srfit/util/argbinders.py +29 -0
- diffpy/srfit/util/inpututils.py +50 -0
- diffpy/srfit/util/nameutils.py +45 -0
- diffpy/srfit/util/observable.py +93 -0
- diffpy/srfit/util/tagmanager.py +150 -0
- diffpy/srfit/util/weakrefcallable.py +170 -0
- diffpy/srfit/version.py +26 -0
- diffpy_srfit-3.1.0.dist-info/METADATA +216 -0
- diffpy_srfit-3.1.0.dist-info/RECORD +73 -0
- diffpy_srfit-3.1.0.dist-info/WHEEL +5 -0
- diffpy_srfit-3.1.0.dist-info/licenses/AUTHORS.rst +10 -0
- diffpy_srfit-3.1.0.dist-info/licenses/LICENSE.rst +138 -0
- diffpy_srfit-3.1.0.dist-info/licenses/LICENSE_DANSE.rst +34 -0
- diffpy_srfit-3.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
##############################################################################
|
|
3
|
+
#
|
|
4
|
+
# diffpy.srfit by DANSE Diffraction group
|
|
5
|
+
# Simon J. L. Billinge
|
|
6
|
+
# (c) 2009 The Trustees of Columbia University
|
|
7
|
+
# in the City of New York. All rights reserved.
|
|
8
|
+
#
|
|
9
|
+
# File coded by: Chris Farrow
|
|
10
|
+
#
|
|
11
|
+
# See AUTHORS.txt for a list of people who contributed.
|
|
12
|
+
# See LICENSE_DANSE.txt for license information.
|
|
13
|
+
#
|
|
14
|
+
##############################################################################
|
|
15
|
+
"""Structure wrapper class for structures compatible with SrReal."""
|
|
16
|
+
|
|
17
|
+
__all__ = ["SrRealParSet"]
|
|
18
|
+
|
|
19
|
+
from diffpy.srfit.structure.basestructureparset import BaseStructureParSet
|
|
20
|
+
from diffpy.srfit.structure.bvsrestraint import BVSRestraint
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class SrRealParSet(BaseStructureParSet):
|
|
24
|
+
"""Base class for SrReal-compatible structure adapters.
|
|
25
|
+
|
|
26
|
+
This derives from BaseStructureParSet and provides some extended
|
|
27
|
+
functionality provided by SrReal.
|
|
28
|
+
|
|
29
|
+
Attributes:
|
|
30
|
+
stru -- The adapted object
|
|
31
|
+
_usesymmetry -- A flag indicating if SrReal calculators that operate on
|
|
32
|
+
this object should use symmetry. By default this is
|
|
33
|
+
True.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
def __init__(self, *args, **kw):
|
|
37
|
+
BaseStructureParSet.__init__(self, *args, **kw)
|
|
38
|
+
self._usesymmetry = True
|
|
39
|
+
self.stru = None
|
|
40
|
+
return
|
|
41
|
+
|
|
42
|
+
def restrainBVS(self, sig=1, scaled=False):
|
|
43
|
+
"""Restrain the bond-valence sum to zero.
|
|
44
|
+
|
|
45
|
+
This adds a penalty to the cost function equal to
|
|
46
|
+
bvmsdiff / sig**2
|
|
47
|
+
where bvmsdiff is the mean-squared difference between the calculated
|
|
48
|
+
and expected bond valence sums for the structure. If scaled is True,
|
|
49
|
+
this is also scaled by the current point-averaged chi^2 value so the
|
|
50
|
+
restraint is roughly equally weighted in the fit.
|
|
51
|
+
|
|
52
|
+
sig -- The uncertainty on the BVS (default 1).
|
|
53
|
+
scaled -- A flag indicating if the restraint is scaled
|
|
54
|
+
(multiplied) by the unrestrained point-average chi^2
|
|
55
|
+
(chi^2/numpoints) (default False).
|
|
56
|
+
|
|
57
|
+
Returns the BVSRestraint object for use with the 'unrestrain' method.
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
# Create the Restraint object
|
|
61
|
+
res = BVSRestraint(self, sig, scaled)
|
|
62
|
+
# Add it to the _restraints set
|
|
63
|
+
self._restraints.add(res)
|
|
64
|
+
# Our configuration changed. Notify observers.
|
|
65
|
+
self._updateConfiguration()
|
|
66
|
+
# Return the Restraint object
|
|
67
|
+
return res
|
|
68
|
+
|
|
69
|
+
def useSymmetry(self, use=True):
|
|
70
|
+
"""Set this structure to use symmetry.
|
|
71
|
+
|
|
72
|
+
This determines how the structure is treated by SrReal
|
|
73
|
+
calculators.
|
|
74
|
+
"""
|
|
75
|
+
self._usesymmetry = bool(use)
|
|
76
|
+
return
|
|
77
|
+
|
|
78
|
+
def usingSymmetry(self):
|
|
79
|
+
"""Check if symmetry is being used."""
|
|
80
|
+
return self._usesymmetry
|
|
81
|
+
|
|
82
|
+
def _getSrRealStructure(self):
|
|
83
|
+
"""Get the structure object for use with SrReal calculators.
|
|
84
|
+
|
|
85
|
+
If this is periodic, then return the structure, otherwise, pass
|
|
86
|
+
it inside of a nosymmetry wrapper.
|
|
87
|
+
"""
|
|
88
|
+
from diffpy.srreal.structureadapter import nosymmetry
|
|
89
|
+
|
|
90
|
+
if self._usesymmetry:
|
|
91
|
+
return self.stru
|
|
92
|
+
return nosymmetry(self.stru)
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
##############################################################################
|
|
3
|
+
#
|
|
4
|
+
# diffpy.srfit by DANSE Diffraction group
|
|
5
|
+
# Simon J. L. Billinge
|
|
6
|
+
# (c) 2008 The Trustees of Columbia University
|
|
7
|
+
# in the City of New York. All rights reserved.
|
|
8
|
+
#
|
|
9
|
+
# File coded by: Chris Farrow
|
|
10
|
+
#
|
|
11
|
+
# See AUTHORS.txt for a list of people who contributed.
|
|
12
|
+
# See LICENSE_DANSE.txt for license information.
|
|
13
|
+
#
|
|
14
|
+
##############################################################################
|
|
15
|
+
"""Utilities and constants used throughout SrFit."""
|
|
16
|
+
|
|
17
|
+
_DASHEDLINE = 78 * "-"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def sortKeyForNumericString(s):
|
|
21
|
+
"""Compute key for sorting strings according to their integer numeric
|
|
22
|
+
value.
|
|
23
|
+
|
|
24
|
+
Each string gets split to string and integer segments to create keys
|
|
25
|
+
for comparison. Signs, decimal points and exponents are ignored.
|
|
26
|
+
This function is intended as the ``key`` argument for the ``sorted``
|
|
27
|
+
or ``list.sort`` function.
|
|
28
|
+
|
|
29
|
+
Parameters
|
|
30
|
+
----------
|
|
31
|
+
s : str
|
|
32
|
+
String which may have numeric components, e.g., "a12b".
|
|
33
|
+
|
|
34
|
+
Returns
|
|
35
|
+
-------
|
|
36
|
+
tuple
|
|
37
|
+
Tuple of non-numeric segments intermixed with integer values.
|
|
38
|
+
"""
|
|
39
|
+
if sortKeyForNumericString._rx is None:
|
|
40
|
+
import re
|
|
41
|
+
|
|
42
|
+
sortKeyForNumericString._rx = re.compile(r"(\d+)")
|
|
43
|
+
rx = sortKeyForNumericString._rx
|
|
44
|
+
rv = tuple((int(w) if i % 2 else w) for i, w in enumerate(rx.split(s)))
|
|
45
|
+
return rv
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
sortKeyForNumericString._rx = None
|
|
49
|
+
|
|
50
|
+
# End of file
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
##############################################################################
|
|
3
|
+
#
|
|
4
|
+
# diffpy.srfit Complex Modeling Initiative
|
|
5
|
+
# (c) 2014 Brookhaven Science Associates,
|
|
6
|
+
# Brookhaven National Laboratory.
|
|
7
|
+
# All rights reserved.
|
|
8
|
+
#
|
|
9
|
+
# File coded by: Pavol Juhas
|
|
10
|
+
#
|
|
11
|
+
# See AUTHORS.txt for a list of people who contributed.
|
|
12
|
+
# See LICENSE.txt for license information.
|
|
13
|
+
#
|
|
14
|
+
##############################################################################
|
|
15
|
+
"""Functions for binding arguments of callable objects."""
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class bind2nd(object):
|
|
19
|
+
"""Freeze second argument of a callable object to a given constant."""
|
|
20
|
+
|
|
21
|
+
def __init__(self, func, arg1):
|
|
22
|
+
"""Freeze the second argument of function func to arg1."""
|
|
23
|
+
self.func = func
|
|
24
|
+
self.arg1 = arg1
|
|
25
|
+
return
|
|
26
|
+
|
|
27
|
+
def __call__(self, *args, **kwargs):
|
|
28
|
+
boundargs = (args[0], self.arg1) + args[1:]
|
|
29
|
+
return self.func(*boundargs, **kwargs)
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
##############################################################################
|
|
3
|
+
#
|
|
4
|
+
# diffpy.srfit by DANSE Diffraction group
|
|
5
|
+
# Simon J. L. Billinge
|
|
6
|
+
# (c) 2010 The Trustees of Columbia University
|
|
7
|
+
# in the City of New York. All rights reserved.
|
|
8
|
+
#
|
|
9
|
+
# File coded by: Chris Farrow
|
|
10
|
+
#
|
|
11
|
+
# See AUTHORS.txt for a list of people who contributed.
|
|
12
|
+
# See LICENSE_DANSE.txt for license information.
|
|
13
|
+
#
|
|
14
|
+
##############################################################################
|
|
15
|
+
"""Input utilities."""
|
|
16
|
+
|
|
17
|
+
__all__ = ["inputToString"]
|
|
18
|
+
|
|
19
|
+
import os.path
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def inputToString(input):
|
|
23
|
+
"""Convert input from various modes to a string.
|
|
24
|
+
|
|
25
|
+
This is useful when you want a method to accept a string, open file object
|
|
26
|
+
or file name.
|
|
27
|
+
|
|
28
|
+
input -- An open file-like object, name of a file
|
|
29
|
+
or a string containing the input.
|
|
30
|
+
|
|
31
|
+
Returns the input in a string
|
|
32
|
+
Raises IOError if the input is supected to be a file name, but the file
|
|
33
|
+
cannot be found.
|
|
34
|
+
"""
|
|
35
|
+
# Get the input into a string
|
|
36
|
+
inptstr = ""
|
|
37
|
+
if hasattr(input, "read"):
|
|
38
|
+
inptstr = input.read()
|
|
39
|
+
# TODO remove handling of string input accept only file or filename
|
|
40
|
+
# FIXME check for typos in the file name
|
|
41
|
+
elif os.path.exists(input) or (len(input) < 80 and input.count("\n") == 0):
|
|
42
|
+
with open(input, "r") as infile:
|
|
43
|
+
inptstr = infile.read()
|
|
44
|
+
else:
|
|
45
|
+
inptstr = input
|
|
46
|
+
|
|
47
|
+
return inptstr
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
# End of file
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
##############################################################################
|
|
3
|
+
#
|
|
4
|
+
# diffpy.srfit by DANSE Diffraction group
|
|
5
|
+
# Simon J. L. Billinge
|
|
6
|
+
# (c) 2008 The Trustees of Columbia University
|
|
7
|
+
# in the City of New York. All rights reserved.
|
|
8
|
+
#
|
|
9
|
+
# File coded by: Chris Farrow
|
|
10
|
+
#
|
|
11
|
+
# See AUTHORS.txt for a list of people who contributed.
|
|
12
|
+
# See LICENSE_DANSE.txt for license information.
|
|
13
|
+
#
|
|
14
|
+
##############################################################################
|
|
15
|
+
"""Name utilities."""
|
|
16
|
+
|
|
17
|
+
__all__ = ["isIdentifier", "validateName"]
|
|
18
|
+
|
|
19
|
+
import re
|
|
20
|
+
|
|
21
|
+
reident = re.compile(r"^[a-zA-Z_]\w*$")
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def isIdentifier(s):
|
|
25
|
+
"""Check to see if a python string is a valid identifier.
|
|
26
|
+
|
|
27
|
+
From http://code.activestate.com/recipes/413487/
|
|
28
|
+
"""
|
|
29
|
+
if reident.match(s) is None:
|
|
30
|
+
return False
|
|
31
|
+
return True
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def validateName(name):
|
|
35
|
+
"""Validate that a name is a valid identifier.
|
|
36
|
+
|
|
37
|
+
Raises ValueError if the name is invalid.
|
|
38
|
+
"""
|
|
39
|
+
# Check that the name is valid
|
|
40
|
+
if not isIdentifier(name):
|
|
41
|
+
raise ValueError(f"Name {name} is not a valid identifier")
|
|
42
|
+
return
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
# End of file
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
#
|
|
4
|
+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
5
|
+
#
|
|
6
|
+
# michael a.g. aïvázis
|
|
7
|
+
# orthologue
|
|
8
|
+
# (c) 1998-2009 all rights reserved
|
|
9
|
+
#
|
|
10
|
+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
11
|
+
# Derived from pyre-1.0/packages/pyre/patterns/Observable.py
|
|
12
|
+
# See pyre-1.0 for full copyright and license information
|
|
13
|
+
|
|
14
|
+
__all__ = ["Observable"]
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
from diffpy.srfit.util.weakrefcallable import weak_ref
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class Observable(object):
|
|
21
|
+
"""Provide notification support for classes that maintain dynamic
|
|
22
|
+
associations with multiple clients.
|
|
23
|
+
|
|
24
|
+
Observers, i.e. clients of the observable, register event handlers
|
|
25
|
+
that will be invoked to notify them whenever something interesting
|
|
26
|
+
happens to the observable. The nature of what is being observed is
|
|
27
|
+
defined by Observable descendants and their managers. For example,
|
|
28
|
+
instances of pyre.calc.Node are observable by other nodes whose
|
|
29
|
+
value depends on them so that the dependents can be notified about
|
|
30
|
+
value changes and forced to recompute their own value.
|
|
31
|
+
|
|
32
|
+
The event handlers are callables that take the observable instance
|
|
33
|
+
as their single argument.
|
|
34
|
+
|
|
35
|
+
interface:
|
|
36
|
+
addObserver: registers its callable argument with the list of
|
|
37
|
+
handlers to invoke removeObserver: remove an event handler from
|
|
38
|
+
the list of handlers to invoke notify: invoke the registered
|
|
39
|
+
handlers in the order in which they were registered
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
def notify(self, other=()):
|
|
43
|
+
"""Notify all observers."""
|
|
44
|
+
# build a list before notification, just in case the observer's
|
|
45
|
+
# callback behavior involves removing itself from our callback set
|
|
46
|
+
semaphores = (self,) + other
|
|
47
|
+
for callable in tuple(self._observers):
|
|
48
|
+
callable(semaphores)
|
|
49
|
+
return
|
|
50
|
+
|
|
51
|
+
# callback management
|
|
52
|
+
|
|
53
|
+
def addObserver(self, callable):
|
|
54
|
+
"""Add callable to the set of observers."""
|
|
55
|
+
f = weak_ref(callable, fallback=_fbRemoveObserver)
|
|
56
|
+
self._observers.add(f)
|
|
57
|
+
return
|
|
58
|
+
|
|
59
|
+
def removeObserver(self, callable):
|
|
60
|
+
"""Remove callable from the set of observers."""
|
|
61
|
+
f = weak_ref(callable)
|
|
62
|
+
self._observers.remove(f)
|
|
63
|
+
return
|
|
64
|
+
|
|
65
|
+
def hasObserver(self, callable):
|
|
66
|
+
"""True if `callable` is present in the set of observers."""
|
|
67
|
+
f = weak_ref(callable)
|
|
68
|
+
rv = f in self._observers
|
|
69
|
+
return rv
|
|
70
|
+
|
|
71
|
+
# meta methods
|
|
72
|
+
|
|
73
|
+
def __init__(self, **kwds):
|
|
74
|
+
super(Observable, self).__init__(**kwds)
|
|
75
|
+
self._observers = set()
|
|
76
|
+
return
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
# end of class Observable
|
|
80
|
+
|
|
81
|
+
# Local helpers --------------------------------------------------------------
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _fbRemoveObserver(fobs, semaphores):
|
|
85
|
+
# Remove WeakBoundMethod `fobs` from the observers of notifying object.
|
|
86
|
+
# This is called from Observable.notify when the WeakBoundMethod
|
|
87
|
+
# associated object dies.
|
|
88
|
+
observable = semaphores[0]
|
|
89
|
+
observable.removeObserver(fobs)
|
|
90
|
+
return
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
# end of file
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
##############################################################################
|
|
3
|
+
#
|
|
4
|
+
# diffpy.srfit by DANSE Diffraction group
|
|
5
|
+
# Simon J. L. Billinge
|
|
6
|
+
# (c) 2008 The Trustees of Columbia University
|
|
7
|
+
# in the City of New York. All rights reserved.
|
|
8
|
+
#
|
|
9
|
+
# File coded by: Chris Farrow
|
|
10
|
+
#
|
|
11
|
+
# See AUTHORS.txt for a list of people who contributed.
|
|
12
|
+
# See LICENSE_DANSE.txt for license information.
|
|
13
|
+
#
|
|
14
|
+
##############################################################################
|
|
15
|
+
"""TagManager class.
|
|
16
|
+
|
|
17
|
+
The TagManager class takes hashable objects and assigns tags to them.
|
|
18
|
+
Objects can then be easily referenced via their assigned tags.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
__all__ = ["TagManager"]
|
|
22
|
+
|
|
23
|
+
import functools
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class TagManager(object):
|
|
27
|
+
"""TagManager class.
|
|
28
|
+
|
|
29
|
+
Manage tags on hashable objects. Tags are strings that carry metadata.
|
|
30
|
+
|
|
31
|
+
silent -- Flag indicating whether to silently pass by when a tag
|
|
32
|
+
cannot be found (bool, True). If this is False, then a
|
|
33
|
+
KeyError will be thrown when a tag cannot be found.
|
|
34
|
+
_tagdict -- A dictionary of tags to sets of tagged objects.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
def __init__(self):
|
|
38
|
+
"""Initialization."""
|
|
39
|
+
self._tagdict = {}
|
|
40
|
+
self.silent = True
|
|
41
|
+
return
|
|
42
|
+
|
|
43
|
+
def alltags(self):
|
|
44
|
+
"""Get all tags managed by the TagManager."""
|
|
45
|
+
return self._tagdict.keys()
|
|
46
|
+
|
|
47
|
+
def tag(self, obj, *tags):
|
|
48
|
+
"""Tag an object.
|
|
49
|
+
|
|
50
|
+
Tags are stored as strings.
|
|
51
|
+
|
|
52
|
+
obj -- Any hashable object to be untagged.
|
|
53
|
+
*tags -- Tags to apply to obj.
|
|
54
|
+
|
|
55
|
+
Raises TypeError if obj is not hashable.
|
|
56
|
+
"""
|
|
57
|
+
for tag in tags:
|
|
58
|
+
oset = self._tagdict.setdefault(str(tag), set())
|
|
59
|
+
oset.add(obj)
|
|
60
|
+
return
|
|
61
|
+
|
|
62
|
+
def untag(self, obj, *tags):
|
|
63
|
+
"""Remove tags from an object.
|
|
64
|
+
|
|
65
|
+
obj -- Any hashable object to be untagged.
|
|
66
|
+
*tags -- Tags to remove from obj. If this is empty, then all
|
|
67
|
+
tags will be removed from obj.
|
|
68
|
+
|
|
69
|
+
Raises KeyError if a passed tag does not apply to obj and self.silent
|
|
70
|
+
is False
|
|
71
|
+
"""
|
|
72
|
+
if not tags:
|
|
73
|
+
tags = self.tags(obj)
|
|
74
|
+
|
|
75
|
+
for tag in tags:
|
|
76
|
+
oset = self.__getObjectSet(tag)
|
|
77
|
+
if obj not in oset and not self.silent:
|
|
78
|
+
raise KeyError("Tag '%s' does not apply" % tag)
|
|
79
|
+
oset.discard(obj)
|
|
80
|
+
|
|
81
|
+
return
|
|
82
|
+
|
|
83
|
+
def tags(self, obj):
|
|
84
|
+
"""Get all tags on an object.
|
|
85
|
+
|
|
86
|
+
Returns list
|
|
87
|
+
"""
|
|
88
|
+
tags = [k for (k, v) in self._tagdict.items() if obj in v]
|
|
89
|
+
return tags
|
|
90
|
+
|
|
91
|
+
def hasTags(self, obj, *tags):
|
|
92
|
+
"""Determine if an object has all passed tags.
|
|
93
|
+
|
|
94
|
+
Returns bool
|
|
95
|
+
"""
|
|
96
|
+
setgen = (self.__getObjectSet(t) for t in tags)
|
|
97
|
+
result = all(obj in s for s in setgen)
|
|
98
|
+
return result
|
|
99
|
+
|
|
100
|
+
def union(self, *tags):
|
|
101
|
+
"""Get all objects that have any of the passed tags.
|
|
102
|
+
|
|
103
|
+
Returns set
|
|
104
|
+
"""
|
|
105
|
+
if not tags:
|
|
106
|
+
return set()
|
|
107
|
+
setgen = (self.__getObjectSet(t) for t in tags)
|
|
108
|
+
objs = functools.reduce(set.union, setgen)
|
|
109
|
+
return objs
|
|
110
|
+
|
|
111
|
+
def intersection(self, *tags):
|
|
112
|
+
"""Get all objects that have all of the passed tags.
|
|
113
|
+
|
|
114
|
+
Returns set
|
|
115
|
+
"""
|
|
116
|
+
if not tags:
|
|
117
|
+
return set()
|
|
118
|
+
setgen = (self.__getObjectSet(t) for t in tags)
|
|
119
|
+
objs = functools.reduce(set.intersection, setgen)
|
|
120
|
+
return objs
|
|
121
|
+
|
|
122
|
+
def verifyTags(self, *tags):
|
|
123
|
+
"""Check that tags are all extant.
|
|
124
|
+
|
|
125
|
+
Raises KeyError if a passed tag does not exist. This ignores
|
|
126
|
+
self.silent.
|
|
127
|
+
"""
|
|
128
|
+
keys = self._tagdict.keys()
|
|
129
|
+
for tag in tags:
|
|
130
|
+
if tag not in keys:
|
|
131
|
+
raise KeyError("Tag '%s' does not exist" % tag)
|
|
132
|
+
return True
|
|
133
|
+
|
|
134
|
+
def __getObjectSet(self, tag):
|
|
135
|
+
"""Helper function for getting an object set with given tag.
|
|
136
|
+
|
|
137
|
+
Raises KeyError if a passed tag does not exist and self.silent
|
|
138
|
+
is False
|
|
139
|
+
"""
|
|
140
|
+
oset = self._tagdict.get(str(tag))
|
|
141
|
+
if oset is None:
|
|
142
|
+
if not self.silent:
|
|
143
|
+
raise KeyError("Tag '%s' does not exist" % tag)
|
|
144
|
+
oset = set()
|
|
145
|
+
return oset
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
# End class TagManager
|
|
149
|
+
|
|
150
|
+
# End of file
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
##############################################################################
|
|
3
|
+
#
|
|
4
|
+
# diffpy.srfit Complex Modeling Initiative
|
|
5
|
+
# (c) 2016 Brookhaven Science Associates,
|
|
6
|
+
# Brookhaven National Laboratory.
|
|
7
|
+
# All rights reserved.
|
|
8
|
+
#
|
|
9
|
+
# File coded by: Pavol Juhas
|
|
10
|
+
#
|
|
11
|
+
# See AUTHORS.txt for a list of people who contributed.
|
|
12
|
+
# See LICENSE.txt for license information.
|
|
13
|
+
#
|
|
14
|
+
##############################################################################
|
|
15
|
+
"""Picklable storage of callable objects using weak references."""
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
import types
|
|
19
|
+
import weakref
|
|
20
|
+
|
|
21
|
+
import six
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class WeakBoundMethod(object):
|
|
25
|
+
"""Callable wrapper to a bound method stored as a weak reference.
|
|
26
|
+
|
|
27
|
+
Support storage of bound methods without keeping the associated objects
|
|
28
|
+
alive forever. Provide facility for a fallback function to be used
|
|
29
|
+
when method-related object is deleted.
|
|
30
|
+
|
|
31
|
+
Attributes
|
|
32
|
+
----------
|
|
33
|
+
function : MethodType
|
|
34
|
+
the unbound function extracted from the wrapped bound method.
|
|
35
|
+
fallback : FunctionType, optional
|
|
36
|
+
plain function to be called when object holding the bound method
|
|
37
|
+
gets deallocated. The fallback function is called with this
|
|
38
|
+
object as the first argument followed by any positional and
|
|
39
|
+
keyword arguments passed for the bound method. The fallback
|
|
40
|
+
function can be used to deregister this wrapper.
|
|
41
|
+
_wref : weakref
|
|
42
|
+
weak reference to the object the wrapped method is bound to.
|
|
43
|
+
_class : type
|
|
44
|
+
the type of the object to which the method is bound.
|
|
45
|
+
This is only used for pickling.
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
__slots__ = ("function", "fallback", "_wref", "_class")
|
|
49
|
+
|
|
50
|
+
def __init__(self, f, fallback=None):
|
|
51
|
+
"""Create a weak reference wrapper to bound method.
|
|
52
|
+
|
|
53
|
+
Parameters
|
|
54
|
+
----------
|
|
55
|
+
f : bound MethodType
|
|
56
|
+
instance-bound method to be wrapped.
|
|
57
|
+
fallback : FunctionType, optional
|
|
58
|
+
plain function to be called instead of the bound method when
|
|
59
|
+
the method associated object gets deallocated.
|
|
60
|
+
"""
|
|
61
|
+
# This does not handle builtin methods, but that can be added
|
|
62
|
+
# if necessary.
|
|
63
|
+
self.function = f.__func__
|
|
64
|
+
if six.PY2:
|
|
65
|
+
self.function = f.__func__.__get__(None, f.im_class)
|
|
66
|
+
self.fallback = fallback
|
|
67
|
+
self._class = type(f.__self__)
|
|
68
|
+
self._wref = weakref.ref(f.__self__)
|
|
69
|
+
return
|
|
70
|
+
|
|
71
|
+
def __call__(self, *args, **kwargs):
|
|
72
|
+
"""Call the wrapped method if the weak-referenced object is alive.
|
|
73
|
+
|
|
74
|
+
If that object does not exist and the fallback function is defined,
|
|
75
|
+
call the fallback function instead.
|
|
76
|
+
|
|
77
|
+
Parameters
|
|
78
|
+
----------
|
|
79
|
+
*args, **kwargs
|
|
80
|
+
same arguments as for the wrapped bound method.
|
|
81
|
+
|
|
82
|
+
Raises
|
|
83
|
+
------
|
|
84
|
+
ReferenceError
|
|
85
|
+
when the method-bound object does not exist and the fallback
|
|
86
|
+
function is not defined.
|
|
87
|
+
"""
|
|
88
|
+
mobj = self._wref()
|
|
89
|
+
if mobj is not None:
|
|
90
|
+
return self.function(mobj, *args, **kwargs)
|
|
91
|
+
if self.fallback is not None:
|
|
92
|
+
return self.fallback(self, *args, **kwargs)
|
|
93
|
+
emsg = "Object bound to {} does not exist.".format(self.function)
|
|
94
|
+
raise ReferenceError(emsg)
|
|
95
|
+
|
|
96
|
+
# support use of this class in hashed collections
|
|
97
|
+
|
|
98
|
+
def __hash__(self):
|
|
99
|
+
return hash((self.function, self._wref))
|
|
100
|
+
|
|
101
|
+
def __eq__(self, other):
|
|
102
|
+
rv = self.function == other.function and (
|
|
103
|
+
self._wref == other._wref or None is self._wref() is other._wref()
|
|
104
|
+
)
|
|
105
|
+
return rv
|
|
106
|
+
|
|
107
|
+
def __ne__(self, other):
|
|
108
|
+
return not self.__eq__(other)
|
|
109
|
+
|
|
110
|
+
# support pickling of this type
|
|
111
|
+
|
|
112
|
+
def __getstate__(self):
|
|
113
|
+
"""Return state with a resolved weak reference."""
|
|
114
|
+
mobj = self._wref()
|
|
115
|
+
nm = self.function.__name__
|
|
116
|
+
amsg = "Unable to pickle this unbound function by name."
|
|
117
|
+
if six.PY2:
|
|
118
|
+
assert self.function == getattr(self._class, nm), amsg
|
|
119
|
+
if six.PY3:
|
|
120
|
+
assert self.function is getattr(self._class, nm), amsg
|
|
121
|
+
state = (self._class, nm, self.fallback, mobj)
|
|
122
|
+
return state
|
|
123
|
+
|
|
124
|
+
def __setstate__(self, state):
|
|
125
|
+
"""Restore the weak reference in this wrapper upon unpickling."""
|
|
126
|
+
(self._class, nm, self.fallback, mobj) = state
|
|
127
|
+
self.function = getattr(self._class, nm)
|
|
128
|
+
if mobj is None:
|
|
129
|
+
# use a fake weak reference that mimics deallocated object.
|
|
130
|
+
self._wref = self.__mimic_empty_ref
|
|
131
|
+
return
|
|
132
|
+
# Here the referred object exists.
|
|
133
|
+
self._wref = weakref.ref(mobj)
|
|
134
|
+
return
|
|
135
|
+
|
|
136
|
+
@staticmethod
|
|
137
|
+
def __mimic_empty_ref():
|
|
138
|
+
return None
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
# end of class WeakBoundMethod
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def weak_ref(f, fallback=None):
|
|
145
|
+
"""Create weak-reference wrapper to a bound method.
|
|
146
|
+
|
|
147
|
+
Parameters
|
|
148
|
+
----------
|
|
149
|
+
f : callable
|
|
150
|
+
object-bound method or a plain function.
|
|
151
|
+
fallback : FunctionType, optional
|
|
152
|
+
plain function to be called when object holding ``f`` gets
|
|
153
|
+
deallocated. The fallback function is called with the
|
|
154
|
+
wrapper object as the first argument followed by positional
|
|
155
|
+
and keyword arguments passed for the bound method. The
|
|
156
|
+
fallback function can be used to deregister the wrapper.
|
|
157
|
+
|
|
158
|
+
Returns
|
|
159
|
+
-------
|
|
160
|
+
WeakBoundMethod
|
|
161
|
+
when `f` is a bound method. If `f` is a plain function or
|
|
162
|
+
already of WeakBoundMethod type, return `f` and ignore the
|
|
163
|
+
`fallback` argument.
|
|
164
|
+
"""
|
|
165
|
+
# NOTE Weak referencing plain functions is probably not needed,
|
|
166
|
+
# because they are already bound to the defining modules.
|
|
167
|
+
rv = f
|
|
168
|
+
if isinstance(f, (types.MethodType, types.BuiltinMethodType)):
|
|
169
|
+
rv = WeakBoundMethod(f, fallback=fallback)
|
|
170
|
+
return rv
|