ccpn.util package



ccpn.util.Anchor module

Anchor file, used as a starting point for functions that return the absolute location of the repository.

Needed to allow ObjectDomain (uses Python 2.1) to find the repository location

ccpn.util.AttrDict module

Module Documentation here

class ccpn.util.AttrDict.AttrDict(*args, **kwargs)[source]

Bases: dict

ccpn.util.AttributeDict module

class ccpn.util.AttributeDict.AttributeDict(*args, **kwds)[source]

Bases: dict

AttributeDict; dict that has its keys also as attributes

ccpn.util.Colour module

Module Documentation here

class ccpn.util.Colour.Colour(value)[source]

Bases: str

A class to make colour manipulation easier and more transparent.

Assumes that r, g, b values are 8-bit so between 0 and 255 and have optional a.

>>> c = Colour('magenta')
>>> c = Colour('#FF00FF')
>>> c = Colour((255, 0, 255))

Returns 4-tuple of (r, g, b, a) where each one is in range 0 to 255


Returns 4-tuple of (r, g, b, a) where each one is in range 0.0 to 1.0


Add a new Hex colour to the colourlist New colour has the name ‘Colour <n>’ where n is the next free number

ccpn.util.Colour.autoCorrectHexColour(colour, referenceHexColour='#ffffff', addNewColour=True)[source]

Autocorrect colours if too close to the reference value


remove spaces from the colourname


insert spaces into the colourname

ccpn.util.Colour.fillColourPulldown(pulldown, allowAuto=False, allowNone=False, includeGradients=True)[source]
ccpn.util.Colour.findNearestHex(hexCol, colourHexList)[source]
ccpn.util.Colour.getAutoColourRgbRatio(inColour=None, sourceObject=None, colourAttribute=None, defaultColour=None)[source]
ccpn.util.Colour.getSpectrumColour(colourName, defaultReturn=None)[source]

return the hex colour of the named colour

ccpn.util.Colour.gray(r, g, b, a=1.0)[source]
ccpn.util.Colour.hexToRgba(hx, transparency=1.0)[source]
ccpn.util.Colour.hexToRgbaArray(array, transparency=1.0)[source]
ccpn.util.Colour.interpolateColourHex(hexColor1, hexColor2, value, alpha=1.0)[source]
ccpn.util.Colour.interpolateColourRgba(colour1, colour2, value, alpha=1.0)[source]
ccpn.util.Colour.invertRGBHue(r, g, b)[source]

Invert the rgb colour using the ycbcr method by finding the opposite hue rgb input r, g, b in range 0-255

ccpn.util.Colour.invertRGBLuma(r, g, b)[source]

Invert the rgb colour using the ycbcr method by inverting the luma rgb input r, g, b in range 0-255


Return true if the colourString is in the list

ccpn.util.Colour.rgbRatioToHex(r, g, b)[source]
ccpn.util.Colour.rgbToHex(r, g, b)[source]
ccpn.util.Colour.rgbaRatioToHex(r, g, b, a=1.0)[source]
ccpn.util.Colour.rgbaToHex(r, g, b, a=255)[source]
ccpn.util.Colour.selectPullDownColour(pulldown, colourString, allowAuto=False)[source]

ccpn.util.Common module

Miscellaneous common utilities

class ccpn.util.Common.LocalFormatter(overrideFloatFormat='.6g')[source]

Bases: string.Formatter

Overrides the string formatter to change the float formatting

convert_field(value, conversion)[source]

Change a camelCase string to string with spaces in front of capitals. Groups of capitals are taken as acronyms and only the last letter of a group is separated. The first letter is capitalised except in the special case of a camel case string beginning <lowerCase,uppercase>, in which case the first lowercase letter is preserved. e.g. camelCase -> Camel Case TLAAcronym -> TLA Acronym pHValue -> pH Value


items – a list of items to be copied to Clipboard. Each value is single quoted if a str (Pid if an AbstractWrapperObject instance), or preserved the format for other cases. All values are comma separated.

A very simple implementation of str to clipboard. An ideal implementation should deal with AbstractWrapperObjects using some sort of parser to be able to perform actions such as copy-paste peakLists via NEF etc.

ccpn.util.Common.dictionaryProduct(dict1, dict2)[source]

multiply input {a:x}, {b:y} to result {(a,b):x*y} dictionary


Yield items from any nested iterable; see Reference. Here is a general approach that applies to numbers, strings, nested lists and mixed containers. From: ref: This solution is modified from a recipe in Beazley, D. and B. Jones. Recipe 4.14, Python Cookbook 3rd

Ed., O’Reilly Media Inc. Sebastopol, CA: 2013.


Take a list of lists and concatenate into a single list. Remove any Nones from the list :param lists: a list of lists :return: list. a single list


Return a list of defined atom names based on the isotopeCode


Get iso-formtted timestamp

ccpn.util.Common.getUuid(programName, timeStamp=None)[source]

Get UUid following the NEF convention


Sort key for sorting a list by the equivalent greek letter

ccpn.util.Common.incrementName(name, split: str = '_')[source]

Add ‘_1’ to name or change suffix ‘_n’ to ‘_(n+1)


Return the index of the item in theList with the maximum value :param theList: an iterable :return index value or -1 for an empty list


Return the index of the item in theList with the minimum value :param theList: an iterable :return index value or -1 for an empty list

ccpn.util.Common.isClose(a, b, relTolerance=1e-05, absTolerance=1e-08)[source]

Are a and b identical within reasonable floating point tolerance? Uses sum of relative (relTolerance) and absolute (absTolerance) difference

Inspired by numpy.isclose()

ccpn.util.Common.isIterable(obj) bool[source]

Returns True if obj is iterable


dynamic module importer.


Take a nested collection of (tuples, lists or sets) and concatenate into a single list. Also changes a single item into a list. Removes any Nones from the list :param inList: list of tuples, lists, sets or single items :return: a single list

ccpn.util.Common.naturalSortList(ll, reverse=True)[source]

ll – a list of strings


a sorted list by natural sort


split sequence code into (seqCode,seqInsertCode, offset) tuple

ccpn.util.Common.percentage(percent, whole)[source]
ccpn.util.Common.recursiveImport(dirname, modname=None, ignoreModules=None, force=False)[source]

