cdxcore.subdir#
Functions
|
Create a root directory for versioned caching on disk using |
Classes
|
Central control parameters for caching. |
|
Information on cfunctions decorated with |
|
A class which encodes standard behaviour of a caching strategy. |
Utility class to track caching and be able to delete all dependent objects. |
|
|
General purpose file formats for |
|
|
Exceptions
Exception raised in case a file was read which had a version, but no test version was provided. |
- class cdxcore.subdir.CacheController(*, exclude_arg_types=[<class 'cdxcore.verbose.Context'>], cache_mode='on', max_filename_length=48, hash_length=8, debug_verbose=None, keep_last_arguments=False)[source]#
Bases:
objectCentral control parameters for caching.
When a parameter object of this type is assigned to a
cdxcore.subdir.SubDir, then it is passed on when sub-directories are created. This way all sub directories have the same caching behaviour.- Parameters:
- exclude_arg_typeslist[type | str], optional
List of types or names of types to exclude from producing unique ids from function arguments. Strings are compated to
type(arg).__name__.Defaults to
[Context].- cache_modeCacheMode, default
ON Top level cache control. Set to “OFF” to turn off all caching.
- max_filename_lengthint, default
48 Maximum filename length. If unique id’s exceed the file name a hash of length
hash_lengthwill be intergated into the file name. Seecdxcore.uniquehash.NamedUniqueHash.- hash_lengthint, default
8 Length of the hash used to make sure each filename is unique See
cdxcore.uniquehash.NamedUniqueHash.- debug_verbose
cdxcore.verbose.Context| None, defaultNone If not
Noneprint caching process messages to this object.- keep_last_argumentsbool, default
False Keep a dictionary of all parameters as string representations after each function call. If the function
Fwas decorated using :meth:cdxcore.subdir.SubDir.cache, you can access this information viaF.cache_info.last_arguments.Note that strings are limited to 100 characters per argument to avoid memory overload when large objects are passed.
- class cdxcore.subdir.CacheInfo(name, idversion, keep_last_arguments)[source]#
Bases:
PrettyObjectInformation on cfunctions decorated with
cdxcore.subdir.SubDir.cache().Functions decorated with
cdxcore.subdir.SubDir.cache()will have a membercache_infoof this type- filename#
Unique filename of the last function call.
- label#
Label of the last function call.
- last_arguments#
Last arguments used. This member is only present if
keep_last_argumentswas set toTruefor the relevantcdxcore.subdir.CacheController.
- last_cached#
Whether the last function call restored data from disk.
- name#
Decoded name of the function.
- path#
Fully qualified path where the file was stored.
- unique_id#
Unique ID of the last function call.
- version#
(hash) version used. This is equal to
F.version.unique_id64.
- class cdxcore.subdir.CacheMode(mode=None)[source]#
Bases:
objectA class which encodes standard behaviour of a caching strategy.
Summary mechanics:
Action
on
gen
off
update
clear
readonly
load cache from disk if exists
x
x
x
write updates to disk
x
x
x
delete existing object
x
delete existing object if incompatible
x
x
x
Standard Caching Semantics
Assuming we wish to cache results from calling a function
fin a file namedfilenamein a directorydirectory, then this is theCacheModewaterfall:def cache_f( filename : str, directory : SubDir, version : str, cache_mode : CacheMode ): if cache_mode.delete: directory.delete(filename) if cache_mode.read: r = directory.read(filename, default=None, version=version, raise_on_error=False, delete_wrong_version=cache_mode.del_incomp ) if not r is None: return r r = f(...) # compute result if cache_mode.write: directory.write(filename, r, version=version, raise_on_error=False ) return r
See
cdxcore.subdir.SubDir.cache()for a comprehensive implementation.- Parameters:
- modestr, optional
Which mode to use:
"on","gen","off","update","clear"or"readonly".The default is
Nonein which case"on"is used.
- CLEAR = 'clear'#
- GEN = 'gen'#
- HELP = "'on' for standard caching; 'gen' for caching but keep existing incompatible files; 'off' to turn off; 'update' to overwrite any existing cache; 'clear' to clear existing caches; 'readonly' to read existing caches but not write new ones"#
Standard
confighelp text, to be used withcdxcore.config.Config.__call__()as follows:from cdxcore.config import Config from cdxcore.subdir import CacheMode def get_cache_mode( config : Config ) -> CacheMode: return CacheMode( config("cache_mode", "on", CacheMode.MODES, CacheMode.HELP) )
- MODES = ['on', 'gen', 'off', 'update', 'clear', 'readonly']#
List of available modes in text form. This list can be used as
castparameter when callingcdxcore.config.Config.__call__():from cdxcore.config import Config from cdxcore.subdir import CacheMode def get_cache_mode( config : Config ) -> CacheMode: return CacheMode( config("cache_mode", "on", CacheMode.MODES, CacheMode.HELP) )
- OFF = 'off'#
- ON = 'on'#
- READONLY = 'readonly'#
- UPDATE = 'update'#
- class cdxcore.subdir.CacheTracker[source]#
Bases:
objectUtility class to track caching and be able to delete all dependent objects.
- class cdxcore.subdir.Format(*values)[source]#
Bases:
EnumGeneral purpose file formats for
cdxcore.subdir.SubDir.Format
Restores objects
Human readable
Speed
Compression
Extension
Types
PICKLE
yes
no
high
no
.pck
all
JSON_PLAIN
no
yes
low
no
.json
all
JSON_PICKLE
yes
limited
low
no
.jpck
all
BLOSC
yes
no
high
yes
.zbsc
all
GZIP
yes
no
high
yes
.pgz
all
POLARS_PARQUET
yes
no
high
yes
.pgz
polars
cdxcore.subdir.SubDirsupportsPOLARS_PARQUETfor reading and writingpolars.DataFramefiles to parquet. Version information is stored in meta data. When used, the object passed tocdxcore.subdir.write()must be a polars data frame.- BLOSC = 3#
bloscbinary compressed format.
- JSON_PICKLE = 1#
jsonpickleformat.
- JSON_PLAIN = 2#
jsonformat.
- POLARS_PARQUET = 10#
- class cdxcore.subdir.SubDir(name, parent=None, *, ext=None, fmt=None, create_directory=None, cache_controller=None, delete_everything=False, delete_everything_upon_exit=False)[source]#
Bases:
objectSubDirimplements a transparent i/o interface for storing data in files.Directories
Instantiate a
SubDirwith a directory name. There are some pre-defined relative system paths the name can refer to:from cdxcore.subdir import SubDir parent = SubDir("!/subdir") # relative to system temp directory parent = SubDir("~/subdir") # relative to user home directory parent = SubDir("./subdir") # relative to current working directory (explicit) parent = SubDir("subdir") # relative to current working directory (implicit) parent = SubDir("/tmp/subdir") # absolute path (linux) parent = SubDir("C:/temp/subdir") # absolute path (windows) parent = SubDir("") # current working directory
Sub-directories can be generated in a number of ways:
subDir = parent('subdir') # using __call__ subDir = SubDir('subdir', parent) # explicit constructor subDir = SubDir('subdir', parent="!/") # explicit constructor with parent being a string
Files managed by
SubDirwill usually have the same extension. This extension can be specified withext, or as part of the directory string:subDir = SubDir("~/subdir", ext="bin") # set extension to 'bin' subDir = SubDir("~/subdir;*.bin") # set extension to 'bin'
Leaving the extension as default
NoneallowsSubDirto automatically use the extension associated with any specified format.Copy Constructor
The constructor is shallow.
File I/O
Write data with
cdxcore.subdir.SubDir.write():subDir.write('item3',item3) # explicit subDir['item1'] = item1 # dictionary style
Note that
cdxcore.subdir.SubDir.write()can write to multiple files at the same time.Read data with
cdxcore.subdir.SubDir.read():item = subDir('item', 'i1') # returns 'i1' if not found. item = subdir.read('item') # returns None if not found item = subdir.read('item','i2') # returns 'i2' if not found item = subDir['item'] # raises a KeyError if not found
Treat files in a directory like dictionaries:
for file in subDir: data = subDir[file] f(item, data) for file, data in subDir.items(): f(item, data)
Delete items:
del subDir['item'] # silently fails if 'item' does not exist subDir.delete('item') # silently fails if 'item' does not exist subDir.delete('item', True) # raises a KeyError if 'item' does not exit
Cleaning up:
parent.delete_all_content() # silently deletes all files with matching extensions, and sub directories.
File Format
SubDirsupports a number of file formats viacdxcore.subdir.Format. Those can be controlled with thefmtkeyword in various functions not leastcdxcore.subdir.SubDir:subdir = SubDir("!/.test", fmt=SubDir.JSON_PICKLE)
See
cdxcore.subdir.Formatfor supported formats.Polars
A
SubDircan read and writepolars.DataFrameif the format is set tocdxcore.subdir.Format.POLARS_PARQUET:import polars as pl import numpy as np from cdxcore.subdir import SubDir x = np.linspace(0,1,5) y = np.sin(x) df = pl.DataFrame({"x":pl.Series(x,pl.Float32), "y":pl.Series(y,pl.Float32)}) sub = SubDir("!/polars", fmt=SubDir.POLARS_PARQUET) sub.write("test", df) r = sub.read("test", raise_on_error=True) assert np.all(r == df)
Version handling is supported with parquet files.
- Parameters:
- namestr:
Name of the directory.
The name may start with any of the following special characters:
'.'for current directory.'~'for home directory.'!'for system default temp directory. Note that outside any administator imposed policies, sub directories of!are permanent.'?'for a temporary temp directory; seecdxcore.subdir.SubDir.temp_temp_dir()regarding semantics.Most importantly, every
SubDirwill be constructed with a different (truly) temporary sub directory. If used,delete_everything_upon_exitis alwaysTrue.
The directory name may also contain a formatting string for defining
exton the fly: for example use"!/test;*.bin"to specify a directory"test"in the user’s temp directory with extension"bin".The directory name can be set to
Nonein which case it is always empty and attempts to write to it fail withEOFError.- parentstr | SubDir | None, default
None Parent directory.
If
parentis acdxcore.subdir.SubDirthen its parameters are used as default values.- extstr | None, default
None Extension for files managed by this
SubDir. All files managed byselfwill share the same extension.If set to
""no extension is assigned to this directory. That mean that all files are considered. For example,cdxcore.subdir.SubDir.files()then returns all files contained in the directory, not just files with a specific extension.If
extisNone, then useparent.extor ifparentwas provided, or otherwise the extension defined byfmt:‘pck’ for the default PICKLE format.
‘json’ for JSON_PLAIN.
‘jpck’ for JSON_PICKLE.
‘zbsc’ for BLOSC.
‘pgz’ for GZIP.
‘prq’ for POLARS_PARQUET.
- fmt
cdxcore.subdir.Format| None, defaultFormat.PICKLE One of the
cdxcore.subdir.Formatcodes.If
extis left toNoneandparentisNonethen setting the a format will also set the corrspondingext.- create_directorybool | None, default
False Whether to create the directory upon creation of the
SubDirobject; otherwise it will be created upon firstcdxcore.subdir.SubDir.write().Set to
Noneto use the setting of the parent directory, orFalseif no parent is specified.- cache_controller
cdxcore.subdir.CacheController| None, defaultNone An object which fine-tunes the behaviour of
cdxcore.subdir.SubDir.cache(). Seecdxcore.subdir.CacheControllerdocumentation for further details.- delete_everythingbool, default
False Delete all contents in the newly defined sub directory upon creation.
- delete_everything_upon_exitbool, default
False Delete all contents of the current exist if
selfis deleted. This is the alwaysTrueif the"?/"pretext was used.Note, however, that this will only be executed once the object is garbage collected.
Default is, for some good reason, is
False.
- DEFAULT_FORMAT = 0#
Default
cdxcore.subdir.Format:Format.PICKLE
- class Format(*values)#
Bases:
EnumThe same as
cdxcore.subdir.Formatfor convenience- BLOSC = 3#
bloscbinary compressed format.
- JSON_PICKLE = 1#
jsonpickleformat.
- JSON_PLAIN = 2#
jsonformat.
- POLARS_PARQUET = 10#
- __call__(element=None, default=<object object>, raise_on_error=False, *, version=None, ext=None, fmt=None, delete_wrong_version=True, create_directory=None)[source]#
Read either data from a file, or return a new sub directory.
If only the
elementargument is used, then this function returns a new sub directory namedelement.If both
elementanddefaultarguments are used, then this function attempts to read the fileelementfrom disk, returningdefaultif it does not exist.Assume we have a subdirectory
sd:from cdxcore.subdir import SubDir sd = SubDir("!/test")
Reading files:
x = sd('file', None) # reads 'file' with default value None x = sd('sd/file', default=1) # reads 'file' from sub directory 'sd' with default value 1 x = sd('file', default=1, ext="tmp") # reads 'file.tmp' with default value 1
Create sub directory:
sd2 = sd("subdir") # creates and returns handle to subdirectory 'subdir' sd2 = sd("subdir1/subdir2") # creates and returns handle to subdirectory 'subdir1/subdir2' sd2 = sd("subdir1/subdir2", ext=".tmp") # creates and returns handle to subdirectory 'subdir1/subdir2' with extension "tmp" sd2 = sd(ext=".tmp") # returns handle to current subdirectory with extension "tmp"
- Parameters:
- elementstr | None
File or directory name, or a list thereof.
elementcan beNoneifdefaultis left at its dummy valueSubDir.RET_SUB_DIR(the default) in which case__call__refers to the current directory.- defaultAny, default
SubDir.RET_SUB_DIR If specified, this function reads
elementwithread( element, default, *args, **kwargs ).If
defaultis not specified and left at the dummy valueSubDir.RET_SUB_DIR, then this function returns a new sub-directory by callingSubDir(element,parent=self,ext=ext,fmt=fmt).- create_directorybool, default
None When creating sub-directories:
Whether or not to instantly create the sub-directory. The default,
None, is to inherit the behaviour fromself.- raise_on_errorbool, default
False When reading files:
Whether to raise an exception if reading an existing file failed. By default this function fails silently and returns
default.- versionstr | None, default
None When reading files:
If not
None, specifies the version of the current code base.In this case, this version will be compared to the version of the file being read. If they do not match, read fails (either by returning default or throwing a
cdxcore.version.VersionErrorexception).You can specify version
"*"to accept any version. Note that this is distinct to usingNonewhich stipulates that the file should not have version information.- delete_wrong_versionbool, default
True. When reading files:
If
True, and if a wrong version was found, delete the file.- extstr | None, default is
None. When reading files:
Extension to be used, or a list thereof if
elementis a list. Defaults to the extension ofself.Semantics:
Noneto use the default extension ofself."*"to use the extension implied byfmt.""to turn off extension management.
When creating sub-directories:
Extension for the new subdirectory; set to
Noneto inherit the parent’s extension.- fmt
cdxcore.subdir.Format| None, defaultNone When reading files:
File format or
Noneto use the directory’s default. Note thatfmtcannot be a list even ifelementis. Unlessextor the SubDir’s extension is"*", changing the format does not automatically change the extension.When creating sub-directories:
Format for the new sub-directory; set to
Noneto inherit the parent’s format.
- Returns:
- Objecttype | SubDir
Either the value in the file, a new sub directory, or lists thereof.
- static as_format(format_name)[source]#
Converts a named format into the respective format code.
Example:
format = SubDir.as_format( config("format", "pickle", SubDir.FORMAT_NAMES, "File format") )
- auto_ext(ext_or_fmt=None)[source]#
Computes the effective extension based on theh inputs
ext_or_fmt, and the current settings forself.If
ext_or_fmtis set to"*"then the extension associated to the format ofselfis returned.- Parameters:
- ext_or_fmtstr |
cdxcore.subdir.Format| None, defaultNone An extension or a format.
- ext_or_fmtstr |
- Returns:
- extstr
The extension with leading
'.'.
- auto_ext_fmt(*, ext=None, fmt=None)[source]#
Computes the effective extension and format based on inputs
extandfmt, each of which defaults to the respective values ofself.Resolves an
extof"*"into the extension associated withfmt.- Returns:
- (ext, fmt)tuple
Here
extcontains the leading'.'andfmtis of typecdxcore.subdir.Format.
- cache(version=None, *, dependencies=None, label=None, uid=None, name=None, in_sub_dir=None, exclude_args=None, include_args=None, exclude_arg_types=None, version_auto_class=True, name_of_func_name_arg='func_name')[source]#
Advanced versioned caching for callables.
Versioned caching is based on the following two simple principles:
Unique Call IDs:
When a function is called with some parameters, the wrapper identifies a unique ID based on the qualified name of the function and on its runtime functional parameters (ie those which alter the outcome of the function). When a function is called the first time with a given unique call ID, it will store the result of the call to disk. If the function is called with the same call ID again, the result is read from disk and returned.
To compute unique call IDs
cdxcore.uniquehash.NamedUniqueHashis used by default.Code Version:
Each function has a version, which includes dependencies on other functions or classes. If the version of data on disk does not match the current version, it is deleted and the generating function is called again. This way you can use your code to drive updates to data generated with cached functions.
Behind the scenes this is implemented using
cdxcore.version.version()which means that the version of a cached function can also depend on versions of non-cached functions or other objects.
Caching Functions#
Caching a simple function
fis staight forward:from cdxcore.subdir import SubDir cache = SubDir("!/.cache") cache.delete_all_content() # for illustration @cache.cache("0.1") def f(x,y): return x*y _ = f(1,2) # function gets computed and the result cached _ = f(1,2) # restore result from cache _ = f(2,2) # different parameters: compute and store result
Cache another function
gwhich callsf, and whose version therefore onf’s version:@cache.cache("0.1", dependencies=[f]) def g(x,y): return g(x,y)**2
Debugging
When using automated caching it is important to understand how changes in parameters and the version of the a function affect caching. To this end,
cdxcore.subdir.SubDir.cache()supports a tracing mechanism via the use of acdxcore.subdir.CacheController:from cdxcore.subdir import SubDir, CacheController, Context ctrl = CacheController( debug_verbose=Context("all") ) cache = SubDir("!/.cache", cache_controller=ctrl ) cache.delete_all_content() # <- delete previous cached files, for this example only @cache.cache("0.1") def f(x,y): return x*y _ = f(1,2) # function gets computed and the result cached _ = f(1,2) # restore result from cache _ = f(2,2) # different parameters: compute and store result
Returns:
00: cache(f@__main__): function registered for caching into 'C:/Users/hans/AppData/Local/Temp/.cache/'. 00: cache(f@__main__): called 'f@__main__' version 'version 0.1' and wrote result into 'C:/Users/hans/AppData/Local/Temp/.cache/f@__main__ 668a6b111549e288.pck'. 00: cache(f@__main__): read 'f@__main__' version 'version 0.1' from cache 'C:/Users/hans/AppData/Local/Temp/.cache/f@__main__ 668a6b111549e288.pck'. 00: cache(f@__main__): called 'f@__main__' version 'version 0.1' and wrote result into 'C:/Users/hans/AppData/Local/Temp/.cache/f@__main__ b5609542d7da0b04.pck'.
Non-Functional Parameters
A function may have non-functional parameters which do not alter the function’s outcome. An example are
debugflags:from cdxcore.subdir import SubDir cache = SubDir("!/.cache") @cache.cache("0.1", dependencies=[f], exclude_args='debug') def g(x,y,debug): # <--' 'debug' is a non-functional parameter if debug: print(f"h(x={x},y={y})") return g(x,y)**2
You can define certain types as non-functional for all functions wrapped by
cdxcore.subdir.SubDir.cache()when construcing thecdxcore.cache.CacheControllerparameter for incdxcore.subdir.SubDir:from cdxcore.subdir import SubDir class Debugger: def output( cond, message ): print(message) ctrl = CacheController(exclude_arg_types=[Debugger]) # <- exclude 'Debugger' parameters from hasing cache = SubDir("!/.cache") @cache.cache("0.1", dependencies=[f]) def g(x,y,debugger : Debugger): # <-- 'debugger' is a non-functional parameter debugger.output(f"h(x={x},y={y})") return g(x,y)**2
Unique IDs and File Naming
The unique call ID of a decorated function is by logicaly generated by its fully qualified name and a unique hash of its functional parameters.
By default,
cdxcore.uniquehash.NamedUniqueHashis used to compute unique hashes. Key default behaviours ofcdxcore.uniquehash.NamedUniqueHash:cdxcore.uniquehash.NamedUniqueHashhashes objects via their__dict__or__slot__members. This can be overwritten for a class by implementing__unique_hash__; seecdxcore.uniquehash.NamedUniqueHash.Function members of objects or any members starting with ‘_’ are not hashed unless this behaviour is changed using
cdxcore.subdir.CacheController.Numpy and panda frames are hashed using their byte representation. That is slow and not recommended. It is better to identify numpy/panda inputs via their generating characteristic ID.
Either way, hashes are not particularly human readable. It is often useful to have unique IDs and therefore filenames which carry some context information.
This can be achieved by using
label:from cdxcore.subdir import SubDir, CacheController ctrl = CacheController( debug_verbose=Context("all") ) cache = SubDir("!/.cache", cache_controller=ctrl ) cache.delete_all_content() # for illustration @cache.cache("0.1") # <- no ID def f1(x,y): return x*y @cache.cache("0.1", label="f2({x},{y})") # <- label uses a string to be passed to str.format() def f2(x,y): return x*y
We can also use a function to generate a
label. In that case all parameters to the function including itsfunc_nameare passed to the function.:@cache.cache("0.1", label=lambda x,y: f"h({x},{y})", exclude_args='debug') def h(x,y,debug=False): if debug: print(f"h(x={x},y={y})") return x*y
We obtain:
f1(1,1) f2(1,1) h(1,1) 00: cache(f1@__main__): function registered for caching into 'C:/Users/hans/AppData/Local/Temp/.cache/'. 00: cache(f2@__main__): function registered for caching into 'C:/Users/hans/AppData/Local/Temp/.cache/'. 00: cache(h@__main__): function registered for caching into 'C:/Users/hans/AppData/Local/Temp/.cache/'. 00: cache(f1@__main__): called 'f1@__main__' version 'version 0.1' and wrote result into 'C:/Users/hans/AppData/Local/Temp/.cache/f1@__main__ ef197d80d6a0bbb0.pck'. 00: cache(f2@__main__): called 'f2(1,1)' version 'version 0.1' and wrote result into 'C:/Users/hans/AppData/Local/Temp/.cache/f2(1,1) bdc3cd99157c10f7.pck'. 00: cache(h@__main__): called 'h(1,1)' version 'version 0.1' and wrote result into 'C:/Users/hans/AppData/Local/Temp/.cache/h(1,1) d3fdafc9182070f4.pck'.
Note that the file names
f2(1,1) bdc3cd99157c10f7.pckandh(1,1) d3fdafc9182070f4.pckfor thef2andhfunction calls are now easier to read as they are comprised of the label of the function and a terminal hash key. The trailing hash is appended because we do not assume that the label returned bylabelis unique. Therefore, a hash generated from all thelabelitself and all pertinent arguments will be appended to the filename.If we know how to generate truly unique IDs which are always valid filenames, then we can use
uidinstead oflabel:@cache.cache("0.1", uid=lambda x,y: f"h2({x},{y})", exclude_args='debug') def h2(x,y,debug=False): if debug: print(f"h(x={x},y={y})") return x*y h2(1,1)
yields:
00: cache(h2@__main__): function registered for caching into 'C:/Users/hans/AppData/Local/Temp/.cache/'. 00: cache(h2@__main__): called 'h2(1,1)' version 'version 0.1' and wrote result into 'C:/Users/hans/AppData/Local/Temp/.cache/h2(1,1).pck'.
In particular, the filename is now
h2(1,1).pckwithout any hash. Ifuidis used the parameter of the function are not hashed. Likelabelthe parameteruidcan also be astr.format()string or a callable.Controlliong which Parameters to Hash
To specify which parameters are pertinent for identifying a unique ID, use:
include_args: list of functions arguments to include. IfNone, use all parameteres as input in the next stepexclude_args: list of function arguments to exclude, if notNone.exclude_arg_types: a list of types or names of type to exclude. This is helpful if control flow is managed with dedicated data types. An example of such a type iscdxcore.verbose.Contextwhich is used to print hierarchical output messages. Types can be globally excluded using acdxcore.subdir.CacheControllerwhen callingcdxcore.subdir.SubDir.
Numpy/Pandas
Numpy/Panda data should not be hashed for identifying unique call IDs. Instead, use the defining characteristics for generating the data frames.
For example:
from cdxcore.pretty import PrettyObject from cdxcore.subdir import SubDir cache = SubDir("!/.cache") cache.delete_all_content() # for illustration @cache.cache("0.1") def load_src( src_def ): result = ... load ... return result # ignore 'src_result'. It is uniquely identified by 'src_def' --> @cache.cache("0.1", dependencies=[load_src], exclude_args=['data']) def statistics( stats_def, src_def, data ): stats = ... using data return stats src_def = PrettyObject() src_def.start = "2010-01-01" src_def.end = "2025-01-01" src_def.x = 0.1 stats_def = PrettyObject() stats_def.lambda = 0.1 stats_def.window = 100 data = load_src( src_def ) stats = statistics( stats_def, src_def, data )
While instructive, this case is not optimal: we do not really need to load
dataif we can reconstructstatsfromdata(unless we needdatafurther on).Consider therefore:
@cache.cache("0.1") def load_src( src_def ): result = ... load ... return result # ignore 'src_result'. It is uniquely identified by 'src_def' --> @cache.cache("0.1", dependencies=[load_src]) def statistics_only( stats_def, src_def ): data = load_src( src_def ) # <-- embedd call to load_src() here stats = ... using src_result return stats stats = statistics_only( stats_def, src_def )
Caching Member Functions#
You can cache member functions like any other function. Note that
cdxcore.version.version()information are by default inherited, i.e. member functions will be dependent on the version of their defining class, and class versions will be dependent on their base classes’ versions:from cdxcore.subdir import SubDir, version cache = SubDir("!/.cache") cache.delete_all_content() # for illustration @version("0.1") class A(object): def __init__(self, x): self.x = x @cache.cache("0.1") def f(self, y): return self.x*y a = A(x=1) _ = a.f(y=1) # compute f and store result _ = a.f(y=1) # load result back from disk a.x = 2 _ = a.f(y=1) # 'a' changed: compute f and store result b = A(x=2) _ = b.f(y=1) # same unique call ID as previous call # -> restore result from disk
WARNING:
cdxcore.uniquehash.UniqueHashdoes not by default process members of objects or dictionaries which start with a “_”. This behaviour can be changed usingcdxcore.subdir.CacheController. For reasonably complex objects it is recommended to implement for your objects the a custom hashing function:__unique_hash__( self, uniqueHash : UniqueHash, debug_trace : DebugTrace )
This function is described at
cdxcore.uniquehash.UniqueHash.Caching Bound Member Functions#
Caching bound member functions is technically quite different to caching a function of a class in general, but also supported:
from cdxcore.subdir import SubDir, version cache = SubDir("!/.cache", cache_controller = CacheController(debug_verbose=Context("all"))) cache.delete_all_content() # for illustration class A(object): def __init__(self,x): self.x = x def f(self,y): return self.x*y a = A(x=1) f = cache.cache("0.1", uid=lambda self, y : f"a.f({y})")(a.f) # <- decorate bound 'f'. r = c(y=2)
In this case the function
fis bound toa. The object is added asselfto the function parameter list even though the bound function parameter list does not includeself. This, together with the comments on hashing objects above, ensures that (hashed) changes toawill be reflected in the unique call ID for the member function.Managing Caching Accross a Project#
For project-wide use it is usually convenient to control caching at the level of a project-wide cache root directory. The classs
cdxcore.subdir.VersionedCacheRootis a thin convenience wrapper around acdxcore.subdir.SubDirwith acdxcore.subdir.CacheController.The idea is to have a central file,
cache.pywhich contains the central root for caching. We recommend using an environment variable to be able to control the location of this directory out side the code. Here is an example with an environment variablePROJECT_CACHE_DIR:# file cache.py from cdxcore.subdir import VersionedCacheRoot import os as os cache_root = VersionedCacheRoot( os.getenv("PROJECT_CACHE_DIR", "!/.cache") )
In a particular project file, say
pipeline.pycreate a file-local cache directory and use it:# file pipeline.py from cache import cache_root cache_dir = cache_root("pipeline") @cache_dir.cache("0.1") def f(x): return x+2 @cache_dir.cache("0.1", dependencies=[f]) def g(x) return f(x)**2 # ...
In case you have issues with caching you can use the central root directory to turn on tracing accross your project:
from cdxcore.verbose import Context cache_root = VersionedCacheRoot( os.getenv("PROJECT_CACHE_DIR", "!/.cache"), debug_verbose=Context.all # turn full traing on )
- Parameters:
- versionstr | None, default
None Version of the function.
If
Nonethen a commonFmust be decorated manually ithcdxcore.version.version().If set, the function
Fis automatically first decorated withcdxcore.version.version()for you.
- dependencieslist[type] | None, default
None A list of version dependencies, either by reference or by name. See
cdxcore.version.version()for details on name lookup if strings are used.- labelstr | Callable | None, default
None Specify a human-readable label for the function call given its parameters.
This label is used to generate the cache file name, and is also printed in when tracing hashing operations. Labels are not assumed to be unique, hence a unique hash of the label and the parameters to this function will be appended to generate the actual cache file name.
Use
uidinstead iflabelrepresents valid unique filenames. You cannot specify bothuidandlabel. If neitheruidandlabelare present,namewill be used.A
labelcan start with a directory, i.e.lablel : lambda x, y : f"x/y"is a valid pattern.Usage:
If
labelis aCallablethenlabel( func_name=name, **parameters )will be called to generate the actual label.The parameter
func_namerefers to the qualified name of the function. Its value can be overwitten byname, while the parameter name itself can be overwritten usingname_of_func_name_arg, see below.If
labelis a plain string without{}formatting: use this string as-is.If
labelis a string with{}formatting, thenlabel.format( func_name=name, **parameters )will be used to generate the actual label.The parameter
func_namerefers to the qualified name of the function. Its value can be overwitten byname, while the parameter name itself can be overwritten usingname_of_func_name_arg, see below.
See above for examples.
labelcannot be used alongsideuid.- uidstr | Callable | None, default
None Alternative to
labelwhich is assumed to generate a unique cache file name. It has the same semantics aslabel. When used, parameters to the decorated function are not hashed as theuidis assumed to be already unique. The string must be a valid file nameA
uidcan start with a directory.Use
labelif the id is not unique. You cannot specify bothuidandlabel. If neitheruidandlabelare present,namewill be used (as non-uniquelabel).- namestr | None, default
None Name of this function which is used either on its own if neither
labelnotuidare used, or which passed as a parameterfunc_nameto either the callable or the formatting operator. See above for more details.If
nameis not specified it defaults to__qualname__expanded by the module name the function is defined in.- include_argslist[str] | None, default
None List of arguments to include in generating an unqiue ID, or
Nonefor all.- exclude_argslist[str] | None, default
None List of arguments to exclude from generating an unique ID. Examples of such non-functional arguments are workflow controls (debugging) and i/o elements.
- exclude_arg_typeslist[type | str] | None, default
None List of parameter types or names of type to exclude from generating an unique ID. Examples of such non-functional arguments are workflow controls (debugging) and i/o elements. Strings are compated to
type(arg).__name__.- in_sub_dirstr | Callable | None, default
None Allows specifying a sub-directory for the cached files, using the same formatting logic as for
label.- version_auto_classbool, default
True Whether to automaticallty add version dependencies on base classes or, for member functions, on containing classes. This is the
auto_classparameter forcdxcore.version.version().- name_of_func_name_argstr, default
"func_name" When formatting
labeloruid, by default"func_name"is used to refer to the current function name. If there is already a parameterfunc_namefor the function, an error will be raised. Use this flag to change the parameter name. Example:from cdxcore.subdir import SubDir cache = SubDir("?/temp") @cache.cache("0.1") def f( func_name, x ): pass f("test", 1)
Generates a
RuntimeErrorf@__main__: 'func_name' is a reserved keyword and used as formatting parameter name for the function name. Found it also in the function parameter list. Use 'name_of_name_arg' to change the internal parameter name used..Instead, use:
@cache.cache("0.1", x : f"{new_func_name}(): {func_name} {x}", name_of_func_name_arg="new_func_name") def f( func_name, x ): pass
- versionstr | None, default
- Returns:
- Decorated F: Callable
A decorated
Fwhose__call__implements the cached call toF.This decorator has a member
cache_infoof typecdxcore.subdir.CacheInfowhich can be used to access information on caching activity.Information available at any time after decoration:
F.cache_info.name: qualified name of the functionF.cache_info.signature: signature of the function
Additonal information available during a call to a decorated function
F, and thereafter (these proprties are not thread-safe):F.cache_info.version: unique version string reflecting all dependencies.F.cache_info.filename: unique filename used for caching logic during the last function call.F.cache_info.label: last label generated, orNone.F.cache_info.arguments: arguments parsed to create a unique call ID, orNone.
Additonal information available after a call to
F(these proprties are not thread-safe):F.cache_info.last_cached: whether the last function call returned a cached object.
The decorated
F()has additional function parameters, namely:override_cache_mode:CacheMode| None, defaultNoneAllows overriding the
CacheModetemporarily, in particular you can set it to"off".track_cached_files:cdxcore.subdir.CacheTracker| None, defaultNoneAllows passing a
cdxcore.subdir.CacheTrackerobject to keep track of all files used (loaded from or saved to). The functioncdxcore.subdir.CacheTracker.delete_cache_files()can be used to delete all files involved in caching.return_cache_uid: bool, defaultFalseIf
True, then the decorated function will return a tupleuid, resultwhereuidis the unique filename generated for this function call, and whereresultis the actual result from the function, cached or not. Thisuidis thread-safe.Usage:
from cdxcore.subdir import SubDir cache_dir = SubDir("!/.cache") @cache_dir.cache() def f(x, y): return x*y uid, xy = f( x=1, y=2, return_cache_uid=True )
This pattern is thread-safe when compared to using:
xy = f( x=1, y=2 ) uid = f.cache_info.filename
- property cache_controller: CacheController#
Returns an assigned
cdxcore.subdir.CacheController, orNone
- property cache_mode: CacheMode#
Returns the
cdxcore.subdir.CacheModeassociated with the underlying cache controller
- delete(file, raise_on_error=False, *, ext=None)[source]#
Deletes
file.This function will quietly fail if
filedoes not exist unlessraise_on_erroris set toTrue.- Parameters:
- file
filename, or list of filenames
- raise_on_errorbool, default
False If
False, do not throwKeyErrorif file does not exist or another error occurs.- extstr | None, default
None Extension, or list thereof if
fileis a list.Use
Nonefor the directory default.""to not use an automatic extension."*"to use the extension associated with the format of the directory.
- delete_all_content(delete_self=False, raise_on_error=False, *, ext=None)[source]#
Deletes all valid keys and subdirectories in this sub directory.
Does not delete files with other extensions. Use
cdxcore.subdir.SubDir.delete_everything()if the aim is to delete, well, everything.- Parameters:
- delete_self: bool
Whether to delete the directory itself as well, or only its contents. If
True, the current object will be left inNonestate.- raise_on_error: bool
Falsefor silent failure- extstr | None, default
None Extension for keys, or
Nonefor the directory’s default. Use""to match all files regardless of extension.
- delete_all_files(raise_on_error=False, *, ext=None)[source]#
Deletes all valid keys in this sub directory with the correct extension.
- Parameters:
- raise_on_errorbool
Set to
Falseto quietly ignore errors.- extstr | None, default
None Extension to be used:
Nonefor the directory default.""to not use an automatic extension."*"to use the extension associated with the format of the directory.
- delete_everything(keep_directory=True)[source]#
Deletes the entire sub directory will all contents.
WARNING: deletes all files and sub-directories, not just those with the present extension. If
keep_directoryisFalse, then the directory referred to by this object will also be deleted.In this case,
selfwill be set toNonestate.
- property existing_path: str#
Return current path, including training
'/'.existing_pathensures that the directory structure exists (or raises an exception). Usecdxcore.subdir.SubDir.path()if creation on the fly is not desired.
- exists(file, *, ext=None)[source]#
Checks whether a file exists.
- Parameters:
- file
Filename, or list of filenames.
- extstr | None, default
None Extension to be used:
Nonefor the directory default.""to not use an automatic extension."*"to use the extension associated with the format of the directory.
- Returns:
- Statusbool
If
fileis a string, returnsTrueorFalse, else it will return a list ofboolvalues.
- static expand_std_root(name)[source]#
Expands
nameby a standardized root directory.The first character of
namecan be either of:"!"returnscdxcore.subdir.SubDir.temp_dir()."."returnscdxcore.subdir.SubDir.working_dir()."~"returnscdxcore.subdir.SubDir.user_dir().
If neither of these matches the first character,
nameis returned as is.This function does not support
"?"because"?"used in the constructor represents a new directory every time it is used.This function returns a string.
- property ext: str#
Returns the common extension of the files in this directory, including leading
'.'. Resolves"*"into the extension associated with the currentcdxcore.subdir.Format.
- file_size(file, *, ext=None)[source]#
Returns the file size of a file.
See comments on
os.path.getatime()for system compatibility information.- Parameters:
- filestr
Filename, or list of filenames.
- extstr
Extension, or list thereof if
fileis an extension.Use
Nonefor the directory default.Use
""for no automatic extension.
- Returns:
- File size if
file, orNoneif an error occurred.
- File size if
- files(*, ext=None)[source]#
Returns a list of files in this subdirectory with the current extension, or the specified extension.
In other words, if the extension is “.pck”, and the files are “file1.pck”, “file2.pck”, “file3.bin” then this function will return [ “file1”, “file2” ]
If
extis:None, then the directory’s default extension will be used.""then this function will return all files in this directory."*"then the extension corresponding to the current format will be used.
This function ignores directories. Use
cdxcore.subdir.SubDir.sub_dirs()to retrieve those.
- property fmt: Format#
Returns current
cdxcore.subdir.Format.
- full_file_name(file, *, ext=None)[source]#
Returns fully qualified file name, based on a given unqualified file name (e.g. without path or extension).
- Parameters:
- filestr
Core file name without path or extension.
- extstr | None, default
None If not
None, use this extension rather thancdxcore.subdir.SubDir.ext.
- Returns:
- Filenamestr | None
Fully qualified system file name. If
selfisNone, then this function returnsNone; iffileisNonethen this function also returnsNone.
- full_temp_file_name(file=None, *, ext=None, create_directory=False)[source]#
Returns a fully qualified unique temporary file name with path and extension
The file name is generated by applying a unique hash to the current directory,
file, the current process and thread IDs, anddatetime.datetime.now().If
fileis notNoneit will be used as a label.This function returns the fully qualified file name. Use
cdxcore.subdir.SubDir.temp_file_name()to only a file name.- Parameters:
- filestr | None, default
None An optional file. If provided,
cdxcore.uniquehash.named_unique_filename48_8()is used to generate the temporary file which means that a portion offilewill head the returned temporary name.If
fileisNone,cdxcore.uniquehash.unique_hash48()is used to generate a 48 character hash.- extstr | None, default
None Extension to use, or
Nonefor the extrension ofself.
- filestr | None, default
- Returns:
- Temporary file namestr
The fully qualified file name.
- get_creation_time(file, *, ext=None)[source]#
Returns the creation time of a file.
See comments on
os.path.getctime()for system compatibility information.- Parameters:
- file
Filename, or list of filenames.
- extstr | None, default
None Extension to be used:
Nonefor the directory default.""to not use an automatic extension."*"to use the extension associated with the format of the directory.
- Returns:
- Datetime
datetime.datetime A single
datetimeiffileis a string, otherwise a list ofdatetime’s. ReturnsNoneif an error occurred.
- Datetime
- get_last_access_time(file, *, ext=None)[source]#
Returns the last access time of a file.
See comments on
os.path.getatime()for system compatibility information.- Parameters:
- file
Filename, or list of filenames.
- extstr | None, default
None Extension to be used:
Nonefor the directory default.""to not use an automatic extension."*"to use the extension associated with the format of the directory.
- Returns:
- Datetime
datetime.datetime A single
datetimeiffileis a string, otherwise a list ofdatetime’s. ReturnsNoneif an error occurred.
- Datetime
- get_last_modification_time(file, *, ext=None)[source]#
Returns the last modification time a file.
See comments on
os.path.getmtime()for system compatibility information.- Parameters:
- file
Filename, or list of filenames.
- extstr | None, default
None Extension to be used:
Nonefor the directory default.""to not use an automatic extension."*"to use the extension associated with the format of the directory.
- Returns:
- Datetime
datetime.datetime A single
datetimeiffileis a string, otherwise a list ofdatetime’s. ReturnsNoneif an error occurred.
- Datetime
- get_version(file, raise_on_error=False, *, ext=None, fmt=None)[source]#
Returns a version stored in a file.
This requires that the file has previously been saved with a version. Otherwise this function will have unpredictable results.
- Parameters:
- filestr
A filename, or a list thereof.
- raise_on_errorbool
Whether to raise an exception if accessing an existing file failed (e.g. if it is a directory). By default this function fails silently and returns the default.
- delete_wrong_versionbool, default
True If
True, and if a wrong version was found, deletefile.- extstr | None, default
None Extension overwrite, or a list thereof if
fileis a list.Set to:
Noneto use directory’s default."*"to use the extension implied byfmt.""for no extension.
- fmt
cdxcore.subdir.Format| None, defaultNone File format or
Noneto use the directory’s default. Note thatfmtcannot be a list even iffileis.
- Returns:
- versionstr
The version.
- property is_none: bool#
Whether this object is
Noneor not. For suchSubDirobject no files exists, and writing any file will fail.
- is_version(file, version=None, raise_on_error=False, *, ext=None, fmt=None, delete_wrong_version=True)[source]#
Tests the version of a file.
- Parameters:
- filestr
A filename, or a list thereof.
- versionstr
Specifies the version to compare the file’s version with.
You can use
"*"to match any version.- raise_on_errorbool
Whether to raise an exception if accessing an existing file failed (e.g. if it is a directory). By default this function fails silently and returns the default.
- delete_wrong_versionbool, default
True If
True, and if a wrong version was found, deletefile.- extstr | None, default
None Extension overwrite, or a list thereof if
fileis a list.Set to:
Noneto use directory’s default."*"to use the extension implied byfmt.""for no extension.
- fmt
cdxcore.subdir.Format| None, defaultNone File format or
Noneto use the directory’s default. Note thatfmtcannot be a list even iffileis.
- Returns:
- Statusbool
Returns
Trueonly if the file exists, has version information, and its version is equal toversion.
- items(*, ext=None, raise_on_error=False)[source]#
Dictionary-style iterable of filenames and their content.
Usage:
subdir = SubDir("!") for file, data in subdir.items(): print( file, str(data)[:100] )
- Parameters:
- extstr | None, default
None Extension or
Nonefor the directory’s current extension. Use""for all file extension.
- extstr | None, default
- Returns:
- Iterable
An iterable generator
- property path: str#
Return current path, including trailing
'/'.Note that the path may not exist yet. If existence is required, consider using
cdxcore.subdir.SubDir.existing_path().
- read(file, default=None, raise_on_error=False, *, version=None, delete_wrong_version=True, ext=None, fmt=None)[source]#
Read data from a file if the file exists, or return
default.Supports
filecontaining directory information.Supports
file(anddefault``as well as ``ext) being iterable. Examples:from cdxcore.subdir import SubDir files = ['file1', 'file2'] sd = SubDir("!/test") sd.read( files ) # both files are using default None sd.read( files, 1 ) # both files are using default '1' sd.read( files, [1,2] ) # files use defaults 1 and 2, respectively sd.read( files, [1] ) # produces error as len(keys) != len([1])
Strings are iterable but are treated as single value. Therefore:
sd.read( files, '12' ) # the default value '12' is used for both files sd.read( files, ['1','2'] ) # use defaults '1' and '2', respectively
- Parameters:
- filestr
A file name or a list thereof.
filemay contain subdirectories.- default
Default value, or default values if
fileis a list.- raise_on_errorbool, default
False Whether to raise an exception if reading an existing file failed. By default this function fails silently and returns the default.
- versionstr | None, default
None If not
None, specifies the version of the current code base.In this case, this version will be compared to the version of the file being read. If they do not match, read fails (either by returning default or throwing a
cdxcore.version.VersionErrorexception).You can specify version
"*"to accept any version. Note that this is distinct to usingNonewhich stipulates that the file should not have version information.- delete_wrong_versionbool, default
True If
True, and if a wrong version was found, delete the file.- extstr | None, default
None Extension overwrite, or a list thereof if
fileis a list.Use:
Noneto use directory’s default.'*'to use the extension implied byfmt.""to turn of extension management.
- fmt
cdxcore.subdir.Format| None, defaultNone File
cdxcore.subdir.FormatorNoneto use the directory’s default.Note:
fmtcannot be a list even iffileis.Unless
extor the SubDir’s extension is'*', changing the format does not automatically change the extension.
- Returns:
- Contenttype | list
For a single
filereturns the content of the file if successfully read, ordefaultotherwise. Iffileis a list, this function returns a list of contents.
- Raises:
- Version error
cdxcore.version.VersionError: If the file’s version did not match the
versionprovided.- Version present
cdxcore.subdir.VersionPresentError: When attempting to read a file without
versionwhich has a version this exception is raised.- I/O errors
Exception Various standard I/O errors are raisedas usual.
- Version error
- read_string(file, default=None, raise_on_error=False, *, ext=None)[source]#
Reads text from a file. Removes trailing EOLs.
Returns the read string, or a list of strings if
filewas iterable.
- static remove_bad_file_characters(file, by='default')[source]#
Replaces invalid characters in a filename using the map
by.See
cdxcore.util.fmt_filename()for documentation and further options.
- rename(source, target, *, ext=None)[source]#
Rename a file.
This function will raise an exception if not successful.
- Parameters:
- source, targetstr
Filenames.
- extstr
Extension.
Use
Nonefor the directory default.Use
""for no automatic extension.
- sub_dirs()[source]#
Retrieve a list of all sub directories.
If
selfdoes not refer to an existing directory, then this function returns an empty list.
- static temp_dir()[source]#
Return system temp directory. Short-cut to
tempfile.gettempdir().This function creates a “permanent temporary” directoy (i.e. under
/tmp/for Linux or%TEMP%for Windows). Most importantly, it is somewhat persisient: you expect it to be there after a reboot.To cater for the use case of a one-off temporary directory use
cdxcore.subdir.SubDir.temp_temp_dir().This function is called when the
!parameter is used when constructingcdxcore.subdir.SubDirobjects.- Returns:
- Pathstr
This function returns a string contains trailing
'/'.
- temp_file_name(file=None)[source]#
Returns a unique temporary file name.
The file name is generated by applying a unique hash to the current directory,
file, the current process and thread IDs, anddatetime.datetime.now().If
fileis notNoneit will be used as a label.This function returns just the file name. Use
cdxcore.subdir.SubDir.full_temp_file_name()to get a full temporary file name including path and extension.- Parameters:
- filestr | None, default
None An optional file. If provided,
cdxcore.uniquehash.named_unique_filename48_8()is used to generate the temporary file which means that a portion offilewill head the returned temporary name.If
fileisNone,cdxcore.uniquehash.unique_hash48()is used to generate a 48 character hash.
- filestr | None, default
- Returns:
- Temporary file namestr
The file name.
- static temp_temp_dir()[source]#
Returns a temporary temp directory name using
tempfile.mkdtemp()which is temporary for the current process and thread, and is not guaranteed to be persisted e.g. when the system is rebooted. Accordingly, this function will return a different directory upon every function call.This function is called when the
?/is used when constructingcdxcore.subdir.SubDirobjects.Implementation notoce:
In most cirsumstances, a temporary temp directioy is not deleted from a system upon reboot. Do not rely on regular clean ups. It is strongly recommended to clean up after usage, for example using the pattern:
from cdxcore.subdir import SubDir import shutil try: tmp_dir = SubDir.temp_temp_dir() ... finally: shutil.rmtree(tmp_dir)
- Returns:
- Pathstr
This function returns a string contains trailing
'/'.
- static user_dir()[source]#
Return current working directory. Short-cut for
os.path.expanduser()with parameter' '.This function is called when the
~/is used when constructingcdxcore.subdir.SubDirobjects.- Returns:
- Pathstr
This function returns a string contains trailing
'/'.
- static working_dir()[source]#
Return current working directory. Short-cut for
os.getcwd().This function is called when the
./is used when constructingcdxcore.subdir.SubDirobjects.- Returns:
- Pathstr
This function returns a string contains trailing
'/'.
- write(file, obj, raise_on_error=True, *, version=None, ext=None, fmt=None)[source]#
Writes an object to file.
Supports
filecontaining directories.Supports
filebeing a list. In this case, ifobjis an iterable it is considered the list of values for the elements offile. Ifobjis not iterable, it will be written into all files fromfile:from cdxcore.subdir import SubDir keys = ['file1', 'file2'] sd = SubDir("!/test") sd.write( keys, 1 ) # works, writes '1' in both files. sd.write( keys, [1,2] ) # works, writes 1 and 2, respectively sd.write( keys, "12" ) # works, writes '12' in both files sd.write( keys, [1] ) # produces error as len(keys) != len(obj)
If the current directory is
None, then the function raises anEOFErrorexception.- Parameters:
- filestr
Core filename, or list thereof.
- obj
Object to write, or list thereof if
fileis a list.- raise_on_errorbool, default ``
If
False, this function will returnFalseupon failure.- versionstr | None, default
None If not
None, specifies the version of the code which generatedobj. This version will be written to the beginning of the file.- extstr | None, default
None Extension, or list thereof if
fileis a list.Use
Noneto use directory’s default extension.Use
"*"to use the extension implied byfmt.
- fmt
cdxcore.subdir.Format| None, defaultNone File format or
Noneto use the directory’s default. Note thatfmtcannot be a list even iffileis. Note that unlessextor the SubDir’s extension is ‘*’, changing the format does not automatically change the extension used.
- Returns:
- Successbool
Boolean to indicate success if
raise_on_errorisFalse.
- write_string(file, line, raise_on_error=True, *, ext=None)[source]#
Writes a line of text into a file.
Supports
file`containing directories.Supports
file`being a list. In this case,linecan either be the same value for all file’s or a list, too.
If the current directory is
None, then the function throws an EOFError exception
- exception cdxcore.subdir.VersionPresentError[source]#
Bases:
RuntimeErrorException raised in case a file was read which had a version, but no test version was provided.
- cdxcore.subdir.VersionedCacheRoot(directory, *, ext=None, fmt=None, create_directory=False, **controller_kwargs)[source]#
Create a root directory for versioned caching on disk using
cdxcore.subdir.SubDir.cache().Usage:
In a central file, define a root directory for all caching activity:
from cdxcore.subdir import VersionedCacheRoot vroot = VersionedCacheRoot("!/cache")
Create sub-directories as suitable, for example:
vtest = vroot("test")
Use these for caching:
@vtest.cache("1.0") def f1( x=1, y=2 ): print(x,y) @vtest.cache("1.0", dps=[f1]) def f2( x=1, y=2, z=3 ): f1( x,y ) print(z)
- Parameters:
- directorystr
Name of the root directory for caching.
Using SubDir the following Short-cuts are supported:
"!/dir"createsdirin the temporary directory."~/dir"createsdirin the home directory."./dir"createsdirrelative to the current directory.
- extstr | None, default
None Extension, which will automatically be appended to file names. The default value depends on
fmt`; for ``Format.PICKLEit is “pck”.- fmt
cdxcore.subdir.Format| None, defaultNone File format; if
extis not specified, the format drives the extension, too. The defaultNonebecomesFormat.PICKLE.- create_directorybool, default
False Whether to create the directory upon creation.
- controller_kwargs: dict
Parameters passed to
cdxcore.subdir.CacheController`.Common parameters used:
exclude_arg_types: list of types or names of types to exclude when auto-generating function signatures from function arguments. An example iscdxcore.verbose.Contextwhich is used to print progress messages.max_filename_length: maximum filename length.hash_length: length used for hashes, seecdxcore.uniquehash.UniqueHash.debug_verboseset toContext.allafter importingfrom cdxcore.verbose import Contextwill turn on tracing all caching operations.
- Returns:
- Root
cdxcore.subdir.SubDir A root directory suitable for caching.
- Root