ifnone
def ifnone(
a, b
):b if a is None else a
This module has an unusually large API surface, so the symbol listing in doc(fastcore.basics) is suppressed via __pyskill_sigs__: the exported cells below assemble into a curated module docstring instead.
The staples used throughout fastai code, each replacing a common multi-line pattern with a one-liner: ifnone(a,b) is b if a is None else a (though both args are always evaluated); listify and tuplify convert anything to a list or tuple the way you’d mean it (None becomes [], a str or dict stays a single item, a generator is consumed); and basic_repr('a,b') gives a class a deterministic key=value repr with no memory address, so notebook and git diffs stay clean.
Since b if a is None else a is such a common pattern, we wrap it in a function. However, be careful, because python will evaluate both a and b when calling ifnone (which it doesn’t do if using the if version directly).
x unless it’s None, in which case raise exc(msg)
The complement of ifnone for the cases where None is not an acceptable answer: many lookups signal “not found” with None (first on an empty sequence, dict.get, a C API returning a null handle), and the caller’s next line is often if x is None: raise .... req folds that guard into the lookup expression itself.
Return the attribute attr for object o. If the attribute doesn’t exist, then return the object o instead.
In types which provide rich display functionality in Jupyter, their __repr__ is also called in order to provide a fallback text representation. Unfortunately, this includes a memory address which changes on every invocation, making it non-deterministic. This causes diffs to get messy and creates conflicts in git. To fix this, put __repr__=basic_repr() inside your class.
If you pass a list of attributes (flds) of an object, then this will generate a string with the name of each attribute and its corresponding value. The format of this string is key=value, where key is the name of the attribute, and value is the value of the attribute. For each value, attempt to use the __name__ attribute, otherwise fall back to using the value’s __repr__ when constructing the string.
Nested objects work too:
"AnotherClass(c=SomeClass(a=1, b='foo'), d='bar')"
Instance variables (but not class variables) are shown if basic_repr is called with no arguments:
"SomeClass(a=1, b='foo')"
As a shortcut for creating a __repr__ for instance variables, you can inherit from BasicRepr:
"SomeClass(a=1, b='foo')"
is_array covers numpy arrays and anything array-like, and pandas objects through iloc:
Convert o to a list
Conversion is designed to “do what you mean”, e.g:
Generators are turned into lists too:
Use match to provide a length to match:
If match is a sequence, it’s length is used:
If the listified item is not of length 1, it must be the same length as match:
tuplify is listify returning a tuple:
Test whether x is truthy; collections with >0 elements are considered True
true avoids the ambiguous truth value of arrays by using their length:
[(array(0), False),
(array(1), True),
(array([0]), True),
(array([0, 1]), True),
(1, True),
(0, False),
('', False),
(None, False)]
An object that is False and can be called, chained, and indexed
null is the single NullType instance. Any attribute, call or index on it returns null again, so a chain never raises:
tonull lets a possibly-None value take part in such a chain:
get_class builds a class whose fields default to None, with __init__, __eq__ and a basic_repr derived from them:
Dynamically create a class, optionally inheriting from sup, containing fld_names
'_t(a=1, b=3)'
Fields can be filled by keyword or by position:
Instances pickle, unannotated fields default to Any, and there is a repr:
Most often you’ll want to call mk_class, since it adds the class to your module. See mk_class for more details and examples of use (which also apply to get_class).
Create a class using get_class and add to the caller’s module
Any kwargs will be added as class attributes, and sup is an optional (tuple of) base classes.
A __init__ is provided that sets attrs for any kwargs, and for any args (matching by position to fields), along with a __repr__ which prints all attrs. The docstring is set to doc. You can pass funcs which will be added as attrs with the function names.
{}
Decorator: makes function a method of a new class nm passing parameters to mk_class
wrap_class turns the decorated function into a method of a new class, made by mk_class in the function’s module:
ignore_exceptions swallows anything raised inside the block:
Context manager to ignore exceptions
exec_local runs code in a fresh local namespace and returns one variable from it:
Curried isinstance but with args reversed
risinstance takes the types first, so it curries into a predicate, and accepts type names as strings, matched against the object’s MRO:
types can also be strings:
ver2tuple reads up to three numeric parts of a version string, treating missing parts as 0:
These are used when you need a pass-through function.
noops is the method form, taking self and returning its argument:
These lists are useful for things like padding an array or adding index column(s) to arrays.
Inf defines the following properties:
count: itertools.count()zeros: itertools.cycle([0])ones : itertools.cycle([1])nones: itertools.cycle([None])Curried versions of the comparison and arithmetic functions in Python’s operator module: lt gt le ge eq ne add sub mul truediv is_ is_not in_ mod. With two args they work like operator’s versions; with one arg they return a partial that binds it as the second argument, so lt(3) means “is less than 3” and in_(vals) means “is contained in vals”. They read especially well as cmp arguments to fastcore.test.test, e.g. test(x, valid, in_).
The remaining operators are generated from the operator module by _mk_op, so they share _oper’s behaviour. in_ is a membership test, and each operator can also be used as a partial with the collection given first:
In addition to in_, the following functions are provided matching the behavior of the equivalent versions in operator: lt gt le ge eq ne add sub mul truediv is_ is_not mod.
Similarly to in_, they also have additional functionality: if you only pass one param, they return a partial function that passes that param as the second positional parameter.
ret_true and ret_false accept any arguments and ignore them, which makes them safe defaults for predicate parameters:
ret_false is the complement:
stop is a function that raises, so it can end an iteration from inside an expression such as a lambda or a map:
Map func over seq, stopping at the first result that fails cond; handles StopIteration
gen maps func over seq and stops at the first result that fails cond, so it can take a slice of an infinite sequence:
Return batches from iterator it of size chunk_sz (or return n_chunks total)
Note that you must pass either chunk_sz, or n_chunks, but not both.
A generator is consumed as it goes, so stop inside one ends the chunks:
Arrays chunk the same way:
An empty input gives no chunks, however it is sized:
Pass pad=True and an optional pad_val to pad the last chunk:
t = list(range(10))
test_eq(chunked(t,3,pad=True), [[0,1,2], [3,4,5], [6,7,8], [9,None,None]])
test_eq(chunked(t,3,pad=True,pad_val=0), [[0,1,2], [3,4,5], [6,7,8], [9,0,0]])
test_eq(chunked(t,4,pad=True,pad_val=-1), [[0,1,2,3], [4,5,6,7], [8,9,-1,-1]])
test_eq(chunked(range(5),2,pad=True), [[0,1], [2,3], [4,None]])otherwise replaces x with y only when the test passes:
AttrDict is a dict whose keys are also attributes, so d.foo reads and writes d['foo'] (to convert a whole nested structure at once, see dict2obj in fastcore.xtras); NS is the same idea built on SimpleNamespace, adding indexing and iteration. store_attr(), called inside __init__, stores the function’s arguments as attributes of self in one line:
These functions reduce boilerplate when setting or manipulating attributes or properties of objects.
custom_dir allows you extract the __dict__ property of a class and appends the list add to it.
adict reads and writes keys as attributes, and missing keys still go through get:
Assignment works both ways too, and the keys show up in dir:
dict subclass that also provides access to keys as attrs, and has a pretty markdown repr
AttrDict will pretty print in Jupyter Notebooks:
AttrDict subclass that returns default_ for missing attrs
AttrDictDefault answers missing attributes with default_ instead of raising:
This is very similar to AttrDict, but since it starts with SimpleNamespace, it has some differences in behavior. You can use it just like SimpleNamespace:
namespace(a=1,
b={'c': 1, 'd': 2},
c={'c': 1, 'd': 2},
d={'c': 1, 'd': 2},
e={'c': 1, 'd': 2},
f={'c': 1, 'd': 2, 'e': 4, 'f': [1, 2, 3, 4, 5]})
…but you can also index it to get/set:
…and iterate t:
Backport of py3.10 get_annotations that returns globals/locals
In Python 3.10 inspect.get_annotations was added. However previous versions of Python are unable to evaluate type annotations correctly if from future import __annotations__ is used. Furthermore, all annotations are evaluated, even if only some subset are needed. get_annotations_ex provides the same functionality as inspect.get_annotations, but works on earlier versions of Python, and returns the globals and locals needed to evaluate types.
eval a type or collection of types, if needed, for annotations in py3.10+
In py3.10, or if from future import __annotations__ is used, a is a str:
__main__._T2a
| is supported for defining Union types when using eval_type even for python versions prior to 3.9:
__main__._T2a | __main__._T2b
Like typing.get_type_hints but returns {} if not allowed type
For example, type func is allowed so type_hints returns the same value as typing.get_hints:
However, class is not an allowed type, so type_hints returns {}:
This supports a wider range of situations than type_hints, by checking type() and __init__ for annotations too:
anno_ret is the return entry of annotations, or None when there is no annotation or no function:
If your return annotation is None, anno_ret will return NoneType (and not None):
If your function does not have a return type, or if you pass in None instead of a function, then anno_ret returns None:
Like inspect.signature, but a declared Parameter.empty default is kept as a default
inspect uses Parameter.empty both as its “no default” marker and as a value a function may declare as an actual default (a common sentinel idiom, e.g. fasthtml.core.add_sig_param). Plain signature() reads such a declaration back as “no default”, producing a signature that fails validation as soon as it is rebuilt, e.g. by Signature.replace. signature_ex keeps the declared default distinct, so the signature stays valid and renders as the source declared it:
The member types of a Union or X|Y annotation, otherwise t unchanged
union2tuple unpacks a Union or X|Y annotation into its member types and returns anything else unchanged:
argnames reads positional and keyword-only names from a function, or from a frame with frame=True:
Decorator which uses any parameter annotations as preprocessing functions
with_cast calls each annotation on its argument before the function runs, defaults included, and applies the return annotation to the result:
Store params named in comma-separated names from calling context into attrs in self
store_attr reads the caller’s arguments by name from its frame, so the class below needs no assignments:
In it’s most basic form, you can use store_attr to shorten code like this:
…to this:
This class behaves as if we’d used the first form:
The __init__ parameters of o that it holds as attributes, with their current values
init_args reads an object’s constructor arguments back from the attributes it stored, which is what a class using store_attr holds. Class attributes and methods that share a parameter’s name are left out. Use it to display or log how an object was made:
Since you normally want to use the first argument (often called self) for storing attributes, it’s optional:
With cast=True any parameter annotations will be used as preprocessing functions for the corresponding arguments:
You can inherit from a class using store_attr, and just call it again to add in any new attributes added in the derived class:
You can skip passing a list of attrs to store. In this case, all arguments passed to the method are stored:
You can skip some attrs by passing but:
You can also pass keywords to store_attr, which is identical to setting the attrs directly:
You can also use store_attr inside functions.
Dict from each k in ks to getattr(o,k)
attrdict picks named attributes into a dict, with default for any that are missing:
properties turns the named methods of cls into properties in place:
The case-convention functions below share one splitter. id_words segments an identifier into its words and never changes case: punctuation characters in splits are treated as separators, and the letter c enables splitting at case boundaries, including after acronym runs. Constrain splits when a convention gives characters different meanings, such as CSS pseudo-selectors where : must not split. Separator runs come back as empty words, so names like __init__ survive a round trip.
Split identifier s into words: punctuation chars in splits are separators (runs kept as empty words, so they survive a round trip), ‘c’ splits case boundaries
test_eq(id_words('beforeRequest'), ['before','Request'])
test_eq(id_words('validation:validate'), ['validation','validate'])
test_eq(id_words('HTMLElement'), ['HTML','Element'])
test_eq(id_words('HX-Request-Type'), ['HX','Request','Type'])
test_eq(id_words('a__b'), ['a','','b'])
test_eq(id_words('a-b_c', 'c'), ['a-b_c'])
id_words('parseHTMLTree')Each to_* emitter owns its casing policy: to_camel keeps acronym words intact (so an already-camel name round-trips exactly, which HtmxOn-style consumers rely on), to_pascal Title-cases every word (the historic snake2camel output), and to_kebab/to_snake lowercase throughout.
snake_case form of s
PascalCase form of s; every word Title-cased (acronyms flatten)
camelCase form of s; acronym words after the first keep their casing
test_eq(to_camel('before-request'), 'beforeRequest')
test_eq(to_camel('parseHTMLTree'), 'parseHTMLTree')
test_eq(to_pascal('a_b_cc'), 'ABCc')
test_eq(to_pascal('parseHTMLTree'), 'ParseHtmlTree')
test_eq(to_kebab('beforeRequest'), 'before-request')
test_eq(to_kebab('noSSESourceError'), 'no-sse-source-error')
test_eq(to_snake('HX-Request-Type'), 'hx_request_type')
test_eq(to_snake('__init__'), '__init__')
test_eq(to_kebab('a__b'), 'a--b')
to_camel('no-sse-source-error'), to_kebab('validation:validate')camel2words splits on case changes only, so hyphens and underscores stay as they are:
camel2snake is to_snake splitting on case changes only:
snake2camel is to_pascal splitting on underscores only, so the first letter is capitalised too:
humanize scales by thousands up to T, keeps one decimal, and drops a trailing .0:
Return the snake-cased name of the class; strip ending cls_name if it exists.
class2attr snake-cases the class name, dropping cls_name when it is the suffix, which suits naming an attribute after a subclass:
A trailing Parent is dropped and the rest snake-cased, while a leading one stays:
getcallable returns noop when the attribute is missing, so the result can always be called:
getattrs reads several attributes at once, in order:
hasattrs is hasattr over a sequence of names:
Set fields flds on dest from src, a dict or an object
setattrs copies the comma-separated fields flds from src, a dict or an object, onto dest:
try_attrs returns the first attribute found, and raises AttributeError naming all of them when none is:
Property decorator with dependency update triggering
DepProp is a descriptor that stores a value and calls a “change” function whenever that value changes or is deleted. This is useful for invalidating caches or triggering side effects when a dependency is updated. An optional normalizer can preprocess values before storage.
Use the .norm decorator to add a normalizer that preprocesses values before storage:
Setting the same value again does not trigger the change function:
Deleting the property removes the backing attribute and calls fchange:
Inherit from GetAttr to have attr access passed down to an instance attribute. This makes it easy to create composites that don’t require callers to know about their components. For a more detailed discussion of how this works as well as relevant context, we suggest reading the delegated composition section of this blog article.
You can customise the behaviour of GetAttr in subclasses via; - _default - By default, this is set to 'default', so attr access is passed down to self.default - _default can be set to the name of any instance attribute that does not start with dunder __ - _xtra - By default, this is None, so all attr access is passed down - You can limit which attrs get passed down by setting _xtra to a list of attribute names
Inherit from this to have all attr accesses in self._xtra passed down to self.default
To illuminate the utility of GetAttr, suppose we have the following two classes, _WebPage which is a superclass of _ProductPage, which we wish to compose like so:
How do we make it so we can just write p.author, instead of p.page.author to access the author attribute? We can use GetAttr, of course! First, we subclass GetAttr when defining _ProductPage. Next, we set self.default to the object whose attributes we want to be able to access directly, which in this case is the page argument passed on initialization:
Now, we can access the author attribute directly from the instance:
If you wish to store the object you are composing in an attribute other than self.default, you can set the class attribute _data as shown below. This is useful in the case where you might have a name collision with self.default:
By default, all attributes and methods of the object you are composing are retained. In the below example, we compose a str object with the class _C. This allows us to directly call string methods on instances of class _C, such as str.lower() or str.upper():
However, you can choose which attributes or methods to retain by defining a class attribute _xtra, which is a list of allowed attribute and method names to delegate. In the below example, we only delegate the lower method from the composed str object when defining class _C:
You must be careful to properly set an instance attribute in __init__ that corresponds to the class attribute _default. The below example sets the class attribute _default to data, but erroneously fails to define self.data (and instead defines self.default).
Failing to properly set instance attributes leads to errors when you try to access methods directly:
Use in __getattr__ to delegate to attr to without inheriting from GetAttr
delegate_attr is a functional way to delegate attributes, and is an alternative to GetAttr. We recommend reading the documentation of GetAttr for more details around delegation.
You can use achieve delegation when you define __getattr__ by using delegate_attr:
ShowPrint is a base class that defines a show method, which is used primarily for callbacks in fastai that expect this method to be defined.
Int, Float, and Str extend int, float and str respectively by adding an additional show method by inheriting from ShowPrint.
The code for Int is shown below:
Examples:
Functions that manipulate popular python collections.
Partition a dict by a predicate that takes key/value params
partition_dict returns the matching pairs first, then the rest, keeping each dict’s order:
flatten recurses into nested collections, leaving strings whole, and yields a flat stream. concat collects it into a list:
strcat stringifies each item before joining:
detuplify unwraps a single item, gives None for an empty tuple, and leaves longer tuples and multi-dimensional arrays alone:
replicate repeats item to the length of match:
setify accepts None, a string, which is kept whole, or any iterable:
merge combines dicts left to right, with later keys winning, and skips None:
Like itertools.groupby but doesn’t need to be sorted, and isn’t lazy, plus some extensions
The result is a dict from key to list of values, in first-seen order:
You can use an int as key or val (which uses itemgetter; passing a str will use attrgetter), eg:
…and you can use a tuple as key or val (which creates a tuple from the provided keys or vals), eg:
Here’s an example of how to invert a grouping, and using a val function:
{1: [0], 3: [0, 2], 7: [0], 5: [3, 7], 8: [4], 4: [5]}
Finds the last index of occurence of x in o (returns -1 if no occurence)
last_index searches from the end and gives -1 when x is absent:
filter_dict, filter_keys and filter_values differ only in what the predicate sees:
{65: 'A', 66: 'B', 67: 'C', 68: 'D', 69: 'E', 70: 'F', 71: 'G', 72: 'H'}
filter_keys passes only the key:
filter_values passes only the value:
cycle never stops, and an empty input cycles None rather than raising:
Like itertools.zip_longest but cycles through elements of all but first argument
zip_cycle runs to the length of the first argument, repeating the others as needed:
Like sorted, but if key is str use attrgetter; if int use itemgetter; use cmp comparator function or key with kwargs
Attributes can be used for sorting by passing their name as a string:
Tuple/list items can be sorted by index position:
A custom key function transforms values:
You can use a comparison function (returning -1/1/0):
Additional parameters can be passed to key/cmp functions:
Reverse sort capability:
not_ wraps a predicate so it answers the opposite:
Like filter_ex, but return indices for matching items
argwhere gives the positions of matching items, with the same negate and kwargs handling as filter_ex:
filter_ex passes kwargs through to f, and negate inverts the test:
All indices of collection a, if a is a collection, otherwise range
range_of gives the indices of a collection, or behaves as range when given numbers:
Same as enumerate, but returns index as 2nd element instead of 1st
renumerate is enumerate with the item first and its index second:
First element of x, optionally filtered by f, or None if missing
first takes any iterable and returns None when nothing qualifies, so it never raises:
Last element of x, optionally filtered by f, or None if missing
last walks the whole iterable, so it works on generators too:
only insists on exactly one item, and its error says whether there were none or several:
Same as getattr, but if attr includes a ., then looks inside nested objects
nested_attr follows a dotted path through attributes or keys, returning default on the first miss:
class CustomIndexable:
def __init__(self): self.data = dict(a=1, b='v', c={'d':5})
def __getitem__(self, key): return self.data[key]
custom_indexable = CustomIndexable()
test_eq(nested_attr(custom_indexable,'a'),1)
test_eq(nested_attr(custom_indexable,'c.d'),5)
test_eq(nested_attr(custom_indexable,'e'),None)class TestObj: def init(self): self.nested = {‘key’: [1, 2, {‘inner’: ‘value’}]} test_obj = TestObj()
test_eq(nested_attr(test_obj, ‘nested.key.2.inner’),‘value’) test_eq(nested_attr([1, 2, 3], ‘1’),2)
Same as setdefault, but if attr includes a ., then looks inside nested objects
nested_setdefault creates each missing level as an empty container of the same type as o:
Same as nested_attr but if not found will return noop
nested_callable is nested_attr defaulting to noop, so the result can always be called:
Index into nested collections, dicts, etc, with idxs
nested_idx walks idxs through nested dicts, lists and objects, returning None for a missing step:
set_nested_idx assigns at the same kind of path:
val2idx inverts a sequence into a value-to-position dict:
Unique elements in x, optional sort, optional return reverse correspondence, optional prepend with elements.
uniqueify keeps first occurrences in order. sort sorts them, start prepends items, and bidir also returns the value-to-index dict:
t = [1,1,0,5,0,3]
test_eq(uniqueify(t),[1,0,5,3])
test_eq(uniqueify(t, sort=True),[0,1,3,5])
test_eq(uniqueify(t, start=[7,8,6]), [7,8,6,1,0,5,3])
v,o = uniqueify(t, bidir=True)
test_eq(v,[1,0,5,3])
test_eq(o,{1:0, 0: 1, 5: 2, 3: 3})
v,o = uniqueify(t, sort=True, bidir=True)
test_eq(v,[0,1,3,5])
test_eq(o,{0:0, 1: 1, 3: 2, 5: 3})Iterate and generate a tuple with a flag for first and last value.
loop_first_last yields (is_first, is_last, value), which saves a length check when rendering sequences:
Iterate and generate a tuple with a flag for first value.
loop_first keeps just the first flag:
loop_last keeps just the last flag:
Index of the first element of lst matching predicate f, or default if none
first_match returns the index of the first match, not the element:
Index of the last element of lst matching predicate f, or default if none
last_match searches from the end:
Plain str.join needs strings, so ','.join([1,2,3]) raises a TypeError. joins maps str over the items first:
A tuple with extended functionality.
fastuple takes its items as separate arguments, and every arithmetic and comparison operator in num_methods is applied elementwise, cycling shorter arguments:
A tuple with elementwise ops and more friendly init behavior
Common failure modes when trying to initialize a tuple in python:
or
However, fastuple allows you to define tuples like this and in the usual way:
mul scales elementwise, by another tuple or by a scalar:
* is already defined in tuple for replicating, so use mul instead
Additionally, the following elementwise operations are available: - le: less than or equal - eq: equal - gt: greater than - min: minimum of
You can also do other elementwise operations like negate a fastuple, or subtract two fastuples:
Tools for making and transforming functions: compose(f,g,...) chains functions left to right; bind is partial extended with arg0,arg1,… placeholders for reordering positional arguments; and fail_clean re-raises exceptions with the library’s own traceback frames stripped, for errors that are part of a function’s contract rather than bugs.
Utilities for functional programming or for defining, modifying, or debugging functions.
bind is the same as partial, but also allows you to reorder positional arguments using variable name(s) arg{i} where i refers to the zero-indexed positional argument. bind as implemented currently only supports reordering of up to the first 5 positional arguments.
Consider the function myfunc below, which has 3 positional arguments. These arguments can be referenced as arg0, arg1, and arg1, respectively.
Same as partial, except you can use arg0 arg1 etc param placeholders
In the below example we bind the positional arguments of myfn as follows:
14, referenced by arg1, is substituted for the first positional argument.17 for the second positional argument.19, referenced by arg0, is subsituted for the third positional argument.In this next example:
17 for the first positional argument.19 refrenced by arg0, becomes the second positional argument.14 becomes the third positional argument.e to 3.This is an example of using bind like partial and do not reorder any arguments:
bind can also be used to change default values. In the below example, we use the first input 3 to override the default value of the named argument e, and supply default values for the first three positional arguments:
Every arg{i} placeholder refers to the i-th call-time argument, in positional and keyword bindings alike; arguments past the highest placeholder index are appended:
mapt is map returning a tuple:
Like map, but use bind, and supports str and indexing
map_ex returns a list by default, and f may be a callable, a format string, or anything indexable:
If f is a string then it is treated as a format string to create the mapping:
If f is a dictionary (or anything supporting __getitem__) then it is indexed to create the mapping:
You can also pass the same arg params that bind accepts:
Create a function that composes all functions in funcs, passing along remaining *args and **kwargs to all
compose applies funcs left to right, threading the extra arguments into each call, and order sorts them by that attribute first:
maps composes all but the last argument and maps the result over the last, with retain deciding how each output relates to its input:
Like functools.partial but also copies over docstring
partialler is partial plus an order attribute, copied from f unless given, and it keeps f’s docstring:
Keyword arguments and order can be given too, and the docstring comes across:
class partial0:
"Like `partialler`, but args passed to callable are inserted at started, instead of at end"
def __init__(self, f, *args, order=None, **kwargs):
self.f,self.args,self.kwargs = f,args,kwargs
self.order = ifnone(order, getattr(f,'order',None))
self.__doc__ = f.__doc__
def __call__(self, *args, **kwargs): return self.f(*args, *self.args, **kwargs, **self.kwargs)partial0 puts the call-time argument first, so f(3) is _f(3, 2), unlike the partialler example above:
instantiate calls a type and leaves an instance alone:
Construct a function which applies f to the argument’s attribute attr
using_attr lifts f to act on an attribute of its argument:
negate also rewrites the docstring to say what it negates:
Returns `not true(...)`
Original: Returns True
Re-raise excs (default: Exception) without internal traceback frames
fail_clean marks a boundary where errors are part of a function’s contract rather than something to debug: exceptions of the listed types (any Exception by default) are re-raised with the internal traceback frames removed, so the caller sees the message and their own call site instead of the library’s plumbing. The original exception object is preserved, including its attributes. Exceptions not listed keep their full stack for debugging. Use @fail_clean bare, or pass exception types like @fail_clean(ValueError):
The traceback is cut down to the caller and the wrapper, with the internal frames gone.
dstar wraps a function to accept a single dictionary, unpacking it as keyword arguments (the ** counterpart of star in fastcore.foundation). For instance:
['Hello, Alice!', 'Hi, Bob!']
A more realistic example showing API request configuration. Each request dictionary may have different keys present, and dspread handles this naturally (missing keys use the function’s defaults):
# chkstyle: skip
def api_request(endpoint, method='GET', timeout=30, headers=None):
return f"{method} {endpoint} (timeout={timeout})"
requests = [
{'endpoint': '/users', 'method': 'POST', 'timeout': 60},
{'endpoint': '/data'},
{'endpoint': '/health', 'method': 'HEAD', 'timeout': 5}
]
list(map(dstar(api_request), requests))['POST /users (timeout=60)',
'GET /data (timeout=30)',
'HEAD /health (timeout=5)']
A Concise Way To Create Lambdas
_all_ adds Self to __all__, since it is made by instantiating _SelfCls rather than defined with def or class:
~Self is a concise alternative to lambda for a function that operates on a single object (note the capitalization!). Write the chain of attribute accesses, method calls, and indexing just as you would after a variable name, with ~Self in its place, and the result is a plain function that runs the chain on its argument:
~Self.sum() is lambda o: o.sum()~Self.imag is lambda o: o.imag~Self[1] is lambda o: o[1]~Self.sum().real is lambda o: o.sum().real~Self alone is the identity, lambda o: oSince ., (), and [] bind tighter than ~, the whole chain builds first and ~ then converts it to a function, so the chain never needs its own parentheses: map(~Self.imag, nums) works as written.
The functions ~Self returns are ordinary functions: safe to introspect, and independent of any later chains built from the same prefix. Parens mean what they mean in plain Python: a step written with () is called, so a chain that calls a non-callable attribute raises TypeError rather than quietly fetching it:
Self.imag reads an attribute and Self.imag() calls it, as in plain Python, so calling a non-callable attribute fails with the usual TypeError.
Calling Self directly adds a call step to the chain, so ~Self(1,b=2) is a function which calls whatever it’s applied to with those arguments:
@patch adds a function to an existing class as a method, using the function’s self: type annotation to pick the class (a union annotation patches several classes at once); @patch_to(Cls) is the same with the class passed explicitly. Both take as_prop, set_prop, and cls_method. fastai code uses this to build classes incrementally across a notebook, so expect to find a class’s methods defined far from the class itself:
Copy a non-builtin function (NB copy.copy does not work for this)
Sometimes it may be desirable to make a copy of a function that doesn’t point to the original object. When you use Python’s built in copy.copy or copy.deepcopy to copy a function, you get a reference to the original object:
copy.copy and copy.deepcopy both return the same function object, so an attribute set on one shows up on the other.
However, with copy_func, you can retrieve a copy of a function without a reference to the original object:
Decorator: add f to cls
The @patch_to decorator allows you to monkey patch a function into a class as a method:
You can access instance properties in the usual way via self:
You can instead specify that the method should be a class method by setting cls_method=True:
Additionally you can specify that the function you want to patch should be a class attribute with as_prop=True:
Once you have a property, you can assign a setter with set_prop=True:
Instead of passing one class to the @patch_to decorator, you can pass multiple classes in a tuple to simulteanously patch more than one class with the same method:
You can also rename the function in the patched class:
Decorator: add f to the first parameter’s class (based on f’s type annotations)
patch finds the class from the first parameter’s annotation, and cls_method=True reads it from cls instead:
@patch is an alternative to @patch_to that allows you similarly monkey patch class(es) by using type annotations:
Similarly to patch_to, you can supply a union of classes instead of a single class in your type annotations to patch multiple classes:
Just like patch_to decorator you can use as_prop, set_prop, and cls_method parameters with patch decorator:
nm renames the patched method, as with patch_to:
Patching classmethod shouldn’t affect how python’s inheritance works
It also works on iterable classes like Enums:
Add new member n with value v to enum class cls at runtime
extend_enum mutates an existing enum class by constructing a new member, registering it in the enum’s internal lookup tables, and attaching it as a class attribute, so it behaves like a normal enum member created in the original class definition.
(<Color.green: 3>, <Color.green: 3>, <Color.green: 3>)
compile_re lets None mean no pattern:
imports() injects the members into the caller’s namespace, so they can be used as bare names:
StrEnum members are strings, and print as their names:
str_enum makes a StrEnum whose values equal their names, registered in the caller’s module so that it pickles:
ValEnum prints the value rather than the name:
a A
Stateful keeps anything in self._state out of pickles, so unpicklable resources can be recreated on load:
A base class/mixin for objects that should not serialize all their state
After a pickle round trip, _state is empty while ordinary attributes survive:
Override _init_state to do any necessary setup steps that are required during __init__ or during deserialization (e.g. pickle.load). Here’s an example of how Stateful simplifies the official Python example for Handling Stateful Objects.
class TextReader(Stateful): # chkstyle: ignore
'Print and number lines in a text file.'
_stateattrs=('file',)
def __init__(self, filename):
self.filename,self.lineno = filename,0
super().__init__()
def readline(self):
self.lineno += 1
line = self.file.readline()
if line: return f"{self.lineno}: {line.strip()}"
def _init_state(self):
self.file = open(self.filename)
for _ in range(self.lineno): self.file.readline()1: {
2: "cells": [
3: {
NotStr forwards string methods through GetAttr while failing isinstance(s, str), for places that treat real strings specially:
Allow strings with special characters to render properly in Jupyter. Without calling print() strings with special characters are displayed like so:
Little hack to get strings to show properly in Jupyter.
'a string\nwith\nnew\nlines and\ttabs'
We can correct this with PrettyString:
Build log-stepped array from start to stop in n steps.
even_mults spaces n values so each is the same multiple of the one before:
num_cpus respects the process’s CPU affinity where the platform reports it, and sets defaults.cpus:
Create properties passing each of range(n) to f
add_props builds n properties in one go, each getter called with its index, with an optional setter:
Reading goes through the getter and assignment through the setter:
Case-insensitive convert string s too a bool (y,yes,t,true,on,1->True)
True values are ‘y’, ‘yes’, ‘t’, ‘true’, ‘on’, and ‘1’; false values are ‘n’, ‘no’, ‘f’, ‘false’, ‘off’, and ‘0’. Raises ValueError if ‘val’ is anything else.
str2int treats an empty string and none as 0, and on and off as 1 and 0:
str2float treats an empty string as 0.0:
str2list parses a Python list literal, adding the brackets if they are missing, and gives [] for an empty string:
str2date parses ISO dates and returns None for an empty string:
datetime.fromisoformat with Z suffix and empty string handling
str2dt also accepts a trailing Z for UTC:
The to_* functions apply the str2* parsers to strings and the plain constructors to anything else. type_map is what typed uses to cast:
Decorator to check param and return types at runtime, with optional casting
typed validates argument types at runtime. This is in contrast to MyPy which only offers static type checking.
For example, a TypeError will be raised if we try to pass an integer into the first argument of the below function:
You can have automatic casting based on heuristics by specifying typed(cast=True). If casting is not possible, a TypeError is raised.
A float is truncated to an int, and a string is stripped and parsed.
We can also optionally allow multiple types by enumarating the types in a tuple as illustrated below:
We currently do not support union types when casting.
typed works with classes, too:
It also works with custom types.
exec_new runs code in a fresh globals dict that carries the current package, so relative imports work, and returns that dict:
exec_import is exec_new for one import, giving a namespace with sym in it:
Copy of sig with removed params dropped and updates added, kind-sorted
sig_with_params lets you modify a function signature by adding, replacing, or removing parameters. This is useful when creating wrapper functions or decorators that need to adjust the signature of the wrapped function.
You can remove parameters by name:
You can also add new parameters:
The result is kind-sorted (kindsort: a stable sort on Parameter.kind, Python’s own ordering rule), so composing groups of params can never produce an illegal signature: a collector in sig stays last however many params are added after it:
A signature that is already in kind order comes back unchanged.
This is a simplified version of fastcore.meta.delegates that supports only regular functions.
Python’s json.dumps can handle custom objects through a default callback, but it does not look for serialization methods on the objects themselves. Therefore even a class is not normally serializable:
xdumps recognizes __json__ and serializes the value it returns. The protocol is applied recursively, so custom objects can appear inside ordinary lists and dictionaries:
xdumps also supports default like dumps does:
Some standard library types cannot implement __json__, since builtin types cannot gain methods, so xdumps handles the common ones directly: datetimes, dates and times become ISO8601 strings, UUID and Path become strings, and enums become their values. An object’s own __json__ still comes first, and default remains the escape hatch for anything else:
revive_dates is the inverse for the datetime case: it walks a decoded JSON tree and converts any string in ISO8601 form (Z suffix included) back into a datetime. Conversion is by shape, so a string that merely looks like a timestamp converts too - apply it to trees where date strings can only be dates, such as message headers, rather than to arbitrary user content:
Recursively convert ISO8601-formatted strings in a decoded JSON tree into datetime objects
in_jupyter and in_notebook tell a notebook front end apart from a plain IPython shell:
These variables are available as booleans in fastcore.basics as IN_IPYTHON, IN_JUPYTER, IN_COLAB and IN_NOTEBOOK.