recursively import all .py files (not starting with ‘__’ and not containing internal ‘.’ in their name) from directory dirname and all its subdirectories, provided they contain ‘’ Serves to check that files compile without error

modname is the module name (dot-separated) corresponding to the directory dirName. If modname is None, dirname must be on the pythonPath

Note that there are potential problems if the files we want are not the ones encountered first on the pythonPath

ccpn.util.Common.reorder(values, axisCodes, refAxisCodes)[source]

reorder values in axisCode order to refAxisCode order, by matching axisCodes

NB, the result will be the length of refAxisCodes, with additional Nones inserted if this is longer than the values.

NB if there are multiple matches possible, one is chosen by heuristics

ccpn.util.Common.sortObjectByName(objs, reverse=True)[source]
  • objs – list of objects that contains the property name. E.g.

  • reverse – bool. False: descending order. True: ascending order.



Sorts the objects by digit if present in the name, otherwise alphabetically.

ccpn.util.Common.splitDataFrameWithinRange(dataframe, column1, column2, minX, maxX, minY, maxY)[source]
  • dataframe – dataframe with index a pid type, columns str, values floats or ints

  • column1 – label1 , eg PC1

  • column2 – label1 , eg PC2

  • minX – min value for Y

  • maxX – Max value for X

  • minY – min value for Y

  • maxY – max value for Y


inners a dataframe like the unput but containing only the values within the ranges and outers (rest) not included in inners


convert a string with a leading integer optionally followed by characters into an (integer,string) tuple


Change string to camelCase format Removes whitespaces, and changes first character to lower case

ccpn.util.Common.stringifier(*fields, **options)[source]

Get stringifier function, that will format an object x according to

<str(x): field1=x.field1, field2=x.field2, …>

All floating point values encountered will be formatted according to floatFormat


Get list of unique elements in sequence, in order of first appearance

ccpn.util.Common.zipCycle(*iterables, emptyDefault=None)[source]

Make an iterator returning elements from the iterable and saving a copy of each. When the iterable is exhausted, return elements from the saved copy.

for i in zipCycle(range(2), range(5), [‘a’, ‘b’, ‘c’], []):


Outputs: (0, 0, ‘a’, None) (1, 1, ‘b’, None) (0, 2, ‘c’, None) (1, 3, ‘a’, None) (0, 4, ‘b’, None)

ccpn.util.Constants module

Constants used in the program core, including enumerations of allowed values

ccpn.util.Data module

Module Documentation here

ccpn.util.ExcelReader module

class ccpn.util.ExcelReader.ExcelReader(project, excelPath)[source]

Bases: object


Load the actual data in the the project

ccpn.util.ExcelReader.makeTemplate(path, fileName='lookupTemplate.xlsx')[source]
  • path – path where to save the template

  • fileName – name of template


the file path where is saved

ccpn.util.FrozenDict module

class ccpn.util.FrozenDict.FrozenDict(*args, **kwargs)[source]

Bases: dict

clear() None.  Remove all items from D.
pop(k[, d]) v, remove specified key and return the corresponding value.

If key is not found, d is returned if given, otherwise KeyError is raised

popitem(*args, **kws)

Remove and return a (key, value) pair as a 2-tuple.

Pairs are returned in LIFO (last-in, first-out) order. Raises KeyError if the dict is empty.

setdefault(*args, **kws)

Insert key with a value of default if key is not in the dictionary.

Return the value for key if key is in the dictionary, else default.

update([E, ]**F) None.  Update D from dict/iterable E and F.

If E is present and has a .keys() method, then does: for k in E: D[k] = E[k] If E is present and lacks a .keys() method, then does: for k, v in E: D[k] = v In either case, this is followed by: for k in F: D[k] = F[k]

ccpn.util.GitTools module

ccpn.util.GitTools.getAllRepositoriesGitCommit() dict[source]

Return a dictionary of the current commit hashes for all the CCPN repositories

ccpn.util.GitTools.getCurrentGitAuthor(workingDir: Optional[str] = None) str[source]

Get the current git commit hash. This function returns the git commit hash for the repository where it’s called.

ccpn.util.GitTools.getCurrentGitCommit(workingDir: Optional[str] = None) str[source]

Get the current git commit hash. This function returns the git commit hash for the repository where it’s called.

ccpn.util.GitTools.runGitCommand(command: str, workingDir: Optional[str] = None) str[source]

ccpn.util.Graph module

General graph handling code

ccpn.util.Graph.minimumStepPath(graph: dict, startNode, endNode=None) Tuple[dict, dict][source]

Minimum-step-path by breadth-first traversal, inspired by Dijkstras algorithm Each edge has the same weight; among paths of the same length the function selects the first encountered. Breadth-first search guarantees that the paths with fewest steps are encountered first.

Input: graph is given in form {node:{node:edgeInfo}} nodes can be any object that can be used as a dictionary key

Output: (costDict, predecessorDict) tuple, where costDict is {node:Tuple[edgeInfo, …]}, with the edgeInfo along the path from start to node predecessorDict is {node:predecessor} the predecessor of node in the shortest path from start

ccpn.util.LabelledEnum module

Module Documentation here

class ccpn.util.LabelledEnum.LabelledEnum(value)[source]

Bases: enum.Enum

Class to handle enumerated types with associated labels


FLOAT = 0, ‘Float’ INTEGER = 1, ‘Integer’ STRING = 2, ‘String’

property description

- None, immutable -

classmethod descriptions()[source]
property label

- None, immutable -

classmethod values()[source]

A few small tests for the labelled Enum

ccpn.util.ListFromString module

ccpn.util.ListFromString.listFromString(string: str) list[source]

Convenience function to turn a string into a list of mixed str and int.

Splits on ‘,’, strips the resulting strings, and converts ‘i-j’ into range(int(i),int(j)+1)

ccpn.util.LocalShutil module

Local copy of shutil - modified to ignore errors in copying permission bits with copystat WIndows-type file systems osmetimes cannot copy permissions, and teh error is not reliably caught on e.g. VMs

ccpn.util.LocalShutil.copytree(src, dst, symlinks=False, ignore=None, copy_function=<function copy>, ignore_dangling_symlinks=False)[source]

Recursively copy a directory tree.

The destination directory must not already exist. If exception(s) occur, an Error is raised with a list of reasons.

If the optional symlinks flag is true, symbolic links in the source tree result in symbolic links in the destination tree; if it is false, the contents of the files pointed to by symbolic links are copied. If the file pointed by the symlink doesn’t exist, an exception will be added in the list of errors raised in an Error exception at the end of the copy process.

You can set the optional ignore_dangling_symlinks flag to true if you want to silence this exception. Notice that this has no effect on platforms that don’t support os.symlink.

The optional ignore argument is a callable. If given, it is called with the src parameter, which is the directory being visited by copytree(), and names which is the list of src contents, as returned by os.listdir():

callable(src, names) -> ignored_names

Since copytree() is called recursively, the callable will be called once for each directory that is copied. It returns a list of names relative to the src directory that should not be copied.

The optional copy_function argument is a callable that will be used to copy each file. It will be called with the source path and the destination path as arguments. By default, copy2() is used, but any function that supports the same signature (like copy()) can be used.

ccpn.util.Logging module

CCPN logger handling

ccpn.util.Logging.createLogger(loggerName, memopsRoot, stream=None, level=None, mode='a', removeOldLogsDays=7)[source]

Return a (unique) logger for this memopsRoot and with given programName, if any. Puts log output into a log file but also optionally can have output go to another, specified, stream (e.g. a console)

ccpn.util.Logging.setLevel(logger, level=20)[source]

Set the logger level (including for the handlers)

ccpn.util.OrderedSet module

Based on Ordered Set By Raymond Hettinger,

class ccpn.util.OrderedSet.FrozenOrderedSet(iterable=None)[source]


add(*args, **kws)

Raise error when performing illegal operation on immutable object

clear(*args, **kws)

Raise error when performing illegal operation on immutable object

discard(*args, **kws)

Raise error when performing illegal operation on immutable object

pop(*args, **kws)

Raise error when performing illegal operation on immutable object

remove(*args, **kws)

Raise error when performing illegal operation on immutable object

class ccpn.util.OrderedSet.OrderedSet(iterable=None)[source]



Add an element.


Remove an element. Do not raise an exception if absent.


Return the popped value. Raise KeyError if empty.

ccpn.util.Parabole module

Class representing a simple parabolic function:

f(x) = y = ax**2 + bx + c

Some (simple) maths:

coefficients a, b, c from three points:

f(x0) = y0 = a*x0**2 + b*x0 + c f(x1) = y1 = a*x1**2 + b*x1 + c f(xm1) = ym1 = a*xm1**2 + b*xm1 + c

y0 - y1 = a (x0-x1)(x0+x1) + b(x0-x1) y0 - ym1 = a (x0-xm1)(x0+xm1) + b(x0-xm1)

but if spaced 1 unit apart:

xm1 = x0-1 x1 = x0+1

y0 - y1 = a*(2x0+1) - b y0 - ym1 = a*(2x0-1) + b


a = -y0 + 0.5*y1 + 0.5*ym1 b = -y0 + y1 - a*(2x0+1) c = a*x0**2 + (y0-y1+a)*x0 + y0

max at df(x)/dx = 2a*x + b = 0

xmax = -b/2a

= x0 + (y0-y1) / 2a + 0.5 = x0 + (y0-y1) / (-2*y0 + y1 + ym1) + 0.5

NB numpy can do all of this, but this class is just a simple wrapper using high-school algebra for some simple methods. Its usage is mainly to easily find the parabolic interpolation of a peak maximum

class ccpn.util.Parabole.Parabole(a, b, c)[source]

Bases: object

A class to implement a simple implementation of a parabolic function: f(x) = y = ax**2 + bx + c


Return the value of the derivative of parabole at ‘x’

static fromPoints(points)[source]

return a new instance derived from 3 points spaced one unit apart



list/tuple with exactly three (x,y) tuples defining three succesive points spaced one unit apart; i.e. if x0 defines the centre point:

points = [ (x0-1.0, f(x0-1.0)), (x0, f(x0)), (x0+1.0, f(x0+1.0)) ]

:return new Parabole instance


Return a (xmax, f(xmax)) tuple

max at:

d(f(x)/dx = 2a*x + b = 0


xmax = -b/2a


Return the value of the parabole at ‘x’

ccpn.util.Path module

Utilities for path handling

Includes extensions of sys.path functions and CCPN-specific functionality

class ccpn.util.Path.Path(*args, **kwargs)[source]

Bases: pathlib.Path

Subclassed for compatibility, convenience and enhancements


Return a Path instance with path.timeStamp-suffix profile


Return self as a string


Return Path instance with an assured suffix; adds suffix if not present. .prefix to suffix is ignored if present. Does not change suffix if there is one (like with_suffix does).

property basename

- None, immutable - the name of self without any suffixes


Copy file represented by self to destination.


Return and (if needed) create all dirNames relative to self :return: Path instance of self / dirName[0] / dirName[1] …

property filepath

- None, immutable - Return the folder without the filename


Return a list rather than a generator


Return a Path instance with path.version.suffix profile

listDirFiles(extension: Optional[str] = None)[source]

Obsolete; extension is without a “.” use listdir instead

listdir(suffix: Optional[str] = None, excludeDotFiles=False) list[source]

If self is a directory path, return a list of its files as Path instance. If the suffix is given (e.g.: .pdf, .jpeg…), returns only files of that pattern. Non recursive.


Return normalised path

open(*args, **kwds)[source]

Subclassing to catch any long file name errors that allegedly can occur on Windows


Recursively remove content of self and subdirectories


Remove file represented by self.


Return a tuple (.parent, .name) strings


Return a tuple of (.parent, .stem, .suffix) strings


Return True if self starts with prefix


Return a Path instance which is unique by incrementing version index

property version

- None, immutable - Parse self to yield a version integer, presumably generated with the incrementVersion method Return 0 if not found


Return self with suffix; inverse of withoutSuffix() partially copies with_suffix, but does not allow for empty argument


Return self without suffix


Return a ~-expanded, left/right spaces-stripped, normalised Path instance

ccpn.util.Path.checkFilePath(filePath, allowDir=True)[source]

Find lowest directory that contains all files in list NB does not normalise file names.

Input: a list of file names Output: lowest directory that contains all files. Does not end with a file


Similar to splitPath but with head being the top directory and tail being the rest.


Removes path whether file or directory, taking into account whether symbolic link.

ccpn.util.Path.fetchDir(path, dirName)[source]
  • path – string of parent path where to add a new subdir

  • dirName – str of the new sub dir


if not already existing, creates a new folder with the given name, return the full path as str


Get absolute path to module (directory or file)


Returns the ‘top’ python directory, the one on the python path.


Returns the ‘top’ directory of the containing repository (ccpnv3).


The same as os.path.join but normalises the result.


Replace invalid chars in path to assure Python 2.1 (used in ObjectDomain) compatibility


Replace invalid chars in path to assure Python 2.1 (used in ObjectDomain) compatibility

ccpn.util.Path.normalisePath(path, makeAbsolute=None)[source]

Normalises the path, e.g. removes redundant .. and slashes and makes sure path uses ‘/’ rather than ‘' as can happen on Windows.


The same as os.path.split but with normalisation taken into account.

ccpn.util.Path.suggestFileLocations(fileNames, startDir=None)[source]

From a list of files, return a common superdirectory and a list of relative file names. If any of the files do not exist, search for an alternative superdirectory that does contain the set of relative file names. Searches in either a superdirectory of the starting/current directory, or in a direct subdirectory.

Input: list of file names

Output: Superdirectory, list of relative file names. If no suitable location is found, superdirectory is returned as None


On Unix does nothing, on Windows replaces ‘/’ with ‘'/

ccpn.util.Phasing module

Module Documentation here

ccpn.util.Phasing.autoPhaseReal(data, fn, p0=0.0, p1=0.0)[source]

Automatic linear phase correction from NmrGlue Parameters ———- data : ndarray

Array of NMR intensity data.

fnstr or function

Algorithm to use for phase scoring. Built in functions can be specified by one of the following strings: “acme”, “peak_minima”


Initial zero order phase in degrees.


Initial first order phase in degrees.


Phased NMR data.

ccpn.util.Phasing.phaseComplexData(data: Sequence[complex], ph0: float = 0.0, ph1: float = 0.0, pivot: float = 1.0) Sequence[complex][source]
ccpn.util.Phasing.phaseRealData(data: Sequence[float], ph0: float = 0.0, ph1: float = 0.0, pivot: float = 1.0) Sequence[float][source]

ccpn.util.PrintFile module

Module Documentation here

class ccpn.util.PrintFile.PrintFile(path, xCount=1, yCount=1, width=800, height=800)[source]

Bases: abc.ABC

abstract startRegion(xOutputRegion, yOutputRegion, xNumber=0, yNumber=0)[source]
abstract writeLine(x1, y1, x2, y2, colour='#000000')[source]
abstract writePolyline(polyline, colour='#000000')[source]
abstract writeText(text, x, y, colour='#000000', fontsize=10, fontfamily='Verdana')[source]

ccpn.util.PrintFormatter module

Module Documentation here

class ccpn.util.PrintFormatter.PrintFormatter[source]

Bases: object

Class to produce formatted strings from python objects.

Includes standard python objects: list, tuple, dict, set, bytes, str, int, float, complex, bool, type(None) and additional objects: OrderedDict, OrderedSet, frozenset, FrozenOrderedSet, FrozenDict

Objects not added to formatter will return a pickled object if ALLOWPICKLE is True, otherwise None

  • The original basis for this came from stackOverflow somewhere, but I can’t seem to find it now

CRLF = '\n'

Call method to produce object from pickled string Returns None if allowPickle is False

TAB = '    '
formatBase(value, indent, formatString='')[source]

Output format for list

formatDict(value, indent, *, formatString='{{{0}}}')

Output format for dict/FrozenDict

formatDictBase(value, indent, formatString='')[source]

Output format for dict/FrozenDict

formatFrozenDict(value, indent, *, formatString='FrozenDict({{{0}}})')

Output format for dict/FrozenDict

formatKlassBase(value, indent, klassName=None, formatString='')[source]

Output format for set of type klass currently ccpn.util.OrderedSet.OrderedSet

frozenset ccpn.util.OrderedSet.FrozenOrderedSet

formatList(value, indent, *, formatString='[{0}]')

Output format for list

formatListType(value, indent, klassName=None, *, formatString='{0}([{1}])')

Output format for set of type klass currently ccpn.util.OrderedSet.OrderedSet

frozenset ccpn.util.OrderedSet.FrozenOrderedSet

formatObject(value, indent)[source]

Fallback method for objects not registered with formatter Returns ‘None’ if allowPickle is False

formatOrderedDict(value, indent)[source]

Output format for OrderedDict (collections.OrderedDict)

formatSet(value, indent, *, formatString='{{{0}}}')

Output format for list

formatSetType(value, indent, klassName=None, *, formatString='{0}({{{1}}})')

Output format for set of type klass currently ccpn.util.OrderedSet.OrderedSet

frozenset ccpn.util.OrderedSet.FrozenOrderedSet

formatTuple(value, indent, *, formatString='({0})')

Output format for list


Safely evaluate an expression node or a string containing a Python expression. The string or node provided may only consist of the following Python literal structures: strings, bytes, numbers, tuples, lists, dicts, sets, booleans, and None.

registerFormat(obj, callback)[source]

Register an object class to formatter


Register a literalEval object class to formatter

ccpn.util.Register module

Module Documentation here

ccpn.util.Register.checkServer(registrationDict, version='3')[source]

Check the registration status on the server

ccpn.util.Register.updateServer(registrationDict, version='3')[source]

ccpn.util.Report module

Module Documentation here

class ccpn.util.Report.Report(parent, project, filename, pagesize=(595.2755905511812, 841.8897637795277), leftMargin=56.69291338582677, rightMargin=56.69291338582677, topMargin=56.69291338582677, bottomMargin=56.69291338582677)[source]

Bases: object

Class container for generating pdf reports


Add a new item to the current story :param item; e.g., paragraph or drawing:


Build the document from the story


Write the document to the file

class ccpn.util.Report.SimpleDocTemplateNoPadding(filename, **kw)[source]

Bases: reportlab.platypus.doctemplate.SimpleDocTemplate

build(flowables, onFirstPage=<function _doNothing>, onLaterPages=<function _doNothing>, canvasmaker=reportlab.pdfgen.canvas.Canvas)[source]

build the document using the flowables. Annotate the first page using the onFirstPage function and later pages using the onLaterPages function. The onXXX pages should follow the signature

def myOnFirstPage(canvas, document):

# do annotations and modify the document …

The functions can do things like draw logos, page numbers, footers, etcetera. They can use external variables to vary the look (for example providing page numbering or section names).

ccpn.util.SafeFilename module

Functions to append a number to the end of a filename if it already exists

ccpn.util.SafeFilename.getSafeFilename(path, mode='w')[source]

Get the first safe filename from the given path

  • path – filepath and filename.

  • mode – open flags


Open file handle and new fileName

ccpn.util.SafeFilename.safeOpen(path, mode)[source]

Open path, but if it already exists, add ‘(n)’ before the extension, where n is the first number found such that the file does not already exist. Returns an open file handle.

Usage: with safeOpen(path, [options]) as (fd, safeFileName):

fd is the file descriptor, to be used as with open, e.g., safeFileName is the new safe filename.

  • path – filepath and filename.

  • mode – open flags


Open file handle and new fileName

ccpn.util.Sorting module


Sort key for strings.

If the entire string evaluates to a float, the result is (‘’, ‘(floatVal, stringVal), ‘’)

Otherwise returns _numericSplitString(key)

Example of sorting order: [‘’, ‘NaN’, ‘-1’, ‘-1A’, ‘0.0’, ‘1’, ‘2’, ‘15’, ‘3.2e12’, ‘Inf’, ‘Ahh’, ‘b’, ‘b2’, ‘b12’, ‘bb’, ‘ciao’]


Universal sort key, using stringSortKey for strings

ccpn.util.Sorting.universalSortKey(key, _stringOrderingHook=None, _orderedKeyHook=<function _orderedKey>, _unorderedKeyHook=<function _unorderedKey>)[source]

Sort mixed types by type, then value or id. Should work for all object types.

This function serves to sort mixed and unpredictable types, e.g. for sorting rows in a mixed-type (or any-type) table, for processing unordered input in semi-reproducible order, or for preliminary hacking about with mixed-type data. Dicts, lists, and tuples are sorted by content, recursively. Circular references are treated by waiting for the RunTimeError after infinite recursion, and then treating the objects as unorderable.

Sorting order of types is giving in the sortOrder list. Booleans are treated as a separate class. Otherwise all real numbers are compared by value, with NaN treated as small than -Infinity. Objects with types that are not treated explicitly (‘ordered’ and ‘unordered’) are sorted first by class name and class id. ‘Ordered’ objects are sorted by their internal comparison method, ‘unordered’ objects by __name__, length, and id (where each is defined).

The ordering keys for strings, orderable types (that support a __lt__ method), and unorderable types (that do not) can be modified by the optional hook parameters.

The function identifies objects whose __lt__ function does not return a Boolean (e.g. numpy.ndarray) as unorderable. set and frozenset are special-cased as unorderable. The function may give unstable sorting results for objects whose __lt__ function returns a Boolean but does not define an ordering (as for sets), but it will sort these correctly by class.

ccpn.util.SphinxExtensions module

Custom extensions to Sphinx documentation generator


Return a listener that will modify doc strings from their Python annotations. If what is a sequence of strings, only docstrings of a type in what will be processed.

In the first version it adds type and modifiability annotation to properties


Return a listener that will modify doc strings from their Python annotations. If what is a sequence of strings, only docstrings of a type in what will be processed.

In the first version it adds type and modifiability annotation to properties

ccpn.util.StructureData module

Structure Data Matrix

class ccpn.util.StructureData.EnsembleData(*args, **kwargs)[source]

Bases: ccpn.core._implementation.DataFrameABC.DataFrameABC

Structure Ensemble data - as a Pandas DataFrame

The structure ensemble is based on a Pandas DataFrame. All of the functionality of DataFrames is available, but we have added a number of convenience methods for working with the data.

In general, there are three things you may want to do with an ensemble:

  1. Select a sub-set of atoms within the ensemble

  2. Access the data within the ensemble

  3. Write data to the ensemble

We will cover each of these in turn below.

  1. Selecting sub-sets of atoms within the ensemble:

Subsets of atoms can be extracted by creating a selector, which is nothing more than a Pandas Series object. These can be thought of as a table with the same number of rows as the ensemble you want to select from, and containing a single column of True/False values, where True represents a value to be included in the selection. We provide a .selector() function that will return a selector based on criteria you provide. Please note that although the criteria names are plural, single values are also allowed.

The following criteria are currently supported:

  • chainCodes allowed values: ‘A’; ‘A,C’; ‘A, C’; [‘A’, ‘C’] not allowed: ‘A-C’ (currently); [‘A, B’, ‘C’] (currently) Note that this is case sensitive, so ‘a’ will likely not select anything

  • residueNames allowed values: ‘MET’; ‘MET,ALA’; ‘MET, ALA’; [‘MET’, ’ALA’] not allowed: ‘MET-ALA’; [‘MET, ALA’, ‘GLU’] (currently) Note that this is case sensitive, so ‘met’ will likely not select anything

  • sequenceIds allowed values: 1; ‘1’; ‘1,2’; ‘1, 2’; ‘4-7’; ‘1, 2, 4-7’; [‘1’, ‘2’]; [1, 2] not allowed: [1, 2, ‘4-7’] (currently);

  • atomNames allowed values: ‘H’; ‘H,N’; ‘H, N’; [‘H’, ‘N’] not allowed: ‘H-N’; [‘H, N’, ‘CA’] (currently)

  • modelNumbers allowed values: 1; ‘1’; ‘1,2’; ‘1, 2’; ‘4-7’; ‘1, 2, 4-7’; [‘1’, ‘2’]; [1, 2] not allowed: [1, 2, ‘4-7’] (currently);

  • ids allowed values: ‘A.3.LEU.N’; ‘A.3.LEU.N, A.3.LEU.CA’;

    ‘A.3.LEU.N, A.3.LEU.CA’; [‘A.3.LEU.N’, ‘A.3.LEU.CA’]

    not allowed: ‘A.3.LEU.N-‘A.3.LEU.CA’; ‘A.3.LEU.N, CA’; [‘A.3.LEU.N, A.3.LEU.CA’, ‘A.3.LEU.CB’]

  • elements allowed values: ‘H’; ‘H,C’; ‘H, C’; [‘H’, ‘C’] not allowed: ‘H-N’; [‘H, N’, ‘C’]

In addition to these criteria, functions taking a record and returning True or False can be supplied via the func keyword argument.

For example:

ensemble.selector(func=lambda r: (r[‘bFactor’]< 70) and (r[‘bFactor’]>60)) which will select everything with a bFactor between 60 and 70 exclusive. The selector can be converted to a filter by setting the inverse keyword to True, so that any record that matches the criteria are excluded from the selection.

Finally, selectors can be combined using Boolean operations. The following statement:

s = ensemble.selector(atomNames=’N, CA’)

is equivalent to:

s1 = ensemble.selector(atomNames=’CA’) s2 = ensemble.selector(atomNames=’N’) s = s1 | s2 # Matches either s1 OR s2

While this statement:

s = ensemble.selector(atomNames=’N, CA’, modelNumbers = ‘1-3’)

is equivalent to:

s1 = ensemble.selector(atomNames=’N, CA’) s2 = ensemble.selector(modelNumbers = ‘1-3’) s = s1 & s2 # Matches both s1 AND s2

Because certain selections are quite common, we provide several pre-packaged selections, these include:

ensemble.backboneSelector ensemble.amideProtonSelector ensemble.amideNitrogenSelector ensemble.methylSelector

Note that selection on chains, residues and atoms, including the pre-packaged selectors

refer to the names that match the coordinates, which may not match the data in the rest of your project.

There is a separate set of columns (‘nmrChainCode’, ‘nmrSequenceCode’, ‘nmrResidueName’, ‘nmrAtomName’ that do match the data in the rest of the project.

Once you have a selector, you can use it to extract a copy of the rows you want from the ensemble via ensemble.extract(). extract() accepts a selector and a list of columns to extract. If no selector is provided, extract() will use any criteria provided to generate a selector on-the-fly for selection (in fact, this is the recommended usage pattern.)

The extract() method has some important caveats: 1. It is very important to remember that extract() gives a COPY of the data, not the original

data. If you change the data in the extracted ensemble, the original data will remain unaltered.

  1. If you use a selector created from one ensemble on a different ensemble, it will fail if they don’t have exactly the same number of records. If they do have the same number of records, you will get the records with the corresponding numbers, which is probably not what you want.

  2. In order to avoid the problem in 2., the recommended usage pattern is to let extract() create the selector on-the-fly.

  3. If you must create complex selectors, please make sure that you create the selector from the exact ensemble you wish to extract from.

  1. There are several ways to access the data within the ensemble (or an extracted subset

thereof.) If your ensemble has multiple records, copies of the columns can be accessed by name. For example:

occupancies = ensemble[‘occupancy’] # Gives a Pandas Series; for a list use list(occupancies)

Alternatively, you can convert the records into a tuple of namedTuples using the as_namedTuples() method.

If you have a single record, the values can be accessed by column name. For example:

atomName = singleRecordEnsemble[‘atomName’]

Instead, it’s often better to loop over copies of all the records in a subset using the iterrecords() iterator:

for record in ensemble.iterrecords():

print(record[‘x’], record[‘y’], record[‘z’])

or the itertuples() iterator:
for record in ensemble.itertuples():

print(record.x, record.y, record.z)

Finally, all of the standard Pandas methods for accessing the data are still available. We leave it to the interested coder to investigate that.

  1. Writing data to the ensemble is by far the most tricky operation. There are two primary issues to be dealt with: putting data in the right place within the ensemble, and making sure you’re writing to the ensemble and not a copy of the ensemble.

The easiest case is probably the least common for users: creating an ensemble from scratch. In this case, the best way to create the ensemble is to assign several equal-length lists or tuples to columns within the ensemble:

ensemble = EnsembleData() ensemble[‘modelNumber’] = [1,1,1,2,2,2] ensemble[‘chainCode’] = [‘A’, ‘A’, ‘A’, ‘A’, ‘A’, ‘A’] # Etc,… ensemble = ensemble.reset_index(drop=True) # Cleanup the indexing

More commonly, users may want to alter values in a pre-existing ensemble. The method setValues() can be used for this. The first parameter to setValues() tells setValues() which record to change, and can be an index, a single record selector or a single record ensemble (this last option is easily achieved with the iterrecords() method.) Any subsequent keyword parameters passed to setValues() are the column names and values to set. For example:

extracted = ensemble.extract(residueNames=’MET’, atomNames=’CB’) for record in extracted.iterrecords():

if record[‘x’] > 999:

ensemble.setValues(record, x=999, y=999, z=999)

Just like extract(), exactly matching the source of your selector/selecting ensemble and the ensemble you call setValues() on is vital to prevent unpredictable behavior. You have been warned!

There are currently no insert functions. You can, if you wish, append a row to the ensemble using setValues and passing an index value not currently in the ensemble:

maxEnsembleIndexValue = ensemble.index.max() ensemble.setValues(maxEnsembleIndexValue+1, x=0, y=1, z=2)

ADVANCED: Pandas experts should note that we override __setattr__, __setitem__, and __str__, so some behaviours will be different. Specifically columns with reserved names are type-checked, and you cannot add new columns with data that match only part of the existing rows.

property amideNitrogenSelector: pandas.core.series.Series

- pandas.core.series.Series, immutable - Return a selector that selects only the amide nitrogen.

property amideProtonSelector: pandas.core.series.Series

- pandas.core.series.Series, immutable - Return a selector that selects only the amide proton.

property backboneSelector: pandas.core.series.Series

- pandas.core.series.Series, immutable - Return a selector that selects backbone atoms.

The selector is specific for:

Ca, C’, O, Nh, Hn

classmethod from_pdb(filename: str) pandas.core.frame.DataFrame[source]

Create an EnsembleData from a pdb file.

property methylSelector: pandas.core.series.Series

- pandas.core.series.Series, immutable - Return a selector that selects atoms in methyl groups.

The selector is specific for:

Ala: Cb and attached protons Leu: Both Cd’s and attached protons Met: Ce and attached protons Thr: Cg and attached protons Val: Both Cg’s and attached protons

selector(index=None, chainCodes=None, residueNames=None, sequenceIds=None, atomNames=None, modelNumbers=None, ids=None, elements=None, func=None, inverse=False) pandas.core.series.Series[source]

Make a boolean selector restricted to rows matching the parameters specified.

NB Incompatible values of the selection parameters may raise various errors.

Returns Pandas Series of booleans

ccpn.util.StructureData.averageStructure(ensemble: ccpn.util.StructureData.EnsembleData) ccpn.util.StructureData.EnsembleData[source]

Calculate the average structure from all the models in an EnsembleData object.

ccpn.util.StructureData.pdb2df(filename: str) pandas.core.frame.DataFrame[source]

Create a Pandas dataframe from a pdb file.

ccpn.util.SubclassLoader module

ccpn.util.SubclassLoader.loadSubclasses(path: str, baseclass, levels=2) set[source]

Gather subclasses of baseclass from path

This attempts to import any file in the directory that doesn’t start with a period or underscore, Then checks each class definition in that imported module for subclasses of the specified baseclass and finally returns the set of all classes it found.

ccpn.util.Svg module

Module Documentation here

class ccpn.util.Svg.Svg(path, xCount=1, yCount=1, width=800, height=800)[source]

Bases: ccpn.util.PrintFile.PrintFile

startRegion(xOutputRegion, yOutputRegion, xNumber=0, yNumber=0)[source]
writeLine(x1, y1, x2, y2, colour='#000000')[source]
writePolyline(polyline, colour='#000000')[source]
writeText(text, x, y, colour='#000000', fontsize=10, fontfamily='Lucida Grande')[source]

ccpn.util.Tensor module

class ccpn.util.Tensor.Tensor(xx: float = 0.0, yy: float = 0.0, zz: float = 0.0, isotropic: float = 0.0, axial: float = 0.0, rhombic: float = 0.0, orientationMatrix=None)[source]

Bases: object

Rank 2 tensor value.

Unlike most other ccpn classes Tensor is NOT linked to a Project and does not have a pid

property axial: float

- float, immutable - axial component of tensor (along z axis)

property isotropic: float

- float, immutable - isotropic component of tensor

property orientationMatrix: numpy.array

- <built-in function array>, immutable - 3,3 numpy array containing orientation matrix of tensor. NBNB TBD agree on a sign convention and modify documentation to suit

property rhombic: float

- float, immutable - rhombic component of tensor

property xx: float

- float, immutable - xx component of tensor

property yy: float

- float, immutable - yy component of tensor

property zz: float

- float, immutable - zz component of tensor

ccpn.util.Ticks module

Module Documentation here


ccpn.util.Time module

Simple wrapper to make time more managable

class ccpn.util.Time.Time(x=0, /)[source]

Bases: float

Simple class to print time in ascii, represented as floats as in time.time()

static fromString(string)[source]

Make from a string, inverse of __str__ ccpn.util.Time.Time[source]

:return a Time instance representing now


:return a string that can be used as a timestamp

ccpn.util.UnitConverters module

ccpn.util.UnitConverters.ppmScale(ppmLimits, npoints)[source]
  • ppmLimits – spectrum ppm limits

  • npoints – total number of points


an array in ppm scale (“backwards”)


ccpn.util.Update module

Module Documentation here

class ccpn.util.Update.UpdateAgent(version, showError=None, showInfo=None, askPassword=None, serverUser=None, server='', serverDbRoot='ccpNmrUpdate', serverDbFile='__UpdateData.db', serverDownloadScript='cgi-bin/update/downloadFile', serverUploadScript='cgi-bin/updateadmin/uploadFileVerify', _updateProgressHandler=None, dryRun=True)[source]

Bases: object

diffUpdates(updateFiles=None, write=<built-in method write of _io.TextIOWrapper object>)[source]

Fetch list of updates from server.


See if can write files to local installation.


Download chosen server files to local installation.

isUpdateDifferent(filePath, fileHashCode)[source]

See if local file is different from server file.

class ccpn.util.Update.UpdateFile(installLocation, serverDbRoot, filePath, fileServerTime=None, fileStoredAs=None, fileHashCode=None, shouldInstall=True, shouldCommit=False, isNew=False, serverDownloadScript=None, serverUploadScript=None)[source]

Bases: object


Remove file as update action


Install updated file

ccpn.util.Update.downloadFile(serverScript, serverDbRoot, fileName)[source]

Download a file from the server

ccpn.util.Update.fetchUrl(url, data=None, headers=None, timeout=2.0, decodeResponse=True)[source]

Fetch url request from the server

ccpn.util.Update.installUpdates(version, dryRun=True)[source]

Check whether the byte-string is binary


Check whether the fileName is a binary file (not always guaranteed) Doesn’t check for a fullPath Returns False if the file does not exist


ccpn.util.Url module

Utilities for Url handling


Check whether an internet conection is available by testing the CCPN weblink

ccpn.util.Url.fetchHttpResponse(method, url, data=None, headers=None, proxySettings=None)[source]

Generate an http, and return the response

ccpn.util.Url.fetchUrl(url, data=None, headers=None, timeout=5, proxySettings=None, decodeResponse=True)[source]

Fetch url request from the server

ccpn.util.Url.uploadFile(url, fileName, data=None)[source]

ccpn.util.UserPreferences module

Module Documentation here

class ccpn.util.UserPreferences.UserPreferences(readPreferences=True)[source]

Bases: object

Class to handle reading user information from the preferences file


Decode a user value


Encode a user value

property proxyDefined

- None, immutable - Return True if the settings contains the USEPROXY attribute

ccpn.util.UserPreferences.getPreferences(skipUserPreferences=False, defaultPath=None, userPath=None)[source]

Read the preferences file and merge with user specific preferences

ccpn.util.convertPaths module

Module Documentation here

ccpn.util.convertPaths.main(ROOT, PATH1, PATH2)[source]

ccpn.util.decorators module

Module Documentation here


Decorator to give the realtime call stack for the decorated function. Adds _callList=None, _callStr=None to the parameter list for the function call so function can access full list.

_callList is tuple of tuples of the form:

((caller info, simple print string), string)

caller info is: (index, name of calling method, stack info)

simple print string is repr if caller info.

The function will need either _callList=None, or **kwds adding to the parameter list.

# Not fully tested














A decorator to log the invocation of the call


A decorator to log the invocation of the call

ccpn.util.decorators.logCommand(prefix='', get=None, isProperty=False)[source]

A decorator to log the invocation of the call to a Framework, Project, … method. Use prefix to set the proper command context, e.g. ‘application.’ or ‘project.’ Use isProperty to get ‘ = ‘args[1]

ccpn.util.decorators.notify(trigger, preExecution=False)[source]

A decorator wrap a method around a notification blanking with explicit notification pre- or post-execution

ccpn.util.decorators.profile(dirPath='~', asText=False)[source]

Get the stats of all related calls firing from inside a specific function/method. Add on top of a function/method to profile it. E.g.:

@profile(dirPath=’/myDesktopPath/’) def my function(*args): …

  • dirPath – str, dir where to dump the pstat file.

  • asText – bool. Make a pstat copy as a human readable text file.


A decorator to wrap a method in an undo block Requires that the ‘self’ has ‘project’ as an attribute

ccpn.util.decorators.pstatToText(pstatPath, outPath=None)[source]

Converts a profile file of type .pstat into a plain text file. :param pstatPath: path of the pstat file. (The output of the decorator “profile”) :param outPath: output pat. Including the file name and extension “.txt”.

If None, saves in the same location of pstat with same original name


the stats object for the file


Class to implement a quick caching decorator

For speed, only the first argument of the wrapped function is taken as the key


Use class as singleton. From: Annotated by GWV Modified by EJB to keep record of all singletons

  • these can later be destroyed, was causing leakage between running testcases


calculate execution time of a function/method


calculate execution time of a function/method


ccpn.util.floatUtils module

fExp and fMan are the functions giving the exponent and mantissa of the decimal floating point representation of a float then we’d expect the following statements to all return true:

fExp(154.3) == 2.0 fMan(154.3) == 1.543 fExp(-1000) == 3 fMan(-1000) == -1

fRepr(number) -> (mantissa, exponent)

fRound(number) -> round to nearest base-10 value; fRound(154.3) == 200

Solution taken from:

ccpn.util.floatUtils.fExp(number) int[source]
ccpn.util.floatUtils.fMan(number) float[source]
ccpn.util.floatUtils.fRepr(number) tuple[source]

base10 equivalent of math.frepr

ccpn.util.floatUtils.fRound(number) float[source]

round to nearest base-10 value

ccpn.util.isotopes module

This file contains NMR isotope related functionalities

class ccpn.util.isotopes.Field(field)[source]

Bases: dict

Class to hold the frequencies of various nuclei for a given field


Add a Nucleus instance defined by isotopeCode


Find nucleus corresponding with freq; return None if not found

property frequencies

- None, immutable - return a tuple of frequencies for this field

isInRange(nucleus, freq)[source]

return True in freq is withing validRange

property nuclei

- None, immutable - return a tuple of Nucleus instances for this field

validRange = (-1.0, 0.5)
class ccpn.util.isotopes.IsotopeRecord(**kwargs)[source]

Bases: ccpn.util.traits.CcpNmrJson.CcpNmrJson

Class to store isotope information

classVersion = 1.0
saveAllTraitsToJson = True
class ccpn.util.isotopes.IsotopeRecords(*args, **kwargs)[source]

Bases: ccpn.util.traits.CcpNmrJson.CcpnJsonDirectoryABC

Singleton class to contain all isotopeRecords as (isotopeCode, IsotopeRecord) (key,value) pairs

attributeName = 'isotopeCode'
directory = Path('/Users/ejb66/PycharmProjects/Git/AnalysisV3/config/isotopeRecords')
isotopesWithSpin(minValue=0.5, maxValue=None)[source]

Return list of all isotopeRecords that have spin between minValue and maxValue (inclusive)

sorted = True
class ccpn.util.isotopes.Nucleus(isotopeCode)[source]

Bases: str

Class that behaves as a string, but holds the information about a particular nucleus and has usefull (!?) conversion methods

property axisCode

- None, immutable - Return axis code string


Return field (T) at absolute frequency (MHz)


Return absolute frequency (MHz) at field (T)

property gamma

- None, immutable - return gamma in MHz/T; NB the isotopeRecord for 1H has the shielded g-value; most likely also for the other nuclei (if available)

muDivHbar = 7.62259328547
ccpn.util.isotopes.checkIsotope(isotopeCode) str[source]

Convert isotopeCode string to most probable isotope code - defaulting to ‘1H’

This function is intended for external format isotope specifications; mostly in SpectrumSource parameter reading routines


Return the most likely field corresponding to spectrometerFrequencies, or None if it cannot be determined


return a tuple of Nuclei instances corresponding to spectrometerFrequencies or None if not identified


Coveniance funtions to return the istopeRecords Instance


:return the nucleus symbol for isotopeCode or None if not found


Get standard element symbol matching name or axisCode

NB, the first letter takes precedence, so e.g. ‘CD’ returns ‘C’ (carbon) rather than ‘CD’ (Cadmium)


Get standard isotope code matching atom name or axisCode string

ccpn.util.jsonIo module

Local enhancements to json, adding support for reading and writing pandas.Series, pandas.DataFrame, numpy.ndarray, OrderedDict, and ccpnmodel.ccpncore.Tensor

pandas.Panel is deprecated and will be loaded as a pandas.DataFrame

ccpn.util.jsonIo.dump(obj: object, fp: str, indent: int = 2, **kwds)[source]

Dump object to json file with extended object type support

ccpn.util.jsonIo.dumps(obj: object, indent: int = 2, **kwds)[source]

Dump object to json string with extended object type support

ccpn.util.jsonIo.load(fp, **kwds)[source]

Load json from file fp with extended object type support

ccpn.util.jsonIo.loads(s: str, **kwds)[source]

Load json from string s with extended object type support

ccpn.util.recursive_import module

python-recursive-import-test [<options>] [<dir> …]

Recursively find the files under the given directories and launch Python subprocess that attempt to import them individually. This is used to check initalization time problems and dependencies: a well-written program should not do much on module initialization. In other words, a good program allows its modules to be imported individually. This has important consequences in large codebases, and allows more flexibility.


Given a Python source filename, return a module name to import.

ccpn.util.recursive_import.find_all_pyfiles(topDirectory, ignoreDirs=(), ignoreFiles=())[source]

Find all the files ending with .py inside topDirectory


Find all the files ending with .py

ccpn.util.recursive_import.importAllPyfiles(topDirectory, ignoreDirs=(), ignoreFiles=(), addToSysPath: Optional[str] = None)[source]

Test import all python files in a directory tree. topDirectory must be (intended to be) on the Python path


ccpn.util.updateHeader module