<project title="fastcore">
fastcore adds to Python features inspired by other languages, like multiple dispatch from Julia, mixins from Ruby, and currying, binding, and more from Haskell. It also adds some “missing features” and clean up some rough edges in the Python standard library, such as simplifying parallel processing, and bringing ideas from NumPy over to Python’s list type.

Here are some tips on using fastcore:

- **Liberal imports**: Utilize `from fastcore.module import *` freely. The library is designed for safe wildcard imports.
- **Enhanced list operations**: Substitute `list` with `L`. This provides advanced indexing, method chaining, and additional functionality while maintaining list-like behavior.
- **Extend existing classes**: Apply the `@patch` decorator to add methods to classes, including built-ins, without subclassing. This enables more flexible code organization.
- **Streamline class initialization**: In `__init__` methods, use `store_attr()` to efficiently set multiple attributes, reducing repetitive assignment code.
- **Explicit keyword arguments**: Apply the `delegates` decorator to functions to replace `**kwargs` with specific parameters, enhancing IDE support and documentation.
- **Optimize parallel execution**: Leverage fastcore's enhanced `ThreadPoolExecutor` and `ProcessPoolExecutor` for simplified concurrent processing.
- **Expressive testing**: Prefer fastcore's testing functions like `test_eq`, `test_ne`, `test_close` for more readable and informative test assertions.
- **Advanced file operations**: Use the extended `Path` class, which adds methods like `ls()`, `read_json()`, and others to `pathlib.Path`.
- **Flexible data structures**: Convert between dictionaries and attribute-access objects using `dict2obj` and `obj2dict` for more intuitive data handling.
- **Data pipeline construction**: Employ `Transform` and `Pipeline` classes to create modular, composable data processing workflows.
- **Functional programming paradigms**: Utilize tools like `compose`, `maps`, and `filter_ex` to write more functional-style Python code.
- **Documentation**: Use `docments` where possible to document parameters of functions and methods.
- **Time-aware caching**: Apply the `timed_cache` decorator to add time-based expiration to the standard `lru_cache` functionality.
- **Simplified CLI creation**: Use fastcore's console script utilities to easily transform Python functions into command-line interfaces.
  <tutorials>
    <doc title="Fastcore Quick Tour" desc="A quick tour of a few higlights from fastcore."># A tour of fastcore



Here’s a (somewhat) quick tour of a few higlights from fastcore.

### Documentation

All fast.ai projects, including this one, are built with
[nbdev](https://nbdev.fast.ai), which is a full literate programming
environment built on Jupyter Notebooks. That means that every piece of
documentation, including the page you’re reading now, can be accessed as
interactive Jupyter notebooks. In fact, you can even grab a link
directly to a notebook running interactively on Google Colab - if you
want to follow along with this tour, click the link below:

``` python
colab_link('index')
```

[Open `index` in
Colab](https://colab.research.google.com/github/fastai/fastcore/blob/master/nbs/index.ipynb)

The full docs are available at
[fastcore.fast.ai](https://fastcore.fast.ai). The code in the examples
and in all fast.ai libraries follow the [fast.ai style
guide](https://docs.fast.ai/dev/style.html). In order to support
interactive programming, all fast.ai libraries are designed to allow for
`import *` to be used safely, particular by ensuring that
[`__all__`](https://riptutorial.com/python/example/2894/the---all---special-variable)
is defined in all packages. In order to see where a function is from,
just type it:

``` python
coll_repr
```

    <function fastcore.foundation.coll_repr(c, max_n=10)>

For more details, including a link to the full documentation and source
code, use `doc`, which pops up a window with this information:

``` python
doc(coll_repr)
```

<img src="images/att_00000.png" width="499" />

The documentation also contains links to any related functions or
classes, which appear like this:
[`coll_repr`](https://fastcore.fast.ai/foundation.html#coll_repr) (in
the notebook itself you will just see a word with back-ticks around it;
the links are auto-generated in the documentation site). The
documentation will generally show one or more examples of use, along
with any background context necessary to understand them. As you’ll see,
the examples for each function and method are shown as tests, rather
than example outputs, so let’s start by explaining that.

### Testing

fastcore’s testing module is designed to work well with
[nbdev](https://nbdev.fast.ai), which is a full literate programming
environment built on Jupyter Notebooks. That means that your tests,
docs, and code all live together in the same notebook. fastcore and
nbdev’s approach to testing starts with the premise that all your tests
should pass. If one fails, no more tests in a notebook are run.

Tests look like this:

``` python
test_eq(coll_repr(range(1000), 5), '(#1000) [0,1,2,3,4...]')
```

That’s an example from the docs for
[`coll_repr`](https://fastcore.fast.ai/foundation.html#coll_repr). As
you see, it’s not showing you the output directly. Here’s what that
would look like:

``` python
coll_repr(range(1000), 5)
```

    '(#1000) [0,1,2,3,4...]'

So, the test is actually showing you what the output looks like, because
if the function call didn’t return `'(#1000) [0,1,2,3,4...]'`, then the
test would have failed.

So every test shown in the docs is also showing you the behavior of the
library — and vice versa!

Test functions always start with `test_`, and then follow with the
operation being tested. So
[`test_eq`](https://fastcore.fast.ai/test.html#test_eq) tests for
equality (as you saw in the example above). This includes tests for
equality of arrays and tensors, lists and generators, and many more:

``` python
test_eq([0,1,2,3], np.arange(4))
```

When a test fails, it prints out information about what was expected:

``` python
test_eq([0,1,2,3], np.arange(3))
```

    ----
      AssertionError: ==:
      [0, 1, 2, 3]
      [0 1 2]

If you want to check that objects are the same type, rather than the
just contain the same collection, use
[`test_eq_type`](https://fastcore.fast.ai/test.html#test_eq_type).

You can test with any comparison function using
[`test`](https://fastcore.fast.ai/test.html#test), e.g test whether an
object is less than:

``` python
test(2, 3, operator.lt)
```

You can even test that exceptions are raised:

``` python
def divide_zero(): return 1/0
test_fail(divide_zero)
```

…and test that things are printed to stdout:

``` python
test_stdout(lambda: print('hi'), 'hi')
```

### Foundations

fast.ai is unusual in that we often use
[mixins](https://en.wikipedia.org/wiki/Mixin) in our code. Mixins are
widely used in many programming languages, such as Ruby, but not so much
in Python. We use mixins to attach new behavior to existing libraries,
or to allow modules to add new behavior to our own classes, such as in
extension modules. One useful example of a mixin we define is
[`Path.ls`](https://fastcore.fast.ai/xtras.html#path.ls), which lists a
directory and returns an
[`L`](https://fastcore.fast.ai/foundation.html#l) (an extended list
class which we’ll discuss shortly):

``` python
p = Path('images')
p.ls()
```

    (#6) [Path('images/mnist3.png'),Path('images/att_00000.png'),Path('images/puppy.jpg'),Path('images/att_00005.png'),Path('images/att_00007.png'),Path('images/att_00006.png')]

You can easily add you own mixins with the
[`patch`](https://fastcore.fast.ai/basics.html#patch)
[decorator](https://realpython.com/primer-on-python-decorators/), which
takes advantage of Python 3 [function
annotations](https://www.python.org/dev/peps/pep-3107/#parameters) to
say what class to patch:

``` python
@patch
def num_items(self:Path): return len(self.ls())

p.num_items()
```

    6

We also use `**kwargs` frequently. In python `**kwargs` in a parameter
like means “*put any additional keyword arguments into a dict called
`kwargs`*”. Normally, using `kwargs` makes an API quite difficult to
work with, because it breaks things like tab-completion and popup lists
of signatures. `utils` provides
[`use_kwargs`](https://fastcore.fast.ai/meta.html#use_kwargs) and
[`delegates`](https://fastcore.fast.ai/meta.html#delegates) to avoid
this problem. See our [detailed article on
delegation](https://www.fast.ai/2019/08/06/delegation/) on this topic.

[`GetAttr`](https://fastcore.fast.ai/basics.html#getattr) solves a
similar problem (and is also discussed in the article linked above):
it’s allows you to use Python’s exceptionally useful
[`__getattr__`](https://fastcore.fast.ai/xml.html#__getattr__) magic
method, but avoids the problem that normally in Python tab-completion
and docs break when using this. For instance, you can see here that
Python’s `dir` function, which is used to find the attributes of a
python object, finds everything inside the `self.default` attribute
here:

``` python
class Author:
    def __init__(self, name): self.name = name

class ProductPage(GetAttr):
    _default = 'author'
    def __init__(self,author,price,cost): self.author,self.price,self.cost = author,price,cost

p = ProductPage(Author("Jeremy"), 1.50, 0.50)
[o for o in dir(p) if not o.startswith('_')]
```

    ['author', 'cost', 'name', 'price']

Looking at that `ProductPage` example, it’s rather verbose and
duplicates a lot of attribute names, which can lead to bugs later if you
change them only in one place. `fastcore` provides
[`store_attr`](https://fastcore.fast.ai/basics.html#store_attr) to
simplify this common pattern. It also provides
[`basic_repr`](https://fastcore.fast.ai/basics.html#basic_repr) to give
simple objects a useful `repr`:

``` python
class ProductPage:
    def __init__(self,author,price,cost): store_attr()
    __repr__ = basic_repr('author,price,cost')

ProductPage("Jeremy", 1.50, 0.50)
```

    __main__.ProductPage(author='Jeremy', price=1.5, cost=0.5)

One of the most interesting `fastcore` functions is the
[`funcs_kwargs`](https://fastcore.fast.ai/meta.html#funcs_kwargs)
decorator. This allows class behavior to be modified without
sub-classing. This can allow folks that aren’t familiar with
object-oriented programming to customize your class more easily. Here’s
an example of a class that uses
[`funcs_kwargs`](https://fastcore.fast.ai/meta.html#funcs_kwargs):

``` python
@funcs_kwargs
class T:
    _methods=['some_method']
    def __init__(self, **kwargs): assert not kwargs, f'Passed unknown args: {kwargs}'

p = T(some_method = print)
p.some_method("hello")
```

    hello

The `assert not kwargs` above is used to ensure that the user doesn’t
pass an unknown parameter (i.e one that’s not in `_methods`). `fastai`
uses [`funcs_kwargs`](https://fastcore.fast.ai/meta.html#funcs_kwargs)
in many places, for instance, you can customize any part of a
`DataLoader` by passing your own methods.

`fastcore` also provides many utility functions that make a Python
programmer’s life easier, in `fastcore.utils`. We won’t look at many
here, since you can easily look at the docs yourself. To get you
started, have a look at the docs for
[`chunked`](https://fastcore.fast.ai/basics.html#chunked) (remember, if
you’re in a notebook, type `doc(chunked)`), which is a handy function
for creating lazily generated batches from a collection.

Python’s
[`ProcessPoolExecutor`](https://fastcore.fast.ai/parallel.html#processpoolexecutor)
is extended to allow `max_workers` to be set to `0`, to easily turn off
parallel processing. This makes it easy to debug your code in serial,
then run it in parallel. It also allows you to pass arguments to your
parallel function, and to ensure there’s a pause between calls, in case
the process you are running has race conditions.
[`parallel`](https://fastcore.fast.ai/parallel.html#parallel) makes
parallel processing even easier to use, and even adds an optional
progress bar.

### L

Like most languages, Python allows for very concise syntax for some very
common types, such as `list`, which can be constructed with `[1,2,3]`.
Perl’s designer Larry Wall explained the reasoning for this kind of
syntax:

> In metaphorical honor of Huffman’s compression code that assigns
> smaller numbers of bits to more common bytes. In terms of syntax, it
> simply means that commonly used things should be shorter, but you
> shouldn’t waste short sequences on less common constructs.

On this basis, `fastcore` has just one type that has a single letter
name: [`L`](https://fastcore.fast.ai/foundation.html#l). The reason for
this is that it is designed to be a replacement for `list`, so we want
it to be just as easy to use as `[1,2,3]`. Here’s how to create that as
an [`L`](https://fastcore.fast.ai/foundation.html#l):

``` python
L(1,2,3)
```

    (#3) [1,2,3]

The first thing to notice is that an
[`L`](https://fastcore.fast.ai/foundation.html#l) object includes in its
representation its number of elements; that’s the `(#3)` in the output
above. If there’s more than 10 elements, it will automatically truncate
the list:

``` python
p = L.range(20).shuffle()
p
```

    (#20) [5,1,9,10,18,13,6,17,3,16...]

[`L`](https://fastcore.fast.ai/foundation.html#l) contains many of the
same indexing ideas that NumPy’s `array` does, including indexing with a
list of indexes, or a boolean mask list:

``` python
p[2,4,6]
```

    (#3) [9,18,6]

It also contains other methods used in `array`, such as
[`L.argwhere`](https://fastcore.fast.ai/foundation.html#l.argwhere):

``` python
p.argwhere(ge(15))
```

    (#5) [4,7,9,18,19]

As you can see from this example, `fastcore` also includes a number of
features that make a functional style of programming easier, such as a
full range of boolean functions (e.g `ge`, `gt`, etc) which give the
same answer as the functions from Python’s `operator` module if given
two parameters, but return a [curried
function](https://en.wikipedia.org/wiki/Currying) if given one
parameter.

There’s too much functionality to show it all here, so be sure to check
the docs. Many little things are added that we thought should have been
in `list` in the first place, such as making this do what you’d expect
(which is an error with `list`, but works fine with
[`L`](https://fastcore.fast.ai/foundation.html#l)):

``` python
1 + L(2,3,4)
```

    (#4) [1,2,3,4]

### Transforms

A [`Transform`](https://fastcore.fast.ai/transform.html#transform) is
the main building block of the fastai data pipelines. In the most
general terms a transform can be any function you want to apply to your
data, however the
[`Transform`](https://fastcore.fast.ai/transform.html#transform) class
provides several mechanisms that make the process of building them easy
and flexible (see the docs for information about each of these):

- Type dispatch
- Dispatch over tuples
- Reversability
- Type propagation
- Preprocessing
- Filtering based on the dataset type
- Ordering
- Appending new behavior with decorators

[`Transform`](https://fastcore.fast.ai/transform.html#transform) looks
for three special methods, <code>encodes</code>, <code>decodes</code>,
and <code>setups</code>, which provide the implementation for
[`__call__`](https://www.python-course.eu/python3_magic_methods.php),
`decode`, and `setup` respectively. For instance:

``` python
class A(Transform):
    def encodes(self, x): return x+1

A()(1)
```

    2

For simple transforms like this, you can also use
[`Transform`](https://fastcore.fast.ai/transform.html#transform) as a
decorator:

``` python
@Transform
def f(x): return x+1

f(1)
```

    2

Transforms can be composed into a
[`Pipeline`](https://fastcore.fast.ai/transform.html#pipeline):

``` python
@Transform
def g(x): return x/2

pipe = Pipeline([f,g])
pipe(3)
```

    2.0

The power of
[`Transform`](https://fastcore.fast.ai/transform.html#transform) and
[`Pipeline`](https://fastcore.fast.ai/transform.html#pipeline) is best
understood by seeing how they’re used to create a complete data
processing pipeline. This is explained in [chapter
11](https://github.com/fastai/fastbook/blob/master/11_midlevel_data.ipynb)
of the [fastai
book](https://www.amazon.com/Deep-Learning-Coders-fastai-PyTorch/dp/1492045527),
which is [available for free](https://github.com/fastai/fastbook) in
Jupyter Notebook format.</doc>
    <doc title="Blog Post" desc="A tour of some of the features of fastcore."># fastcore: An Underrated Python Library

A unique python library that extends the python programming language and provides utilities that enhance productivity.

Sep 1, 2020 •  Hamel Husain •  14 min read

__fastcore   fastai

# Background __

I recently embarked on a journey to sharpen my python skills: I wanted to learn advanced patterns, idioms, and techniques. I started with reading books on advanced Python, however, the information didn't seem to stick without having somewhere to apply it. I also wanted the ability to ask questions from an expert while I was learning -- which is an arrangement that is hard to find! That's when it occurred to me: What if I could find an open source project that has fairly advanced python code and write documentation and tests? I made a bet that if I did this it would force me to learn everything very deeply, and the maintainers would be appreciative of my work and be willing to answer my questions.

And that's exactly what I did over the past month! I'm pleased to report that it has been the most efficient learning experience I've ever experienced. I've discovered that writing documentation forced me to deeply understand not just what the code does but also _why the code works the way it does_ , and to explore edge cases while writing tests. Most importantly, I was able to ask questions when I was stuck, and maintainers were willing to devote extra time knowing that their mentorship was in service of making their code more accessible! It turns out the library I choose, fastcore is some of the most fascinating Python I have ever encountered as its purpose and goals are fairly unique.

For the uninitiated, fastcore is a library on top of which many fast.ai projects are built on. Most importantly, fastcore extends the python programming language and strives to eliminate boilerplate and add useful functionality for common tasks. In this blog post, I'm going to highlight some of my favorite tools that fastcore provides, rather than sharing what I learned about python. My goal is to pique your interest in this library, and hopefully motivate you to check out the documentation after you are done to learn more!

# Why fastcore is interesting __

  1. **Get exposed to ideas from other languages without leaving python:** I’ve always heard that it is beneficial to learn other languages in order to become a better programmer. From a pragmatic point of view, I’ve found it difficult to learn other languages because I could never use them at work. Fastcore extends python to include patterns found in languages as diverse as Julia, Ruby and Haskell. Now that I understand these tools I am motivated to learn other languages.
  2. **You get a new set of pragmatic tools** : fastcore includes utilities that will allow you to write more concise expressive code, and perhaps solve new problems.
  3. **Learn more about the Python programming language:** Because fastcore extends the python programming language, many advanced concepts are exposed during the process. For the motivated, this is a great way to see how many of the internals of python work. 

# A whirlwind tour through fastcore __

Here are some things you can do with fastcore that immediately caught my attention.

* * *

## Making **kwargs transparent __

Whenever I see a function that has the argument****kwargs** , I cringe a little. This is because it means the API is obfuscated and I have to read the source code to figure out what valid parameters might be. Consider the below example:

```
def baz(a, b=2, c=3, d=4): return a + b + c

def foo(c, a, **kwargs):
    return c + baz(a, **kwargs)

inspect.signature(foo)

```

```
<Signature (c, a, **kwargs)>
```

Without reading the source code, it might be hard for me to know that `foo` also accepts and additional parameters `b` and `d`. We can fix this with `delegates`:

```
def baz(a, b=2, c=3, d=4): return a + b + c

@delegates(baz) # this decorator will pass down keyword arguments from baz
def foo(c, a, **kwargs):
    return c + baz(a, **kwargs)

inspect.signature(foo)

```

```
<Signature (c, a, b=2, d=4)>
```

You can customize the behavior of this decorator. For example, you can have your cake and eat it too by passing down your arguments and also keeping `**kwargs`:

```
@delegates(baz, keep=True)
def foo(c, a, **kwargs):
    return c + baz(a, **kwargs)

inspect.signature(foo)

```

```
<Signature (c, a, b=2, d=4, **kwargs)>
```

You can also exclude arguments. For example, we exclude argument `d` from delegation:

```
def basefoo(a, b=2, c=3, d=4): pass

@delegates(basefoo, but=['d']) # exclude `d`
def foo(c, a, **kwargs): pass

inspect.signature(foo)

```

```
<Signature (c, a, b=2)>
```

You can also delegate between classes:

```
class BaseFoo:
    def __init__(self, e, c=2): pass

@delegates()# since no argument was passsed here we delegate to the superclass
class Foo(BaseFoo):
    def __init__(self, a, b=1, **kwargs): super().__init__(**kwargs)

inspect.signature(Foo)

```

```
<Signature (a, b=1, c=2)>
```

For more information, read the docs on delegates.

* * *

## Avoid boilerplate when setting instance attributes __

Have you ever wondered if it was possible to avoid the boilerplate involved with setting attributes in`__init__`?

```
class Test:
    def __init__(self, a, b ,c): 
        self.a, self.b, self.c = a, b, c

```

Ouch! That was painful. Look at all the repeated variable names. Do I really have to repeat myself like this when defining a class? Not Anymore! Checkout store_attr:

```
class Test:
    def __init__(self, a, b, c): 
        store_attr()

t = Test(5,4,3)
assert t.b == 4

```

You can also exclude certain attributes:

```
class Test:
    def __init__(self, a, b, c): 
        store_attr(but=['c'])

t = Test(5,4,3)
assert t.b == 4
assert not hasattr(t, 'c')

```

There are many more ways of customizing and using `store_attr` than I highlighted here. Check out the docs for more detail.

P.S. you might be thinking that Python dataclasses also allow you to avoid this boilerplate. While true in some cases, `store_attr` is more flexible.1

1\. For example, store_attr does not rely on inheritance, which means you won't get stuck using multiple inheritance when using this with your own classes. Also, unlike dataclasses, store_attr does not require python 3.7 or higher. Furthermore, you can use store_attr anytime in the object lifecycle, and in any location in your class to customize the behavior of how and when variables are stored.↩

* * *

## Avoiding subclassing boilerplate __

One thing I hate about python is the`__super__().__init__()` boilerplate associated with subclassing. For example:

```
class ParentClass:
    def __init__(self): self.some_attr = 'hello'

class ChildClass(ParentClass):
    def __init__(self):
        super().__init__()

cc = ChildClass()
assert cc.some_attr == 'hello' # only accessible b/c you used super

```

We can avoid this boilerplate by using the metaclass PrePostInitMeta. We define a new class called `NewParent` that is a wrapper around the `ParentClass`:

```
class NewParent(ParentClass, metaclass=PrePostInitMeta):
    def __pre_init__(self, *args, **kwargs): super().__init__()

class ChildClass(NewParent):
    def __init__(self):pass

sc = ChildClass()
assert sc.some_attr == 'hello' 

```

* * *

## Type Dispatch __

Type dispatch, orMultiple dispatch, allows you to change the way a function behaves based upon the input types it receives. This is a prominent feature in some programming languages like Julia. For example, this is a conceptual example of how multiple dispatch works in Julia, returning different values depending on the input types of x and y:

```
collide_with(x::Asteroid, y::Asteroid) = ... 
# deal with asteroid hitting asteroid

collide_with(x::Asteroid, y::Spaceship) = ... 
# deal with asteroid hitting spaceship

collide_with(x::Spaceship, y::Asteroid) = ... 
# deal with spaceship hitting asteroid

collide_with(x::Spaceship, y::Spaceship) = ... 
# deal with spaceship hitting spaceship

```

Type dispatch can be especially useful in data science, where you might allow different input types (i.e. Numpy arrays and Pandas dataframes) to a function that processes data. Type dispatch allows you to have a common API for functions that do similar tasks.

Unfortunately, Python does not support this out-of-the box. Fortunately, there is the @typedispatch decorator to the rescue. This decorator relies upon type hints in order to route inputs the correct version of the function:

```
@typedispatch
def f(x:str, y:str): return f'{x}{y}'

@typedispatch
def f(x:np.ndarray): return x.sum()

@typedispatch
def f(x:int, y:int): return x+y

```

Below is a demonstration of type dispatch at work for the function `f`:

```
f('Hello ', 'World!')

```

```
'Hello World!'
```

```
f(2,3)

```

```
5
```

```
f(np.array([5,5,5,5]))

```

```
20
```

There are limitations of this feature, as well as other ways of using this functionality that you can read about here. In the process of learning about typed dispatch, I also found a python library called multipledispatch made by Mathhew Rocklin (the creator of Dask).

After using this feature, I am now motivated to learn languages like Julia to discover what other paradigms I might be missing.

* * *

## A better version of functools.partial __

`functools.partial` is a great utility that creates functions from other functions that lets you set default values. Lets take this function for example that filters a list to only contain values >= `val`:

```
test_input = [1,2,3,4,5,6]
def f(arr, val): 
    "Filter a list to remove any values that are less than val."
    return [x for x in arr if x >= val]

f(test_input, 3)

```

```
[3, 4, 5, 6]
```

You can create a new function out of this function using `partial` that sets the default value to 5:

```
filter5 = partial(f, val=5)
filter5(test_input)

```

```
[5, 6]
```

One problem with `partial` is that it removes the original docstring and replaces it with a generic docstring:

```
filter5.__doc__

```

```
'partial(func, *args, **keywords) - new function with partial application\n    of the given arguments and keywords.\n'
```

fastcore.utils.partialler fixes this, and makes sure the docstring is retained such that the new API is transparent:

```
filter5 = partialler(f, val=5)
filter5.__doc__

```

```
'Filter a list to remove any values that are less than val.'
```

* * *

## Composition of functions __

A technique that is pervasive in functional programming languages is function composition, whereby you chain a bunch of functions together to achieve some kind of result. This is especially useful when applying various data transformations. Consider a toy example where I have three functions: (1) Removes elements of a list less than 5 (from the prior section) (2) adds 2 to each number (3) sums all the numbers:

```
def add(arr, val): return [x + val for x in arr]
def arrsum(arr): return sum(arr)

# See the previous section on partialler
add2 = partialler(add, val=2)

transform = compose(filter5, add2, arrsum)
transform([1,2,3,4,5,6])

```

```
15
```

But why is this useful? You might me thinking, I can accomplish the same thing with:

```
arrsum(add2(filter5([1,2,3,4,5,6])))

```

You are not wrong! However, composition gives you a convenient interface in case you want to do something like the following:

```
def fit(x, transforms:list):
    "fit a model after performing transformations"
    x = compose(*transforms)(x)
    y = [np.mean(x)] * len(x) # its a dumb model.  Don't judge me
    return y

# filters out elements < 5, adds 2, then predicts the mean
fit(x=[1,2,3,4,5,6], transforms=[filter5, add2])

```

```
[7.5, 7.5]
```

For more information about `compose`, read the docs.

* * *

## A more useful `__repr__`__

In python,`__repr__` helps you get information about an object for logging and debugging. Below is what you get by default when you define a new class. (Note: we are using `store_attr`, which was discussed earlier).

```
class Test:
    def __init__(self, a, b=2, c=3): store_attr() # `store_attr` was discussed previously

Test(1)

```

```
<__main__.Test at 0x7ffcd766cee0>
```

We can use basic_repr to quickly give us a more sensible default:

```
class Test:
    def __init__(self, a, b=2, c=3): store_attr() 
    __repr__ = basic_repr('a,b,c')

Test(2)

```

```
Test(a=2, b=2, c=3)
```

* * *

## Monkey Patching With A Decorator __

It can be convenient tomonkey patch with a decorator, which is especially helpful when you want to patch an external library you are importing. We can use the decorator @patch from `fastcore.foundation` along with type hints like so:

```
class MyClass(int): pass  

@patch
def func(self:MyClass, a): return self+a

mc = MyClass(3)

```

Now, `MyClass` has an additional method named `func`:

```
mc.func(10)

```

```
13
```

Still not convinced? I'll show you another example of this kind of patching in the next section.

* * *

## A better pathlib.Path __

When you seethese extensions to pathlib.path you won't ever use vanilla pathlib again! A number of additional methods have been added to pathlib, such as:

  * `Path.readlines`: same as `with open('somefile', 'r') as f: f.readlines()`
  * `Path.read`: same as `with open('somefile', 'r') as f: f.read()`
  * `Path.save`: saves file as pickle
  * `Path.load`: loads pickle file
  * `Path.ls`: shows the contents of the path as a list. 
  * etc.

Read more about this here. Here is a demonstration of `ls`:

```
from fastcore.utils import *
from pathlib import Path
p = Path('.')
p.ls() # you don't get this with vanilla Pathlib.Path!!

```

```
(#7) [Path('2020-09-01-fastcore.ipynb'),Path('README.md'),Path('fastcore_imgs'),Path('2020-02-20-test.ipynb'),Path('.ipynb_checkpoints'),Path('2020-02-21-introducing-fastpages.ipynb'),Path('my_icons')]
```

Wait! What's going on here? We just imported `pathlib.Path` \- why are we getting this new functionality? Thats because we imported the `fastcore.utils` module, which patches this module via the `@patch` decorator discussed earlier. Just to drive the point home on why the `@patch` decorator is useful, I'll go ahead and add another method to `Path` right now:

```
@patch
def fun(self:Path): return "This is fun!"

p.fun()

```

```
'This is fun!'
```

That is magical, right? I know! That's why I'm writing about it!

* * *

## An Even More Concise Way To Create Lambdas __

`Self`, with an uppercase S, is an even more concise way to create lambdas that are calling methods on an object. For example, let's create a lambda for taking the sum of a Numpy array:

```
arr=np.array([5,4,3,2,1])
f = lambda a: a.sum()
assert f(arr) == 15

```

You can use `Self` in the same way:

```
f = Self.sum()
assert f(arr) == 15

```

Let's create a lambda that does a groupby and max of a Pandas dataframe:

```
import pandas as pd
df=pd.DataFrame({'Some Column': ['a', 'a', 'b', 'b', ], 
                 'Another Column': [5, 7, 50, 70]})

f = Self.groupby('Some Column').mean()
f(df)

```

| Another Column  
---|---  
Some Column |   
a | 6  
b | 60  
  
Read more about `Self` in the docs).

* * *

## Notebook Functions __

These are simple but handy, and allow you to know whether or not code is executing in a Jupyter Notebook, Colab, or an Ipython Shell:

```
from fastcore.imports import in_notebook, in_colab, in_ipython
in_notebook(), in_colab(), in_ipython()

```

```
(True, False, True)
```

This is useful if you are displaying certain types of visualizations, progress bars or animations in your code that you may want to modify or toggle depending on the environment.

* * *

## A Drop-In Replacement For List __

You might be pretty happy with Python's`list`. This is one of those situations that you don't know you needed a better list until someone showed one to you. Enter `L`, a list like object with many extra goodies.

The best way I can describe `L` is to pretend that `list` and `numpy` had a pretty baby:

define a list (check out the nice `__repr__` that shows the length of the list!)

```
L(1,2,3)

```

```
(#3) [1,2,3]
```

Shuffle a list:

```
p = L.range(20).shuffle()
p

```

```
(#20) [8,7,5,12,14,16,2,15,19,6...]
```

Index into a list:

```
p[2,4,6]

```

```
(#3) [5,14,2]
```

L has sensible defaults, for example appending an element to a list:

```
1 + L(2,3,4)

```

```
(#4) [1,2,3,4]
```

There is much more `L` has to offer. Read the docs to learn more.

# But Wait ... There's More!__

There are more things I would like to show you about fastcore, but there is no way they would reasonably fit into a blog post. Here is a list of some of my favorite things that I didn't demo in this blog post:

## Utilities __

TheBasics section contain many shortcuts to perform common tasks or provide an additional interface to what standard python provides.

  * mk_class: quickly add a bunch of attributes to a class
  * wrap_class: add new methods to a class with a simple decorator
  * groupby: similar to Scala's groupby
  * merge: merge dicts
  * fasttuple: a tuple on steroids
  * Infinite Lists: useful for padding and testing
  * chunked: for batching and organizing stuff

## Multiprocessing __

TheMultiprocessing section extends python's multiprocessing library by offering features like:

  * progress bars
  * ability to pause to mitigate race conditions with external services
  * processing things in batches on each worker, ex: if you have a vectorized operation to perform in chunks

## Functional Programming __

Thefunctional programming section is my favorite part of this library.

  * maps: a map that also composes functions
  * mapped: A more robust `map`
  * using_attr: compose a function that operates on an attribute

## Transforms __

Transforms is a collection of utilities for creating data transformations and associated pipelines. These transformation utilities build upon many of the building blocks discussed in this blog post.

## Further Reading __

**It should be noted that you should read themain page of the docs first, followed by the section on tests to fully understand the documentation.**

  * The fastcore documentation site.
  * The fastcore GitHub repo.
  * Blog post on delegation.

# Shameless plug: fastpages __

This blog post was written entirely in a Jupyter Notebook, which GitHub automatically converted into to a blog post! Sound interesting?Check out fastpages.</doc>
  </tutorials>
  <api>
    <doc title="API List" desc="A succint list of all functions and methods in fastcore."># fastcore Module Documentation

## fastcore.basics

> Basic functionality used in the fastai library

- `def ifnone(a, b)`
    `b` if `a` is None else `a`

- `def maybe_attr(o, attr)`
    `getattr(o,attr,o)`

- `def basic_repr(flds)`
    Minimal `__repr__`

- `def is_array(x)`
    `True` if `x` supports `__array__` or `iloc`

- `def listify(o, *rest)`
    Convert `o` to a `list`

- `def tuplify(o, use_list, match)`
    Make `o` a tuple

- `def true(x)`
    Test whether `x` is truthy; collections with >0 elements are considered `True`

- `class NullType`
    An object that is `False` and can be called, chained, and indexed

    - `def __getattr__(self, *args)`
    - `def __call__(self, *args, **kwargs)`
    - `def __getitem__(self, *args)`
    - `def __bool__(self)`

- `def tonull(x)`
    Convert `None` to `null`

- `def get_class(nm, *fld_names, **flds)`
    Dynamically create a class, optionally inheriting from `sup`, containing `fld_names`

- `def mk_class(nm, *fld_names, **flds)`
    Create a class using `get_class` and add to the caller's module

- `def wrap_class(nm, *fld_names, **flds)`
    Decorator: makes function a method of a new class `nm` passing parameters to `mk_class`

- `class ignore_exceptions`
    Context manager to ignore exceptions

    - `def __enter__(self)`
    - `def __exit__(self, *args)`

- `def exec_local(code, var_name)`
    Call `exec` on `code` and return the var `var_name`

- `def risinstance(types, obj)`
    Curried `isinstance` but with args reversed

- `class Inf`
    Infinite lists


- `def in_(x, a)`
    `True` if `x in a`

- `def ret_true(*args, **kwargs)`
    Predicate: always `True`

- `def ret_false(*args, **kwargs)`
    Predicate: always `False`

- `def stop(e)`
    Raises exception `e` (by default `StopIteration`)

- `def gen(func, seq, cond)`
    Like `(func(o) for o in seq if cond(func(o)))` but handles `StopIteration`

- `def chunked(it, chunk_sz, drop_last, n_chunks)`
    Return batches from iterator `it` of size `chunk_sz` (or return `n_chunks` total)

- `def otherwise(x, tst, y)`
    `y if tst(x) else x`

- `def custom_dir(c, add)`
    Implement custom `__dir__`, adding `add` to `cls`

- `class AttrDict`
    `dict` subclass that also provides access to keys as attrs

    - `def __getattr__(self, k)`
    - `def __setattr__(self, k, v)`
    - `def __dir__(self)`
    - `def copy(self)`

- `class AttrDictDefault`
    `AttrDict` subclass that returns `None` for missing attrs

    - `def __init__(self, *args, **kwargs)`
    - `def __getattr__(self, k)`

- `class NS`
    `SimpleNamespace` subclass that also adds `iter` and `dict` support

    - `def __iter__(self)`
    - `def __getitem__(self, x)`
    - `def __setitem__(self, x, y)`

- `def get_annotations_ex(obj)`
    Backport of py3.10 `get_annotations` that returns globals/locals

- `def eval_type(t, glb, loc)`
    `eval` a type or collection of types, if needed, for annotations in py3.10+

- `def type_hints(f)`
    Like `typing.get_type_hints` but returns `{}` if not allowed type

- `def annotations(o)`
    Annotations for `o`, or `type(o)`

- `def anno_ret(func)`
    Get the return annotation of `func`

- `def signature_ex(obj, eval_str)`
    Backport of `inspect.signature(..., eval_str=True` to <py310

- `def argnames(f, frame)`
    Names of arguments to function or frame `f`

- `def with_cast(f)`
    Decorator which uses any parameter annotations as preprocessing functions

- `def store_attr(names, self, but, cast, store_args, **attrs)`
    Store params named in comma-separated `names` from calling context into attrs in `self`

- `def attrdict(o, *ks)`
    Dict from each `k` in `ks` to `getattr(o,k)`

- `def properties(cls, *ps)`
    Change attrs in `cls` with names in `ps` to properties

- `def camel2words(s, space)`
    Convert CamelCase to 'spaced words'

- `def camel2snake(name)`
    Convert CamelCase to snake_case

- `def snake2camel(s)`
    Convert snake_case to CamelCase

- `def class2attr(self, cls_name)`
    Return the snake-cased name of the class; strip ending `cls_name` if it exists.

- `def getcallable(o, attr)`
    Calls `getattr` with a default of `noop`

- `def getattrs(o, *attrs)`
    List of all `attrs` in `o`

- `def hasattrs(o, attrs)`
    Test whether `o` contains all `attrs`

- `def try_attrs(obj, *attrs)`
    Return first attr that exists in `obj`

- `class GetAttrBase`
    Basic delegation of `__getattr__` and `__dir__`

    - `def __getattr__(self, k)`
    - `def __dir__(self)`

- `class GetAttr`
    Inherit from this to have all attr accesses in `self._xtra` passed down to `self.default`

    - `def __getattr__(self, k)`
    - `def __dir__(self)`
    - `def __setstate__(self, data)`

- `def delegate_attr(self, k, to)`
    Use in `__getattr__` to delegate to attr `to` without inheriting from `GetAttr`

- `class ShowPrint`
    Base class that prints for `show`

    - `def show(self, *args, **kwargs)`

- `class Int`
    An extensible `int`


- `class Str`
    An extensible `str`


- `class Float`
    An extensible `float`


- `def partition(coll, f)`
    Partition a collection by a predicate

- `def flatten(o)`
    Concatenate all collections and items as a generator

- `def concat(colls)`
    Concatenate all collections and items as a list

- `def strcat(its, sep)`
    Concatenate stringified items `its`

- `def detuplify(x)`
    If `x` is a tuple with one thing, extract it

- `def replicate(item, match)`
    Create tuple of `item` copied `len(match)` times

- `def setify(o)`
    Turn any list like-object into a set.

- `def merge(*ds)`
    Merge all dictionaries in `ds`

- `def range_of(x)`
    All indices of collection `x` (i.e. `list(range(len(x)))`)

- `def groupby(x, key, val)`
    Like `itertools.groupby` but doesn't need to be sorted, and isn't lazy, plus some extensions

- `def last_index(x, o)`
    Finds the last index of occurence of `x` in `o` (returns -1 if no occurence)

- `def filter_dict(d, func)`
    Filter a `dict` using `func`, applied to keys and values

- `def filter_keys(d, func)`
    Filter a `dict` using `func`, applied to keys

- `def filter_values(d, func)`
    Filter a `dict` using `func`, applied to values

- `def cycle(o)`
    Like `itertools.cycle` except creates list of `None`s if `o` is empty

- `def zip_cycle(x, *args)`
    Like `itertools.zip_longest` but `cycle`s through elements of all but first argument

- `def sorted_ex(iterable, key, reverse)`
    Like `sorted`, but if key is str use `attrgetter`; if int use `itemgetter`

- `def not_(f)`
    Create new function that negates result of `f`

- `def argwhere(iterable, f, negate, **kwargs)`
    Like `filter_ex`, but return indices for matching items

- `def filter_ex(iterable, f, negate, gen, **kwargs)`
    Like `filter`, but passing `kwargs` to `f`, defaulting `f` to `noop`, and adding `negate` and `gen`

- `def renumerate(iterable, start)`
    Same as `enumerate`, but returns index as 2nd element instead of 1st

- `def first(x, f, negate, **kwargs)`
    First element of `x`, optionally filtered by `f`, or None if missing

- `def only(o)`
    Return the only item of `o`, raise if `o` doesn't have exactly one item

- `def nested_attr(o, attr, default)`
    Same as `getattr`, but if `attr` includes a `.`, then looks inside nested objects

- `def nested_setdefault(o, attr, default)`
    Same as `setdefault`, but if `attr` includes a `.`, then looks inside nested objects

- `def nested_callable(o, attr)`
    Same as `nested_attr` but if not found will return `noop`

- `def nested_idx(coll, *idxs)`
    Index into nested collections, dicts, etc, with `idxs`

- `def set_nested_idx(coll, value, *idxs)`
    Set value indexed like `nested_idx

- `def val2idx(x)`
    Dict from value to index

- `def uniqueify(x, sort, bidir, start)`
    Unique elements in `x`, optional `sort`, optional return reverse correspondence, optional prepend with elements.

- `def loop_first_last(values)`
    Iterate and generate a tuple with a flag for first and last value.

- `def loop_first(values)`
    Iterate and generate a tuple with a flag for first value.

- `def loop_last(values)`
    Iterate and generate a tuple with a flag for last value.

- `def first_match(lst, f, default)`
    First element of `lst` matching predicate `f`, or `default` if none

- `def last_match(lst, f, default)`
    Last element of `lst` matching predicate `f`, or `default` if none

- `class fastuple`
    A `tuple` with elementwise ops and more friendly __init__ behavior

    - `def __new__(cls, x, *rest)`
    - `def mul(self, *args)`
        `*` is already defined in `tuple` for replicating, so use `mul` instead

    - `def add(self, *args)`
        `+` is already defined in `tuple` for concat, so use `add` instead


- `class bind`
    Same as `partial`, except you can use `arg0` `arg1` etc param placeholders

    - `def __init__(self, func, *pargs, **pkwargs)`
    - `def __call__(self, *args, **kwargs)`

- `def mapt(func, *iterables)`
    Tuplified `map`

- `def map_ex(iterable, f, *args, **kwargs)`
    Like `map`, but use `bind`, and supports `str` and indexing

- `def compose(*funcs)`
    Create a function that composes all functions in `funcs`, passing along remaining `*args` and `**kwargs` to all

- `def maps(*args)`
    Like `map`, except funcs are composed first

- `def partialler(f, *args, **kwargs)`
    Like `functools.partial` but also copies over docstring

- `def instantiate(t)`
    Instantiate `t` if it's a type, otherwise do nothing

- `def using_attr(f, attr)`
    Construct a function which applies `f` to the argument's attribute `attr`

- `def copy_func(f)`
    Copy a non-builtin function (NB `copy.copy` does not work for this)

- `def patch_to(cls, as_prop, cls_method)`
    Decorator: add `f` to `cls`

- `def patch(f)`
    Decorator: add `f` to the first parameter's class (based on f's type annotations)

- `def patch_property(f)`
    Deprecated; use `patch(as_prop=True)` instead

- `def compile_re(pat)`
    Compile `pat` if it's not None

- `class ImportEnum`
    An `Enum` that can have its values imported

    - `@classmethod def imports(cls)`
    - `@property def name(self)`

- `class StrEnum`
    An `ImportEnum` that behaves like a `str`

    - `def __str__(self)`
    - `@property def name(self)`

- `def str_enum(name, *vals)`
    Simplified creation of `StrEnum` types

- `class ValEnum`
    An `ImportEnum` that stringifies using values

    - `def __str__(self)`
    - `@property def name(self)`

- `class Stateful`
    A base class/mixin for objects that should not serialize all their state

    - `def __init__(self, *args, **kwargs)`
    - `def __getstate__(self)`
    - `def __setstate__(self, state)`

- `class NotStr`
    Behaves like a `str`, but isn't an instance of one

    - `def __init__(self, s)`
    - `def __repr__(self)`
    - `def __str__(self)`
    - `def __add__(self, b)`
    - `def __mul__(self, b)`
    - `def __len__(self)`
    - `def __eq__(self, b)`
    - `def __lt__(self, b)`
    - `def __hash__(self)`
    - `def __bool__(self)`
    - `def __contains__(self, b)`
    - `def __iter__(self)`

- `class PrettyString`
    Little hack to get strings to show properly in Jupyter.

    - `def __repr__(self)`

- `def even_mults(start, stop, n)`
    Build log-stepped array from `start` to `stop` in `n` steps.

- `def num_cpus()`
    Get number of cpus

- `def add_props(f, g, n)`
    Create properties passing each of `range(n)` to f

- `def typed(f)`
    Decorator to check param and return types at runtime

- `def exec_new(code)`
    Execute `code` in a new environment and return it

- `def exec_import(mod, sym)`
    Import `sym` from `mod` in a new environment

- `def str2bool(s)`
    Case-insensitive convert string `s` too a bool (`y`,`yes`,`t`,`true`,`on`,`1`->`True`)

## fastcore.dispatch

> Basic single and dual parameter dispatch

- `def lenient_issubclass(cls, types)`
    If possible return whether `cls` is a subclass of `types`, otherwise return False.

- `def sorted_topologically(iterable)`
    Return a new list containing all items from the iterable sorted topologically

- `class TypeDispatch`
    Dictionary-like object; `__getitem__` matches keys of types using `issubclass`

    - `def __init__(self, funcs, bases)`
    - `def add(self, f)`
        Add type `t` and function `f`

    - `def first(self)`
        Get first function in ordered dict of type:func.

    - `def returns(self, x)`
        Get the return type of annotation of `x`.

    - `def __repr__(self)`
    - `def __call__(self, *args, **kwargs)`
    - `def __get__(self, inst, owner)`
    - `def __getitem__(self, k)`
        Find first matching type that is a super-class of `k`


- `class DispatchReg`
    A global registry for `TypeDispatch` objects keyed by function name

    - `def __init__(self)`
    - `def __call__(self, f)`

- `def retain_meta(x, res, as_copy)`
    Call `res.set_meta(x)`, if it exists

- `def default_set_meta(self, x, as_copy)`
    Copy over `_meta` from `x` to `res`, if it's missing

- `@typedispatch def cast(x, typ)`
    cast `x` to type `typ` (may also change `x` inplace)

- `def retain_type(new, old, typ, as_copy)`
    Cast `new` to type of `old` or `typ` if it's a superclass

- `def retain_types(new, old, typs)`
    Cast each item of `new` to type of matching item in `old` if it's a superclass

- `def explode_types(o)`
    Return the type of `o`, potentially in nested dictionaries for thing that are listy

## fastcore.docments

> Document parameters using comments.

- `def docstring(sym)`
    Get docstring for `sym` for functions ad classes

- `def parse_docstring(sym)`
    Parse a numpy-style docstring in `sym`

- `def isdataclass(s)`
    Check if `s` is a dataclass but not a dataclass' instance

- `def get_dataclass_source(s)`
    Get source code for dataclass `s`

- `def get_source(s)`
    Get source code for string, function object or dataclass `s`

- `def get_name(obj)`
    Get the name of `obj`

- `def qual_name(obj)`
    Get the qualified name of `obj`

- `@delegates(_docments) def docments(elt, full, **kwargs)`
    Generates a `docment`

- `def extract_docstrings(code)`
    Create a dict from function/class/method names to tuples of docstrings and param lists

## fastcore.docscrape

> Parse numpy-style docstrings

- `def strip_blank_lines(l)`
    Remove leading and trailing blank lines from a list of lines

- `class Reader`
    A line-based string reader.

    - `def __init__(self, data)`
    - `def __getitem__(self, n)`
    - `def reset(self)`
    - `def read(self)`
    - `def seek_next_non_empty_line(self)`
    - `def eof(self)`
    - `def read_to_condition(self, condition_func)`
    - `def read_to_next_empty_line(self)`
    - `def read_to_next_unindented_line(self)`
    - `def peek(self, n)`
    - `def is_empty(self)`

- `class ParseError`
    - `def __str__(self)`

- `class NumpyDocString`
    Parses a numpydoc string to an abstract representation

    - `def __init__(self, docstring, config)`
    - `def __iter__(self)`
    - `def __len__(self)`
    - `def __getitem__(self, key)`
    - `def __setitem__(self, key, val)`

- `def dedent_lines(lines, split)`
    Deindent a list of lines maximally

## fastcore.foundation

> The `L` class and helpers for it

- `@contextmanager def working_directory(path)`
    Change working directory to `path` and return to previous on exit.

- `def add_docs(cls, cls_doc, **docs)`
    Copy values from `docs` to `cls` docstrings, and confirm all public methods are documented

- `def docs(cls)`
    Decorator version of `add_docs`, using `_docs` dict

- `def coll_repr(c, max_n)`
    String repr of up to `max_n` items of (possibly lazy) collection `c`

- `def is_bool(x)`
    Check whether `x` is a bool or None

- `def mask2idxs(mask)`
    Convert bool mask or index list to index `L`

- `def is_indexer(idx)`
    Test whether `idx` will index a single item in a list

- `class CollBase`
    Base class for composing a list of `items`

    - `def __init__(self, items)`
    - `def __len__(self)`
    - `def __getitem__(self, k)`
    - `def __setitem__(self, k, v)`
    - `def __delitem__(self, i)`
    - `def __repr__(self)`
    - `def __iter__(self)`

- `class L`
    Behaves like a list of `items` but can also index with list of indices or masks

    - `def __init__(self, items, *rest)`
    - `def __getitem__(self, idx)`
    - `def copy(self)`
    - `def __setitem__(self, idx, o)`
        Set `idx` (can be list of indices, or mask, or int) items to `o` (which is broadcast if not iterable)

    - `def __eq__(self, b)`
    - `def sorted(self, key, reverse)`
    - `def __iter__(self)`
    - `def __contains__(self, b)`
    - `def __reversed__(self)`
    - `def __invert__(self)`
    - `def __repr__(self)`
    - `def __mul__(a, b)`
    - `def __add__(a, b)`
    - `def __radd__(a, b)`
    - `def __addi__(a, b)`
    - `@classmethod def split(cls, s, sep, maxsplit)`
    - `@classmethod def range(cls, a, b, step)`
    - `def map(self, f, *args, **kwargs)`
    - `def argwhere(self, f, negate, **kwargs)`
    - `def argfirst(self, f, negate)`
    - `def filter(self, f, negate, **kwargs)`
    - `def enumerate(self)`
    - `def renumerate(self)`
    - `def unique(self, sort, bidir, start)`
    - `def val2idx(self)`
    - `def cycle(self)`
    - `def map_dict(self, f, *args, **kwargs)`
    - `def map_first(self, f, g, *args, **kwargs)`
    - `def itemgot(self, *idxs)`
    - `def attrgot(self, k, default)`
    - `def starmap(self, f, *args, **kwargs)`
    - `def zip(self, cycled)`
    - `def zipwith(self, *rest)`
    - `def map_zip(self, f, *args, **kwargs)`
    - `def map_zipwith(self, f, *rest, **kwargs)`
    - `def shuffle(self)`
    - `def concat(self)`
    - `def reduce(self, f, initial)`
    - `def sum(self)`
    - `def product(self)`
    - `def setattrs(self, attr, val)`

- `def save_config_file(file, d, **kwargs)`
    Write settings dict to a new config file, or overwrite the existing one.

- `class Config`
    Reading and writing `ConfigParser` ini files

    - `def __init__(self, cfg_path, cfg_name, create, save, extra_files, types)`
    - `def __repr__(self)`
    - `def __setitem__(self, k, v)`
    - `def __contains__(self, k)`
    - `def save(self)`
    - `def __getattr__(self, k)`
    - `def __getitem__(self, k)`
    - `def get(self, k, default)`
    - `def path(self, k, default)`

## fastcore.imghdr

> Recognize image file formats based on their first few bytes.

- `def test_jpeg(h, f)`
    JPEG data with JFIF or Exif markers; and raw JPEG

- `def test_gif(h, f)`
    GIF ('87 and '89 variants)

- `def test_tiff(h, f)`
    TIFF (can be in Motorola or Intel byte order)

- `def test_rgb(h, f)`
    SGI image library

- `def test_pbm(h, f)`
    PBM (portable bitmap)

- `def test_pgm(h, f)`
    PGM (portable graymap)

- `def test_ppm(h, f)`
    PPM (portable pixmap)

- `def test_rast(h, f)`
    Sun raster file

- `def test_xbm(h, f)`
    X bitmap (X10 or X11)

## fastcore.imports

- `def is_iter(o)`
    Test whether `o` can be used in a `for` loop

- `def is_coll(o)`
    Test whether `o` is a collection (i.e. has a usable `len`)

- `def all_equal(a, b)`
    Compares whether `a` and `b` are the same length and have the same contents

- `def noop(x, *args, **kwargs)`
    Do nothing

- `def noops(self, x, *args, **kwargs)`
    Do nothing (method)

- `def isinstance_str(x, cls_name)`
    Like `isinstance`, except takes a type name instead of a type

- `def equals(a, b)`
    Compares `a` and `b` for equality; supports sublists, tensors and arrays too

- `def ipython_shell()`
    Same as `get_ipython` but returns `False` if not in IPython

- `def in_ipython()`
    Check if code is running in some kind of IPython environment

- `def in_colab()`
    Check if the code is running in Google Colaboratory

- `def in_jupyter()`
    Check if the code is running in a jupyter notebook

- `def in_notebook()`
    Check if the code is running in a jupyter notebook

- `def remove_prefix(text, prefix)`
    Temporary until py39 is a prereq

- `def remove_suffix(text, suffix)`
    Temporary until py39 is a prereq

## fastcore.meta

> Metaclasses

- `def test_sig(f, b)`
    Test the signature of an object

- `class FixSigMeta`
    A metaclass that fixes the signature on classes that override `__new__`

    - `def __new__(cls, name, bases, dict)`

- `class PrePostInitMeta`
    A metaclass that calls optional `__pre_init__` and `__post_init__` methods

    - `def __call__(cls, *args, **kwargs)`

- `class AutoInit`
    Same as `object`, but no need for subclasses to call `super().__init__`

    - `def __pre_init__(self, *args, **kwargs)`

- `class NewChkMeta`
    Metaclass to avoid recreating object passed to constructor

    - `def __call__(cls, x, *args, **kwargs)`

- `class BypassNewMeta`
    Metaclass: casts `x` to this class if it's of type `cls._bypass_type`

    - `def __call__(cls, x, *args, **kwargs)`

- `def empty2none(p)`
    Replace `Parameter.empty` with `None`

- `def anno_dict(f)`
    `__annotation__ dictionary with `empty` cast to `None`, returning empty if doesn't exist

- `def use_kwargs_dict(keep, **kwargs)`
    Decorator: replace `**kwargs` in signature with `names` params

- `def use_kwargs(names, keep)`
    Decorator: replace `**kwargs` in signature with `names` params

- `def delegates(to, keep, but)`
    Decorator: replace `**kwargs` in signature with params from `to`

- `def method(f)`
    Mark `f` as a method

- `def funcs_kwargs(as_method)`
    Replace methods in `cls._methods` with those from `kwargs`

## fastcore.net

> Network, HTTP, and URL functions

- `def urlquote(url)`
    Update url's path with `urllib.parse.quote`

- `def urlwrap(url, data, headers)`
    Wrap `url` in a urllib `Request` with `urlquote`

- `class HTTP4xxClientError`
    Base class for client exceptions (code 4xx) from `url*` functions


- `class HTTP5xxServerError`
    Base class for server exceptions (code 5xx) from `url*` functions


- `def urlopen(url, data, headers, timeout, **kwargs)`
    Like `urllib.request.urlopen`, but first `urlwrap` the `url`, and encode `data`

- `def urlread(url, data, headers, decode, return_json, return_headers, timeout, **kwargs)`
    Retrieve `url`, using `data` dict or `kwargs` to `POST` if present

- `def urljson(url, data, timeout)`
    Retrieve `url` and decode json

- `def urlclean(url)`
    Remove fragment, params, and querystring from `url` if present

- `def urlsave(url, dest, reporthook, headers, timeout)`
    Retrieve `url` and save based on its name

- `def urlvalid(x)`
    Test if `x` is a valid URL

- `def urlrequest(url, verb, headers, route, query, data, json_data)`
    `Request` for `url` with optional route params replaced by `route`, plus `query` string, and post `data`

- `@patch def summary(self, skip)`
    Summary containing full_url, headers, method, and data, removing `skip` from headers

- `def urlsend(url, verb, headers, decode, route, query, data, json_data, return_json, return_headers, debug, timeout)`
    Send request with `urlrequest`, converting result to json if `return_json`

- `def do_request(url, post, headers, **data)`
    Call GET or json-encoded POST on `url`, depending on `post`

- `def start_server(port, host, dgram, reuse_addr, n_queue)`
    Create a `socket` server on `port`, with optional `host`, of type `dgram`

- `def start_client(port, host, dgram)`
    Create a `socket` client on `port`, with optional `host`, of type `dgram`

- `def tobytes(s)`
    Convert `s` into HTTP-ready bytes format

- `def http_response(body, status, hdrs, **kwargs)`
    Create an HTTP-ready response, adding `kwargs` to `hdrs`

- `@threaded def recv_once(host, port)`
    Spawn a thread to receive a single HTTP request and store in `d['r']`

## fastcore.parallel

> Threading and multiprocessing functions

- `def threaded(process)`
    Run `f` in a `Thread` (or `Process` if `process=True`), and returns it

- `def startthread(f)`
    Like `threaded`, but start thread immediately

- `def startproc(f)`
    Like `threaded(True)`, but start Process immediately

- `class ThreadPoolExecutor`
    Same as Python's ThreadPoolExecutor, except can pass `max_workers==0` for serial execution

    - `def __init__(self, max_workers, on_exc, pause, **kwargs)`
    - `def map(self, f, items, *args, **kwargs)`

- `@delegates() class ProcessPoolExecutor`
    Same as Python's ProcessPoolExecutor, except can pass `max_workers==0` for serial execution

    - `def __init__(self, max_workers, on_exc, pause, **kwargs)`
    - `def map(self, f, items, *args, **kwargs)`

- `def parallel(f, items, *args, **kwargs)`
    Applies `func` in parallel to `items`, using `n_workers`

- `def run_procs(f, f_done, args)`
    Call `f` for each item in `args` in parallel, yielding `f_done`

- `def parallel_gen(cls, items, n_workers, **kwargs)`
    Instantiate `cls` in `n_workers` procs & call each on a subset of `items` in parallel.

## fastcore.py2pyi

- `def imp_mod(module_path, package)`
    Import dynamically the module referenced in `fn`

- `def has_deco(node, name)`
    Check if a function node `node` has a decorator named `name`

- `def create_pyi(fn, package)`
    Convert `fname.py` to `fname.pyi` by removing function bodies and expanding `delegates` kwargs

- `@call_parse def py2pyi(fname, package)`
    Convert `fname.py` to `fname.pyi` by removing function bodies and expanding `delegates` kwargs

- `@call_parse def replace_wildcards(path)`
    Expand wildcard imports in the specified Python file.

## fastcore.script

> A fast way to turn your python function into a script.

- `def store_true()`
    Placeholder to pass to `Param` for `store_true` action

- `def store_false()`
    Placeholder to pass to `Param` for `store_false` action

- `def bool_arg(v)`
    Use as `type` for `Param` to get `bool` behavior

- `class Param`
    A parameter in a function used in `anno_parser` or `call_parse`

    - `def __init__(self, help, type, opt, action, nargs, const, choices, required, default)`
    - `def set_default(self, d)`
    - `@property def pre(self)`
    - `@property def kwargs(self)`
    - `def __repr__(self)`

- `def anno_parser(func, prog)`
    Look at params (annotated with `Param`) in func and return an `ArgumentParser`

- `def args_from_prog(func, prog)`
    Extract args from `prog`

- `def call_parse(func, nested)`
    Decorator to create a simple CLI from `func` using `anno_parser`

## fastcore.style

> Fast styling for friendly CLIs.

- `class StyleCode`
    An escape sequence for styling terminal text.

    - `def __init__(self, name, code, typ)`
    - `def __str__(self)`

- `class Style`
    A minimal terminal text styler.

    - `def __init__(self, codes)`
    - `def __dir__(self)`
    - `def __getattr__(self, k)`
    - `def __call__(self, obj)`
    - `def __repr__(self)`

- `def demo()`
    Demonstrate all available styles and their codes.

## fastcore.test

> Helper functions to quickly write tests in notebooks

- `def test_fail(f, msg, contains, args, kwargs)`
    Fails with `msg` unless `f()` raises an exception and (optionally) has `contains` in `e.args`

- `def test(a, b, cmp, cname)`
    `assert` that `cmp(a,b)`; display inputs and `cname or cmp.__name__` if it fails

- `def nequals(a, b)`
    Compares `a` and `b` for `not equals`

- `def test_eq(a, b)`
    `test` that `a==b`

- `def test_eq_type(a, b)`
    `test` that `a==b` and are same type

- `def test_ne(a, b)`
    `test` that `a!=b`

- `def is_close(a, b, eps)`
    Is `a` within `eps` of `b`

- `def test_close(a, b, eps)`
    `test` that `a` is within `eps` of `b`

- `def test_is(a, b)`
    `test` that `a is b`

- `def test_shuffled(a, b)`
    `test` that `a` and `b` are shuffled versions of the same sequence of items

- `def test_stdout(f, exp, regex)`
    Test that `f` prints `exp` to stdout, optionally checking as `regex`

- `def test_fig_exists(ax)`
    Test there is a figure displayed in `ax`

- `class ExceptionExpected`
    Context manager that tests if an exception is raised

    - `def __init__(self, ex, regex)`
    - `def __enter__(self)`
    - `def __exit__(self, type, value, traceback)`

## fastcore.transform

> Definition of `Transform` and `Pipeline`

- `class Transform`
    Delegates (`__call__`,`decode`,`setup`) to (<code>encodes</code>,<code>decodes</code>,<code>setups</code>) if `split_idx` matches

    - `def __init__(self, enc, dec, split_idx, order)`
    - `@property def name(self)`
    - `def __call__(self, x, **kwargs)`
    - `def decode(self, x, **kwargs)`
    - `def __repr__(self)`
    - `def setup(self, items, train_setup)`

- `class InplaceTransform`
    A `Transform` that modifies in-place and just returns whatever it's passed


- `class DisplayedTransform`
    A transform with a `__repr__` that shows its attrs

    - `@property def name(self)`

- `class ItemTransform`
    A transform that always take tuples as items

    - `def __call__(self, x, **kwargs)`
    - `def decode(self, x, **kwargs)`

- `def get_func(t, name, *args, **kwargs)`
    Get the `t.name` (potentially partial-ized with `args` and `kwargs`) or `noop` if not defined

- `class Func`
    Basic wrapper around a `name` with `args` and `kwargs` to call on a given type

    - `def __init__(self, name, *args, **kwargs)`
    - `def __repr__(self)`
    - `def __call__(self, t)`

- `def compose_tfms(x, tfms, is_enc, reverse, **kwargs)`
    Apply all `func_nm` attribute of `tfms` on `x`, maybe in `reverse` order

- `def mk_transform(f)`
    Convert function `f` to `Transform` if it isn't already one

- `def gather_attrs(o, k, nm)`
    Used in __getattr__ to collect all attrs `k` from `self.{nm}`

- `def gather_attr_names(o, nm)`
    Used in __dir__ to collect all attrs `k` from `self.{nm}`

- `class Pipeline`
    A pipeline of composed (for encode/decode) transforms, setup with types

    - `def __init__(self, funcs, split_idx)`
    - `def setup(self, items, train_setup)`
    - `def add(self, ts, items, train_setup)`
    - `def __call__(self, o)`
    - `def __repr__(self)`
    - `def __getitem__(self, i)`
    - `def __setstate__(self, data)`
    - `def __getattr__(self, k)`
    - `def __dir__(self)`
    - `def decode(self, o, full)`
    - `def show(self, o, ctx, **kwargs)`

## fastcore.xdg

> XDG Base Directory Specification helpers.

- `def xdg_cache_home()`
    Path corresponding to `XDG_CACHE_HOME`

- `def xdg_config_dirs()`
    Paths corresponding to `XDG_CONFIG_DIRS`

- `def xdg_config_home()`
    Path corresponding to `XDG_CONFIG_HOME`

- `def xdg_data_dirs()`
    Paths corresponding to XDG_DATA_DIRS`

- `def xdg_data_home()`
    Path corresponding to `XDG_DATA_HOME`

- `def xdg_runtime_dir()`
    Path corresponding to `XDG_RUNTIME_DIR`

- `def xdg_state_home()`
    Path corresponding to `XDG_STATE_HOME`

## fastcore.xml

> Concise generation of XML.

- `class FT`
    A 'Fast Tag' structure, containing `tag`,`children`,and `attrs`

    - `def __init__(self, tag, cs, attrs, void_, **kwargs)`
    - `def __setattr__(self, k, v)`
    - `def __getattr__(self, k)`
    - `@property def list(self)`
    - `def get(self, k, default)`
    - `def __repr__(self)`
    - `def __add__(self, b)`
    - `def __getitem__(self, idx)`
    - `def __iter__(self)`

- `def ft(tag, *c, **kw)`
    Create an `FT` structure for `to_xml()`

- `def Html(*c, **kwargs)`
    An HTML tag, optionally preceeded by `!DOCTYPE HTML`

- `class Safe`
    - `def __html__(self)`

- `def to_xml(elm, lvl, indent, do_escape)`
    Convert `ft` element tree into an XML string

- `def highlight(s, lang)`
    Markdown to syntax-highlight `s` in language `lang`

## fastcore.xtras

> Utility functions used in the fastai library

- `def walk(path, symlinks, keep_file, keep_folder, skip_folder, func, ret_folders)`
    Generator version of `os.walk`, using functions to filter files and folders

- `def globtastic(path, recursive, symlinks, file_glob, file_re, folder_re, skip_file_glob, skip_file_re, skip_folder_re, func, ret_folders)`
    A more powerful `glob`, including regex matches, symlink handling, and skip parameters

- `@contextmanager def maybe_open(f, mode, **kwargs)`
    Context manager: open `f` if it is a path (and close on exit)

- `def mkdir(path, exist_ok, parents, overwrite, **kwargs)`
    Creates and returns a directory defined by `path`, optionally removing previous existing directory if `overwrite` is `True`

- `def image_size(fn)`
    Tuple of (w,h) for png, gif, or jpg; `None` otherwise

- `def bunzip(fn)`
    bunzip `fn`, raising exception if output already exists

- `def loads(s, **kw)`
    Same as `json.loads`, but handles `None`

- `def loads_multi(s)`
    Generator of >=0 decoded json dicts, possibly with non-json ignored text at start and end

- `def dumps(obj, **kw)`
    Same as `json.dumps`, but uses `ujson` if available

- `def untar_dir(fname, dest, rename, overwrite)`
    untar `file` into `dest`, creating a directory if the root contains more than one item

- `def repo_details(url)`
    Tuple of `owner,name` from ssh or https git repo `url`

- `def run(cmd, *rest)`
    Pass `cmd` (splitting with `shlex` if string) to `subprocess.run`; return `stdout`; raise `IOError` if fails

- `def open_file(fn, mode, **kwargs)`
    Open a file, with optional compression if gz or bz2 suffix

- `def save_pickle(fn, o)`
    Save a pickle file, to a file name or opened file

- `def load_pickle(fn)`
    Load a pickle file from a file name or opened file

- `def parse_env(s, fn)`
    Parse a shell-style environment string or file

- `def expand_wildcards(code)`
    Expand all wildcard imports in the given code string.

- `def dict2obj(d, list_func, dict_func)`
    Convert (possibly nested) dicts (or lists of dicts) to `AttrDict`

- `def obj2dict(d)`
    Convert (possibly nested) AttrDicts (or lists of AttrDicts) to `dict`

- `def repr_dict(d)`
    Print nested dicts and lists, such as returned by `dict2obj`

- `def is_listy(x)`
    `isinstance(x, (tuple,list,L,slice,Generator))`

- `def mapped(f, it)`
    map `f` over `it`, unless it's not listy, in which case return `f(it)`

- `@patch def readlines(self, hint, encoding)`
    Read the content of `self`

- `@patch def read_json(self, encoding, errors)`
    Same as `read_text` followed by `loads`

- `@patch def mk_write(self, data, encoding, errors, mode)`
    Make all parent dirs of `self`, and write `data`

- `@patch def relpath(self, start)`
    Same as `os.path.relpath`, but returns a `Path`, and resolves symlinks

- `@patch def ls(self, n_max, file_type, file_exts)`
    Contents of path as a list

- `@patch def delete(self)`
    Delete a file, symlink, or directory tree

- `class IterLen`
    Base class to add iteration to anything supporting `__len__` and `__getitem__`

    - `def __iter__(self)`

- `@docs class ReindexCollection`
    Reindexes collection `coll` with indices `idxs` and optional LRU cache of size `cache`

    - `def __init__(self, coll, idxs, cache, tfm)`
    - `def __getitem__(self, i)`
    - `def __len__(self)`
    - `def reindex(self, idxs)`
    - `def shuffle(self)`
    - `def cache_clear(self)`
    - `def __getstate__(self)`
    - `def __setstate__(self, s)`

- `def get_source_link(func)`
    Return link to `func` in source code

- `def truncstr(s, maxlen, suf, space)`
    Truncate `s` to length `maxlen`, adding suffix `suf` if truncated

- `def sparkline(data, mn, mx, empty_zero)`
    Sparkline for `data`, with `None`s (and zero, if `empty_zero`) shown as empty column

- `def modify_exception(e, msg, replace)`
    Modifies `e` with a custom message attached

- `def round_multiple(x, mult, round_down)`
    Round `x` to nearest multiple of `mult`

- `def set_num_threads(nt)`
    Get numpy (and others) to use `nt` threads

- `def join_path_file(file, path, ext)`
    Return `path/file` if file is a string or a `Path`, file otherwise

- `def autostart(g)`
    Decorator that automatically starts a generator

- `class EventTimer`
    An event timer with history of `store` items of time `span`

    - `def __init__(self, store, span)`
    - `def add(self, n)`
        Record `n` events

    - `@property def duration(self)`
    - `@property def freq(self)`

- `def stringfmt_names(s)`
    Unique brace-delimited names in `s`

- `class PartialFormatter`
    A `string.Formatter` that doesn't error on missing fields, and tracks missing fields and unused args

    - `def __init__(self)`
    - `def get_field(self, nm, args, kwargs)`
    - `def check_unused_args(self, used, args, kwargs)`

- `def partial_format(s, **kwargs)`
    string format `s`, ignoring missing field errors, returning missing and extra fields

- `def utc2local(dt)`
    Convert `dt` from UTC to local time

- `def local2utc(dt)`
    Convert `dt` from local to UTC time

- `def trace(f)`
    Add `set_trace` to an existing function `f`

- `@contextmanager def modified_env(*delete, **replace)`
    Context manager temporarily modifying `os.environ` by deleting `delete` and replacing `replace`

- `class ContextManagers`
    Wrapper for `contextlib.ExitStack` which enters a collection of context managers

    - `def __init__(self, mgrs)`
    - `def __enter__(self)`
    - `def __exit__(self, *args, **kwargs)`

- `def shufflish(x, pct)`
    Randomly relocate items of `x` up to `pct` of `len(x)` from their starting location

- `def console_help(libname)`
    Show help for all console scripts from `libname`

- `def hl_md(s, lang, show)`
    Syntax highlight `s` using `lang`.

- `def type2str(typ)`
    Stringify `typ`

- `class Unset`
    - `def __repr__(self)`
    - `def __str__(self)`
    - `def __bool__(self)`
    - `@property def name(self)`

- `def nullable_dc(cls)`
    Like `dataclass`, but default of `UNSET` added to fields without defaults

- `def flexiclass(cls)`
    Convert `cls` into a `dataclass` like `make_nullable`. Converts in place and also returns the result.

- `def asdict(o)`
    Convert `o` to a `dict`, supporting dataclasses, namedtuples, iterables, and `__dict__` attrs.

- `def is_typeddict(cls)`
    Check if `cls` is a `TypedDict`

- `def is_namedtuple(cls)`
    `True` if `cls` is a namedtuple type

- `def flexicache(*funcs)`
    Like `lru_cache`, but customisable with policy `funcs`

- `def time_policy(seconds)`
    A `flexicache` policy that expires cached items after `seconds` have passed

- `def mtime_policy(filepath)`
    A `flexicache` policy that expires cached items after `filepath` modified-time changes

- `def timed_cache(seconds, maxsize)`
    Like `lru_cache`, but also with time-based eviction
</doc>
  </api>
  <optional>
    <doc title="fastcore.test" desc="Simple testing functions"># Test



## Simple test functions

We can check that code raises an exception when that’s expected
([`test_fail`](https://fastcore.fast.ai/test.html#test_fail)).

To test for equality or inequality (with different types of things) we
define a simple function
[`test`](https://fastcore.fast.ai/test.html#test) that compares two
objects with a given `cmp` operator.

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/test.py#L16"
target="_blank" style="float:right; font-size:smaller">source</a>

### test_fail

>      test_fail (f, msg='', contains='', args=None, kwargs=None)

*Fails with `msg` unless `f()` raises an exception and (optionally) has
`contains` in `e.args`*

``` python
def _fail(): raise Exception("foobar")
test_fail(_fail, contains="foo")

def _fail(): raise Exception()
test_fail(_fail)
```

We can also pass `args` and `kwargs` to function to check if it fails
with special inputs.

``` python
def _fail_args(a):
    if a == 5:
        raise ValueError
test_fail(_fail_args, args=(5,))
test_fail(_fail_args, kwargs=dict(a=5))
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/test.py#L26"
target="_blank" style="float:right; font-size:smaller">source</a>

### test

>      test (a, b, cmp, cname=None)

*`assert` that `cmp(a,b)`; display inputs and `cname or cmp.__name__` if
it fails*

``` python
test([1,2],[1,2], operator.eq)
test_fail(lambda: test([1,2],[1], operator.eq))
test([1,2],[1],   operator.ne)
test_fail(lambda: test([1,2],[1,2], operator.ne))
```

------------------------------------------------------------------------

### all_equal

>      all_equal (a, b)

*Compares whether `a` and `b` are the same length and have the same
contents*

``` python
test(['abc'], ['abc'], all_equal)
test_fail(lambda: test(['abc'],['cab'], all_equal))
```

------------------------------------------------------------------------

### equals

>      equals (a, b)

*Compares `a` and `b` for equality; supports sublists, tensors and
arrays too*

``` python
test([['abc'],['a']], [['abc'],['a']],  equals)
test([['abc'],['a'],'b', [['x']]], [['abc'],['a'],'b', [['x']]],  equals) # supports any depth and nested structure
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/test.py#L32"
target="_blank" style="float:right; font-size:smaller">source</a>

### nequals

>      nequals (a, b)

*Compares `a` and `b` for `not equals`*

``` python
test(['abc'], ['ab' ], nequals)
```

## test_eq test_ne, etc…

Just use
[`test_eq`](https://fastcore.fast.ai/test.html#test_eq)/[`test_ne`](https://fastcore.fast.ai/test.html#test_ne)
to test for `==`/`!=`.
[`test_eq_type`](https://fastcore.fast.ai/test.html#test_eq_type) checks
things are equal and of the same type. We define them using
[`test`](https://fastcore.fast.ai/test.html#test):

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/test.py#L37"
target="_blank" style="float:right; font-size:smaller">source</a>

### test_eq

>      test_eq (a, b)

*[`test`](https://fastcore.fast.ai/test.html#test) that `a==b`*

``` python
test_eq([1,2],[1,2])
test_eq([1,2],map(int,[1,2]))
test_eq(array([1,2]),array([1,2]))
test_eq(array([1,2]),array([1,2]))
test_eq([array([1,2]),3],[array([1,2]),3])
test_eq(dict(a=1,b=2), dict(b=2,a=1))
test_fail(lambda: test_eq([1,2], 1), contains="==")
test_fail(lambda: test_eq(None, np.array([1,2])), contains="==")
test_eq({'a', 'b', 'c'}, {'c', 'a', 'b'})
```

``` python
df1 = pd.DataFrame(dict(a=[1,2],b=['a','b']))
df2 = pd.DataFrame(dict(a=[1,2],b=['a','b']))
df3 = pd.DataFrame(dict(a=[1,2],b=['a','c']))

test_eq(df1,df2)
test_eq(df1.a,df2.a)
test_fail(lambda: test_eq(df1,df3), contains='==')
class T(pd.Series): pass
test_eq(df1.iloc[0], T(df2.iloc[0])) # works with subclasses
```

``` python
test_eq(torch.zeros(10), torch.zeros(10, dtype=torch.float64))
test_eq(torch.zeros(10), torch.ones(10)-1)
test_fail(lambda:test_eq(torch.zeros(10), torch.ones(1, 10)), contains='==')
test_eq(torch.zeros(3), [0,0,0])
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/test.py#L42"
target="_blank" style="float:right; font-size:smaller">source</a>

### test_eq_type

>      test_eq_type (a, b)

*[`test`](https://fastcore.fast.ai/test.html#test) that `a==b` and are
same type*

``` python
test_eq_type(1,1)
test_fail(lambda: test_eq_type(1,1.))
test_eq_type([1,1],[1,1])
test_fail(lambda: test_eq_type([1,1],(1,1)))
test_fail(lambda: test_eq_type([1,1],[1,1.]))
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/test.py#L49"
target="_blank" style="float:right; font-size:smaller">source</a>

### test_ne

>      test_ne (a, b)

*[`test`](https://fastcore.fast.ai/test.html#test) that `a!=b`*

``` python
test_ne([1,2],[1])
test_ne([1,2],[1,3])
test_ne(array([1,2]),array([1,1]))
test_ne(array([1,2]),array([1,1]))
test_ne([array([1,2]),3],[array([1,2])])
test_ne([3,4],array([3]))
test_ne([3,4],array([3,5]))
test_ne(dict(a=1,b=2), ['a', 'b'])
test_ne(['a', 'b'], dict(a=1,b=2))
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/test.py#L54"
target="_blank" style="float:right; font-size:smaller">source</a>

### is_close

>      is_close (a, b, eps=1e-05)

*Is `a` within `eps` of `b`*

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/test.py#L63"
target="_blank" style="float:right; font-size:smaller">source</a>

### test_close

>      test_close (a, b, eps=1e-05)

*[`test`](https://fastcore.fast.ai/test.html#test) that `a` is within
`eps` of `b`*

``` python
test_close(1,1.001,eps=1e-2)
test_fail(lambda: test_close(1,1.001))
test_close([-0.001,1.001], [0.,1.], eps=1e-2)
test_close(np.array([-0.001,1.001]), np.array([0.,1.]), eps=1e-2)
test_close(array([-0.001,1.001]), array([0.,1.]), eps=1e-2)
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/test.py#L68"
target="_blank" style="float:right; font-size:smaller">source</a>

### test_is

>      test_is (a, b)

*[`test`](https://fastcore.fast.ai/test.html#test) that `a is b`*

``` python
test_fail(lambda: test_is([1], [1]))
a = [1]
test_is(a, a)
b = [2]; test_fail(lambda: test_is(a, b))
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/test.py#L73"
target="_blank" style="float:right; font-size:smaller">source</a>

### test_shuffled

>      test_shuffled (a, b)

*[`test`](https://fastcore.fast.ai/test.html#test) that `a` and `b` are
shuffled versions of the same sequence of items*

``` python
a = list(range(50))
b = copy(a)
random.shuffle(b)
test_shuffled(a,b)
test_fail(lambda:test_shuffled(a,a))
```

``` python
a = 'abc'
b = 'abcabc'
test_fail(lambda:test_shuffled(a,b))
```

``` python
a = ['a', 42, True] 
b = [42, True, 'a']
test_shuffled(a,b)
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/test.py#L79"
target="_blank" style="float:right; font-size:smaller">source</a>

### test_stdout

>      test_stdout (f, exp, regex=False)

*Test that `f` prints `exp` to stdout, optionally checking as `regex`*

``` python
test_stdout(lambda: print('hi'), 'hi')
test_fail(lambda: test_stdout(lambda: print('hi'), 'ho'))
test_stdout(lambda: 1+1, '')
test_stdout(lambda: print('hi there!'), r'^hi.*!$', regex=True)
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/test.py#L87"
target="_blank" style="float:right; font-size:smaller">source</a>

### test_warns

>      test_warns (f, show=False)

``` python
test_warns(lambda: warnings.warn("Oh no!"))
test_fail(lambda: test_warns(lambda: 2+2), contains='No warnings raised')
```

``` python
test_warns(lambda: warnings.warn("Oh no!"), show=True)
```

    <class 'UserWarning'>: Oh no!

``` python
im = Image.open(TEST_IMAGE).resize((128,128)); im
```

![](00_test_files/figure-commonmark/cell-35-output-1.png)

``` python
im = Image.open(TEST_IMAGE_BW).resize((128,128)); im
```

![](00_test_files/figure-commonmark/cell-36-output-1.png)

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/test.py#L101"
target="_blank" style="float:right; font-size:smaller">source</a>

### test_fig_exists

>      test_fig_exists (ax)

*Test there is a figure displayed in `ax`*

``` python
fig,ax = plt.subplots()
ax.imshow(array(im));
```

![](00_test_files/figure-commonmark/cell-38-output-1.png)

``` python
test_fig_exists(ax)
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/test.py#L106"
target="_blank" style="float:right; font-size:smaller">source</a>

### ExceptionExpected

>      ExceptionExpected (ex=<class 'Exception'>, regex='')

*Context manager that tests if an exception is raised*

``` python
def _tst_1(): assert False, "This is a test"
def _tst_2(): raise SyntaxError

with ExceptionExpected(): _tst_1()
with ExceptionExpected(ex=AssertionError, regex="This is a test"): _tst_1()
with ExceptionExpected(ex=SyntaxError): _tst_2()
```

`exception` is an abbreviation for `ExceptionExpected()`.

``` python
with exception: _tst_1()
```</doc>
    <doc title="fastcore.basics" desc="Basic functionality used in the fastai library."># Basic functionality



## Basics

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L36"
target="_blank" style="float:right; font-size:smaller">source</a>

### ifnone

>      ifnone (a, b)

*`b` if `a` is None else `a`*

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`](https://fastcore.fast.ai/basics.html#ifnone) (which it
doesn’t do if using the `if` version directly).

``` python
test_eq(ifnone(None,1), 1)
test_eq(ifnone(2   ,1), 2)
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L41"
target="_blank" style="float:right; font-size:smaller">source</a>

### maybe_attr

>      maybe_attr (o, attr)

*`getattr(o,attr,o)`*

Return the attribute `attr` for object `o`. If the attribute doesn’t
exist, then return the object `o` instead.

``` python
class myobj: myattr='foo'

test_eq(maybe_attr(myobj, 'myattr'), 'foo')
test_eq(maybe_attr(myobj, 'another_attr'), myobj)
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L46"
target="_blank" style="float:right; font-size:smaller">source</a>

### basic_repr

>      basic_repr (flds=None)

*Minimal `__repr__`*

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.

``` python
class SomeClass: __repr__=basic_repr()
repr(SomeClass())
```

    '<__main__.SomeClass>'

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.

``` python
class SomeClass:
    a=1
    b='foo'
    __repr__=basic_repr('a,b')
    __name__='some-class'

repr(SomeClass())
```

    "__main__.SomeClass(a=1, b='foo')"

``` python
class AnotherClass:
    c=SomeClass()
    d='bar'
    __repr__=basic_repr(['c', 'd'])

repr(AnotherClass())
```

    "__main__.AnotherClass(c=__main__.SomeClass(a=1, b='foo'), d='bar')"

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L58"
target="_blank" style="float:right; font-size:smaller">source</a>

### is_array

>      is_array (x)

*`True` if `x` supports `__array__` or `iloc`*

``` python
is_array(np.array(1)),is_array([1])
```

    (True, False)

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L63"
target="_blank" style="float:right; font-size:smaller">source</a>

### listify

>      listify (o=None, *rest, use_list=False, match=None)

*Convert `o` to a `list`*

Conversion is designed to “do what you mean”, e.g:

``` python
test_eq(listify('hi'), ['hi'])
test_eq(listify(b'hi'), [b'hi'])
test_eq(listify(array(1)), [array(1)])
test_eq(listify(1), [1])
test_eq(listify([1,2]), [1,2])
test_eq(listify(range(3)), [0,1,2])
test_eq(listify(None), [])
test_eq(listify(1,2), [1,2])
```

``` python
arr = np.arange(9).reshape(3,3)
listify(arr)
```

    [array([[0, 1, 2],
            [3, 4, 5],
            [6, 7, 8]])]

``` python
listify(array([1,2]))
```

    [array([1, 2])]

Generators are turned into lists too:

``` python
gen = (o for o in range(3))
test_eq(listify(gen), [0,1,2])
```

Use `match` to provide a length to match:

``` python
test_eq(listify(1,match=3), [1,1,1])
```

If `match` is a sequence, it’s length is used:

``` python
test_eq(listify(1,match=range(3)), [1,1,1])
```

If the listified item is not of length `1`, it must be the same length
as `match`:

``` python
test_eq(listify([1,1,1],match=3), [1,1,1])
test_fail(lambda: listify([1,1],match=3))
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L79"
target="_blank" style="float:right; font-size:smaller">source</a>

### tuplify

>      tuplify (o, use_list=False, match=None)

*Make `o` a tuple*

``` python
test_eq(tuplify(None),())
test_eq(tuplify([1,2,3]),(1,2,3))
test_eq(tuplify(1,match=[1,2,3]),(1,1,1))
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L84"
target="_blank" style="float:right; font-size:smaller">source</a>

### true

>      true (x)

*Test whether `x` is truthy; collections with \>0 elements are
considered `True`*

``` python
[(o,true(o)) for o in
 (array(0),array(1),array([0]),array([0,1]),1,0,'',None)]
```

    [(array(0), False),
     (array(1), True),
     (array([0]), True),
     (array([0, 1]), True),
     (1, True),
     (0, False),
     ('', False),
     (None, False)]

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L90"
target="_blank" style="float:right; font-size:smaller">source</a>

### NullType

>      NullType ()

*An object that is `False` and can be called, chained, and indexed*

``` python
bool(null.hi().there[3])
```

    False

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L100"
target="_blank" style="float:right; font-size:smaller">source</a>

### tonull

>      tonull (x)

*Convert `None` to `null`*

``` python
bool(tonull(None).hi().there[3])
```

    False

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L105"
target="_blank" style="float:right; font-size:smaller">source</a>

### get_class

>      get_class (nm, *fld_names, sup=None, doc=None, funcs=None, anno=None,
>                 **flds)

*Dynamically create a class, optionally inheriting from `sup`,
containing `fld_names`*

``` python
_t = get_class('_t', 'a', b=2, anno={'b':int})
t = _t()
test_eq(t.a, None)
test_eq(t.b, 2)
t = _t(1, b=3)
test_eq(t.a, 1)
test_eq(t.b, 3)
t = _t(1, 3)
test_eq(t.a, 1)
test_eq(t.b, 3)
test_eq(t, pickle.loads(pickle.dumps(t)))
test_eq(_t.__annotations__, {'b':int, 'a':typing.Any})
repr(t)
```

    '__main__._t(a=1, b=3)'

Most often you’ll want to call
[`mk_class`](https://fastcore.fast.ai/basics.html#mk_class), since it
adds the class to your module. See
[`mk_class`](https://fastcore.fast.ai/basics.html#mk_class) for more
details and examples of use (which also apply to
[`get_class`](https://fastcore.fast.ai/basics.html#get_class)).

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L134"
target="_blank" style="float:right; font-size:smaller">source</a>

### mk_class

>      mk_class (nm, *fld_names, sup=None, doc=None, funcs=None, mod=None,
>                anno=None, **flds)

*Create a class using
[`get_class`](https://fastcore.fast.ai/basics.html#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.

``` python
mk_class('_t', a=1, sup=dict)
t = _t()
test_eq(t.a, 1)
assert(isinstance(t,dict))
```

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.

``` python
def foo(self): return 1
mk_class('_t', 'a', sup=dict, doc='test doc', funcs=foo)

t = _t(3, b=2)
test_eq(t.a, 3)
test_eq(t.b, 2)
test_eq(t.foo(), 1)
test_eq(t.__doc__, 'test doc')
t
```

    {}

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L141"
target="_blank" style="float:right; font-size:smaller">source</a>

### wrap_class

>      wrap_class (nm, *fld_names, sup=None, doc=None, funcs=None, **flds)

*Decorator: makes function a method of a new class `nm` passing
parameters to
[`mk_class`](https://fastcore.fast.ai/basics.html#mk_class)*

``` python
@wrap_class('_t', a=2)
def bar(self,x): return x+1

t = _t()
test_eq(t.a, 2)
test_eq(t.bar(3), 4)
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L149"
target="_blank" style="float:right; font-size:smaller">source</a>

#### ignore_exceptions

>      ignore_exceptions ()

*Context manager to ignore exceptions*

``` python
with ignore_exceptions(): 
    # Exception will be ignored
    raise Exception
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L155"
target="_blank" style="float:right; font-size:smaller">source</a>

### exec_local

>      exec_local (code, var_name)

*Call `exec` on `code` and return the var `var_name`*

``` python
test_eq(exec_local("a=1", "a"), 1)
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L167"
target="_blank" style="float:right; font-size:smaller">source</a>

### risinstance

>      risinstance (types, obj=None)

*Curried `isinstance` but with args reversed*

``` python
assert risinstance(int, 1)
assert not risinstance(str, 0)
assert risinstance(int)(1)
assert not risinstance(int)(None)
```

`types` can also be strings:

``` python
assert risinstance(('str','int'), 'a')
assert risinstance('str', 'a')
assert not risinstance('int', 'a')
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L174"
target="_blank" style="float:right; font-size:smaller">source</a>

### ver2tuple

>      ver2tuple (v:str)

``` python
test_eq(ver2tuple('3.8.1'), (3,8,1))
test_eq(ver2tuple('3.1'), (3,1,0))
test_eq(ver2tuple('3.'), (3,0,0))
test_eq(ver2tuple('3'), (3,0,0))
```

## NoOp

These are used when you need a pass-through function.

------------------------------------------------------------------------

### noop

>      noop (x=None, *args, **kwargs)

*Do nothing*

``` python
noop()
test_eq(noop(1),1)
```

------------------------------------------------------------------------

### noops

>      noops (x=None, *args, **kwargs)

*Do nothing (method)*

``` python
class _t: foo=noops
test_eq(_t().foo(1),1)
```

## Infinite Lists

These lists are useful for things like padding an array or adding index
column(s) to arrays.

[`Inf`](https://fastcore.fast.ai/basics.html#inf) defines the following
properties:

- `count: itertools.count()`
- `zeros: itertools.cycle([0])`
- `ones : itertools.cycle([1])`
- `nones: itertools.cycle([None])`

``` python
test_eq([o for i,o in zip(range(5), Inf.count)],
        [0, 1, 2, 3, 4])

test_eq([o for i,o in zip(range(5), Inf.zeros)],
        [0]*5)

test_eq([o for i,o in zip(range(5), Inf.ones)],
        [1]*5)

test_eq([o for i,o in zip(range(5), Inf.nones)],
        [None]*5)
```

## Operator Functions

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L206"
target="_blank" style="float:right; font-size:smaller">source</a>

### in\_

>      in_ (x, a)

*`True` if `x in a`*

``` python
# test if element is in another
assert in_('c', ('b', 'c', 'a'))
assert in_(4, [2,3,4,5])
assert in_('t', 'fastai')
test_fail(in_('h', 'fastai'))

# use in_ as a partial
assert in_('fastai')('t')
assert in_([2,3,4,5])(4)
test_fail(in_('fastai')('h'))
```

In addition to [`in_`](https://fastcore.fast.ai/basics.html#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*.

``` python
lt(3,5),gt(3,5),is_(None,None),in_(0,[1,2]),mod(3,2)
```

    (True, False, True, False, 1)

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.

``` python
lt(5)(3),gt(5)(3),is_(None)(None),in_([1,2])(0),mod(2)(3)
```

    (True, False, True, False, 1)

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L219"
target="_blank" style="float:right; font-size:smaller">source</a>

### ret_true

>      ret_true (*args, **kwargs)

*Predicate: always `True`*

``` python
assert ret_true(1,2,3)
assert ret_true(False)
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L224"
target="_blank" style="float:right; font-size:smaller">source</a>

### ret_false

>      ret_false (*args, **kwargs)

*Predicate: always `False`*

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L229"
target="_blank" style="float:right; font-size:smaller">source</a>

### stop

>      stop (e=<class 'StopIteration'>)

*Raises exception `e` (by default `StopIteration`)*

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L234"
target="_blank" style="float:right; font-size:smaller">source</a>

### gen

>      gen (func, seq, cond=<function ret_true>)

*Like `(func(o) for o in seq if cond(func(o)))` but handles
`StopIteration`*

``` python
test_eq(gen(noop, Inf.count, lt(5)),
        range(5))
test_eq(gen(operator.neg, Inf.count, gt(-5)),
        [0,-1,-2,-3,-4])
test_eq(gen(lambda o:o if o<5 else stop(), Inf.count),
        range(5))
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L239"
target="_blank" style="float:right; font-size:smaller">source</a>

### chunked

>      chunked (it, chunk_sz=None, drop_last=False, n_chunks=None)

*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.

``` python
t = list(range(10))
test_eq(chunked(t,3),      [[0,1,2], [3,4,5], [6,7,8], [9]])
test_eq(chunked(t,3,True), [[0,1,2], [3,4,5], [6,7,8],    ])

t = map(lambda o:stop() if o==6 else o, Inf.count)
test_eq(chunked(t,3), [[0, 1, 2], [3, 4, 5]])
t = map(lambda o:stop() if o==7 else o, Inf.count)
test_eq(chunked(t,3), [[0, 1, 2], [3, 4, 5], [6]])

t = np.arange(10)
test_eq(chunked(t,3),      [[0,1,2], [3,4,5], [6,7,8], [9]])
test_eq(chunked(t,3,True), [[0,1,2], [3,4,5], [6,7,8],    ])

test_eq(chunked([], 3),          [])
test_eq(chunked([], n_chunks=3), [])
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L250"
target="_blank" style="float:right; font-size:smaller">source</a>

### otherwise

>      otherwise (x, tst, y)

*`y if tst(x) else x`*

``` python
test_eq(otherwise(2+1, gt(3), 4), 3)
test_eq(otherwise(2+1, gt(2), 4), 4)
```

## Attribute Helpers

These functions reduce boilerplate when setting or manipulating
attributes or properties of objects.

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L255"
target="_blank" style="float:right; font-size:smaller">source</a>

### custom_dir

>      custom_dir (c, add)

*Implement custom `__dir__`, adding `add` to `cls`*

[`custom_dir`](https://fastcore.fast.ai/basics.html#custom_dir) allows
you extract the [`__dict__` property of a
class](https://stackoverflow.com/questions/19907442/explain-dict-attribute)
and appends the list `add` to it.

``` python
class _T: 
    def f(): pass

s = custom_dir(_T(), add=['foo', 'bar'])
assert {'foo', 'bar', 'f'}.issubset(s)
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L260"
target="_blank" style="float:right; font-size:smaller">source</a>

### AttrDict

*`dict` subclass that also provides access to keys as attrs*

``` python
d = AttrDict(a=1,b="two")
test_eq(d.a, 1)
test_eq(d['b'], 'two')
test_eq(d.get('c','nope'), 'nope')
d.b = 2
test_eq(d.b, 2)
test_eq(d['b'], 2)
d['b'] = 3
test_eq(d['b'], 3)
test_eq(d.b, 3)
assert 'a' in dir(d)
```

[`AttrDict`](https://fastcore.fast.ai/basics.html#attrdict) will pretty
print in Jupyter Notebooks:

``` python
_test_dict = {'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]}}
AttrDict(_test_dict)
```

``` json
{ '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]}}
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L269"
target="_blank" style="float:right; font-size:smaller">source</a>

### AttrDictDefault

>      AttrDictDefault (*args, default_=None, **kwargs)

*[`AttrDict`](https://fastcore.fast.ai/basics.html#attrdict) subclass
that returns `None` for missing attrs*

``` python
d = AttrDictDefault(a=1,b="two", default_='nope')
test_eq(d.a, 1)
test_eq(d['b'], 'two')
test_eq(d.c, 'nope')
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L278"
target="_blank" style="float:right; font-size:smaller">source</a>

### NS

*`SimpleNamespace` subclass that also adds `iter` and `dict` support*

This is very similar to
[`AttrDict`](https://fastcore.fast.ai/basics.html#attrdict), but since
it starts with `SimpleNamespace`, it has some differences in behavior.
You can use it just like `SimpleNamespace`:

``` python
d = NS(**_test_dict)
d
```

    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:

``` python
d['a']
```

    1

…and iterate t:

``` python
list(d)
```

    ['a', 'b', 'c', 'd', 'e', 'f']

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L285"
target="_blank" style="float:right; font-size:smaller">source</a>

### get_annotations_ex

>      get_annotations_ex (obj, globals=None, locals=None)

*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`](https://fastcore.fast.ai/basics.html#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.

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L332"
target="_blank" style="float:right; font-size:smaller">source</a>

### eval_type

>      eval_type (t, glb, loc)

*`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`:

``` python
class _T2a: pass
def func(a: _T2a): pass
ann,glb,loc = get_annotations_ex(func)

eval_type(ann['a'], glb, loc)
```

    __main__._T2a

`|` is supported for defining `Union` types when using
[`eval_type`](https://fastcore.fast.ai/basics.html#eval_type) even for
python versions prior to 3.9:

``` python
class _T2b: pass
def func(a: _T2a|_T2b): pass
ann,glb,loc = get_annotations_ex(func)

eval_type(ann['a'], glb, loc)
```

    typing.Union[__main__._T2a, __main__._T2b]

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L345"
target="_blank" style="float:right; font-size:smaller">source</a>

### type_hints

>      type_hints (f)

*Like `typing.get_type_hints` but returns `{}` if not allowed type*

Below is a list of allowed types for type hints in python:

``` python
list(typing._allowed_types)
```

    [function,
     builtin_function_or_method,
     method,
     module,
     wrapper_descriptor,
     method-wrapper,
     method_descriptor]

For example, type `func` is allowed so
[`type_hints`](https://fastcore.fast.ai/basics.html#type_hints) returns
the same value as `typing.get_hints`:

``` python
def f(a:int)->bool: ... # a function with type hints (allowed)
exp = {'a':int,'return':bool}
test_eq(type_hints(f), typing.get_type_hints(f))
test_eq(type_hints(f), exp)
```

However, `class` is not an allowed type, so
[`type_hints`](https://fastcore.fast.ai/basics.html#type_hints) returns
`{}`:

``` python
class _T:
    def __init__(self, a:int=0)->bool: ...
assert not type_hints(_T)
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L352"
target="_blank" style="float:right; font-size:smaller">source</a>

### annotations

>      annotations (o)

*Annotations for `o`, or `type(o)`*

This supports a wider range of situations than
[`type_hints`](https://fastcore.fast.ai/basics.html#type_hints), by
checking `type()` and `__init__` for annotations too:

``` python
for o in _T,_T(),_T.__init__,f: test_eq(annotations(o), exp)
assert not annotations(int)
assert not annotations(print)
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L362"
target="_blank" style="float:right; font-size:smaller">source</a>

### anno_ret

>      anno_ret (func)

*Get the return annotation of `func`*

``` python
def f(x) -> float: return x
test_eq(anno_ret(f), float)

def f(x) -> typing.Tuple[float,float]: return x
assert anno_ret(f)==typing.Tuple[float,float]
```

If your return annotation is `None`,
[`anno_ret`](https://fastcore.fast.ai/basics.html#anno_ret) will return
`NoneType` (and not `None`):

``` python
def f(x) -> None: return x

test_eq(anno_ret(f), NoneType)
assert anno_ret(f) is not None # returns NoneType instead of None
```

If your function does not have a return type, or if you pass in `None`
instead of a function, then
[`anno_ret`](https://fastcore.fast.ai/basics.html#anno_ret) returns
`None`:

``` python
def f(x): return x

test_eq(anno_ret(f), None)
test_eq(anno_ret(None), None) # instead of passing in a func, pass in None
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L369"
target="_blank" style="float:right; font-size:smaller">source</a>

### signature_ex

>      signature_ex (obj, eval_str:bool=False)

*Backport of `inspect.signature(..., eval_str=True` to \<py310*

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L386"
target="_blank" style="float:right; font-size:smaller">source</a>

### union2tuple

>      union2tuple (t)

``` python
test_eq(union2tuple(Union[int,str]), (int,str))
test_eq(union2tuple(int), int)
assert union2tuple(Tuple[int,str])==Tuple[int,str]
test_eq(union2tuple((int,str)), (int,str))
if UnionType: test_eq(union2tuple(int|str), (int,str))
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L392"
target="_blank" style="float:right; font-size:smaller">source</a>

### argnames

>      argnames (f, frame=False)

*Names of arguments to function or frame `f`*

``` python
test_eq(argnames(f), ['x'])
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L398"
target="_blank" style="float:right; font-size:smaller">source</a>

### with_cast

>      with_cast (f)

*Decorator which uses any parameter annotations as preprocessing
functions*

``` python
@with_cast
def _f(a, b:Path, c:str='', d=0): return (a,b,c,d)

test_eq(_f(1, '.', 3), (1,Path('.'),'3',0))
test_eq(_f(1, '.'), (1,Path('.'),'',0))

@with_cast
def _g(a:int=0)->str: return a

test_eq(_g(4.0), '4')
test_eq(_g(4.4), '4')
test_eq(_g(2), '2')
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L424"
target="_blank" style="float:right; font-size:smaller">source</a>

### store_attr

>      store_attr (names=None, but='', cast=False, store_args=None, **attrs)

*Store params named in comma-separated `names` from calling context into
attrs in `self`*

In it’s most basic form, you can use
[`store_attr`](https://fastcore.fast.ai/basics.html#store_attr) to
shorten code like this:

``` python
class T:
    def __init__(self, a,b,c): self.a,self.b,self.c = a,b,c
```

…to this:

``` python
class T:
    def __init__(self, a,b,c): store_attr('a,b,c', self)
```

This class behaves as if we’d used the first form:

``` python
t = T(1,c=2,b=3)
assert t.a==1 and t.b==3 and t.c==2
```

In addition, it stores the attrs as a `dict` in `__stored_args__`, which
you can use for display, logging, and so forth.

``` python
test_eq(t.__stored_args__, {'a':1, 'b':3, 'c':2})
```

Since you normally want to use the first argument (often called `self`)
for storing attributes, it’s optional:

``` python
class T:
    def __init__(self, a,b,c:str): store_attr('a,b,c')

t = T(1,c=2,b=3)
assert t.a==1 and t.b==3 and t.c==2
```

With `cast=True` any parameter annotations will be used as preprocessing
functions for the corresponding arguments:

``` python
class T:
    def __init__(self, a:listify, b, c:str): store_attr('a,b,c', cast=True)

t = T(1,c=2,b=3)
assert t.a==[1] and t.b==3 and t.c=='2'
```

You can inherit from a class using
[`store_attr`](https://fastcore.fast.ai/basics.html#store_attr), and
just call it again to add in any new attributes added in the derived
class:

``` python
class T2(T):
    def __init__(self, d, **kwargs):
        super().__init__(**kwargs)
        store_attr('d')

t = T2(d=1,a=2,b=3,c=4)
assert t.a==2 and t.b==3 and t.c==4 and t.d==1
```

You can skip passing a list of attrs to store. In this case, all
arguments passed to the method are stored:

``` python
class T:
    def __init__(self, a,b,c): store_attr()

t = T(1,c=2,b=3)
assert t.a==1 and t.b==3 and t.c==2
```

``` python
class T4(T):
    def __init__(self, d, **kwargs):
        super().__init__(**kwargs)
        store_attr()

t = T4(4, a=1,c=2,b=3)
assert t.a==1 and t.b==3 and t.c==2 and t.d==4
```

``` python
class T4:
    def __init__(self, *, a: int, b: float = 1):
        store_attr()
        
t = T4(a=3)
assert t.a==3 and t.b==1
t = T4(a=3, b=2)
assert t.a==3 and t.b==2
```

You can skip some attrs by passing `but`:

``` python
class T:
    def __init__(self, a,b,c): store_attr(but='a')

t = T(1,c=2,b=3)
assert t.b==3 and t.c==2
assert not hasattr(t,'a')
```

You can also pass keywords to
[`store_attr`](https://fastcore.fast.ai/basics.html#store_attr), which
is identical to setting the attrs directly, but also stores them in
`__stored_args__`.

``` python
class T:
    def __init__(self): store_attr(a=1)

t = T()
assert t.a==1
```

You can also use store_attr inside functions.

``` python
def create_T(a, b):
    t = SimpleNamespace()
    store_attr(self=t)
    return t

t = create_T(a=1, b=2)
assert t.a==1 and t.b==2
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L442"
target="_blank" style="float:right; font-size:smaller">source</a>

### attrdict

>      attrdict (o, *ks, default=None)

*Dict from each `k` in `ks` to `getattr(o,k)`*

``` python
class T:
    def __init__(self, a,b,c): store_attr()

t = T(1,c=2,b=3)
test_eq(attrdict(t,'b','c'), {'b':3, 'c':2})
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L447"
target="_blank" style="float:right; font-size:smaller">source</a>

### properties

>      properties (cls, *ps)

*Change attrs in `cls` with names in `ps` to properties*

``` python
class T:
    def a(self): return 1
    def b(self): return 2
properties(T,'a')

test_eq(T().a,1)
test_eq(T().b(),2)
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L457"
target="_blank" style="float:right; font-size:smaller">source</a>

### camel2words

>      camel2words (s, space=' ')

*Convert CamelCase to ‘spaced words’*

``` python
test_eq(camel2words('ClassAreCamel'), 'Class Are Camel')
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L462"
target="_blank" style="float:right; font-size:smaller">source</a>

### camel2snake

>      camel2snake (name)

*Convert CamelCase to snake_case*

``` python
test_eq(camel2snake('ClassAreCamel'), 'class_are_camel')
test_eq(camel2snake('Already_Snake'), 'already__snake')
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L468"
target="_blank" style="float:right; font-size:smaller">source</a>

### snake2camel

>      snake2camel (s)

*Convert snake_case to CamelCase*

``` python
test_eq(snake2camel('a_b_cc'), 'ABCc')
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L473"
target="_blank" style="float:right; font-size:smaller">source</a>

### class2attr

>      class2attr (cls_name)

*Return the snake-cased name of the class; strip ending `cls_name` if it
exists.*

``` python
class Parent:
    @property
    def name(self): return class2attr(self, 'Parent')

class ChildOfParent(Parent): pass
class ParentChildOf(Parent): pass

p = Parent()
cp = ChildOfParent()
cp2 = ParentChildOf()

test_eq(p.name, 'parent')
test_eq(cp.name, 'child_of')
test_eq(cp2.name, 'parent_child_of')
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L478"
target="_blank" style="float:right; font-size:smaller">source</a>

### getcallable

>      getcallable (o, attr)

*Calls `getattr` with a default of `noop`*

``` python
class Math:
    def addition(self,a,b): return a+b

m = Math()

test_eq(getcallable(m, "addition")(a=1,b=2), 3)
test_eq(getcallable(m, "subtraction")(a=1,b=2), None)
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L483"
target="_blank" style="float:right; font-size:smaller">source</a>

### getattrs

>      getattrs (o, *attrs, default=None)

*List of all `attrs` in `o`*

``` python
from fractions import Fraction
```

``` python
getattrs(Fraction(1,2), 'numerator', 'denominator')
```

    [1, 2]

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L488"
target="_blank" style="float:right; font-size:smaller">source</a>

### hasattrs

>      hasattrs (o, attrs)

*Test whether `o` contains all `attrs`*

``` python
assert hasattrs(1,('imag','real'))
assert not hasattrs(1,('imag','foo'))
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L493"
target="_blank" style="float:right; font-size:smaller">source</a>

### setattrs

>      setattrs (dest, flds, src)

``` python
d = dict(a=1,bb="2",ignore=3)
o = SimpleNamespace()
setattrs(o, "a,bb", d)
test_eq(o.a, 1)
test_eq(o.bb, "2")
```

``` python
d = SimpleNamespace(a=1,bb="2",ignore=3)
o = SimpleNamespace()
setattrs(o, "a,bb", d)
test_eq(o.a, 1)
test_eq(o.bb, "2")
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L499"
target="_blank" style="float:right; font-size:smaller">source</a>

### try_attrs

>      try_attrs (obj, *attrs)

*Return first attr that exists in `obj`*

``` python
test_eq(try_attrs(1, 'real'), 1)
test_eq(try_attrs(1, 'foobar', 'real'), 1)
```

## Attribute Delegation

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L507"
target="_blank" style="float:right; font-size:smaller">source</a>

### GetAttrBase

>      GetAttrBase ()

*Basic delegation of
[`__getattr__`](https://fastcore.fast.ai/xml.html#__getattr__) and
`__dir__`*

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L516"
target="_blank" style="float:right; font-size:smaller">source</a>

#### GetAttr

>      GetAttr ()

*Inherit from this to have all attr accesses in `self._xtra` passed down
to `self.default`*

Inherit from [`GetAttr`](https://fastcore.fast.ai/basics.html#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](https://www.fast.ai/2019/08/06/delegation/).

You can customise the behaviour of
[`GetAttr`](https://fastcore.fast.ai/basics.html#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

To illuminate the utility of
[`GetAttr`](https://fastcore.fast.ai/basics.html#getattr), suppose we
have the following two classes, `_WebPage` which is a superclass of
`_ProductPage`, which we wish to compose like so:

``` python
class _WebPage:
    def __init__(self, title, author="Jeremy"):
        self.title,self.author = title,author

class _ProductPage:
    def __init__(self, page, price): self.page,self.price = page,price
        
page = _WebPage('Soap', author="Sylvain")
p = _ProductPage(page, 15.0)
```

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`](https://fastcore.fast.ai/basics.html#getattr), of course!
First, we subclass
[`GetAttr`](https://fastcore.fast.ai/basics.html#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:

``` python
class _ProductPage(GetAttr):
    def __init__(self, page, price): self.default,self.price = page,price #self.default allows you to access page directly.

p = _ProductPage(page, 15.0)
```

Now, we can access the `author` attribute directly from the instance:

``` python
test_eq(p.author, 'Sylvain')
```

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`:

``` python
class _C(GetAttr):
    _default = '_data' # use different component name; `self._data` rather than `self.default`
    def __init__(self,a): self._data = a
    def foo(self): noop

t = _C('Hi')
test_eq(t._data, 'Hi') 
test_fail(lambda: t.default) # we no longer have self.default
test_eq(t.lower(), 'hi')
test_eq(t.upper(), 'HI')
assert 'lower' in dir(t)
assert 'upper' in dir(t)
```

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()`:

``` python
class _C(GetAttr):
    # allow all attributes and methods to get passed to `self.default` (by leaving _xtra=None)
    def __init__(self,a): self.default = a
    def foo(self): noop

t = _C('Hi')
test_eq(t.lower(), 'hi')
test_eq(t.upper(), 'HI')
assert 'lower' in dir(t)
assert 'upper' in dir(t)
```

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`:

``` python
class _C(GetAttr):
    _xtra = ['lower'] # specify which attributes get passed to `self.default`
    def __init__(self,a): self.default = a
    def foo(self): noop

t = _C('Hi')
test_eq(t.default, 'Hi')
test_eq(t.lower(), 'hi')
test_fail(lambda: t.upper()) # upper wasn't in _xtra, so it isn't available to be called
assert 'lower' in dir(t)
assert 'upper' not in dir(t)
```

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:

``` python
class _C(GetAttr):
    _default = 'data' # use a bad component name; i.e. self.data does not exist
    def __init__(self,a): self.default = a
    def foo(self): noop
        
# TODO: should we raise an error when we create a new instance ...
t = _C('Hi')
test_eq(t.default, 'Hi')
# ... or is it enough for all GetAttr features to raise errors
test_fail(lambda: t.data)
test_fail(lambda: t.lower())
test_fail(lambda: t.upper())
test_fail(lambda: dir(t))
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L534"
target="_blank" style="float:right; font-size:smaller">source</a>

### delegate_attr

>      delegate_attr (k, to)

*Use in [`__getattr__`](https://fastcore.fast.ai/xml.html#__getattr__)
to delegate to attr `to` without inheriting from
[`GetAttr`](https://fastcore.fast.ai/basics.html#getattr)*

[`delegate_attr`](https://fastcore.fast.ai/basics.html#delegate_attr) is
a functional way to delegate attributes, and is an alternative to
[`GetAttr`](https://fastcore.fast.ai/basics.html#getattr). We recommend
reading the documentation of
[`GetAttr`](https://fastcore.fast.ai/basics.html#getattr) for more
details around delegation.

You can use achieve delegation when you define
[`__getattr__`](https://fastcore.fast.ai/xml.html#__getattr__) by using
[`delegate_attr`](https://fastcore.fast.ai/basics.html#delegate_attr):

``` python
class _C:
    def __init__(self, o): self.o = o # self.o corresponds to the `to` argument in delegate_attr.
    def __getattr__(self, k): return delegate_attr(self, k, to='o')
    

t = _C('HELLO') # delegates to a string
test_eq(t.lower(), 'hello')

t = _C(np.array([5,4,3])) # delegates to a numpy array
test_eq(t.sum(), 12)

t = _C(pd.DataFrame({'a': [1,2], 'b': [3,4]})) # delegates to a pandas.DataFrame
test_eq(t.b.max(), 4)
```

## Extensible Types

[`ShowPrint`](https://fastcore.fast.ai/basics.html#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`](https://fastcore.fast.ai/basics.html#int),
[`Float`](https://fastcore.fast.ai/basics.html#float), and
[`Str`](https://fastcore.fast.ai/basics.html#str) extend `int`, `float`
and `str` respectively by adding an additional `show` method by
inheriting from
[`ShowPrint`](https://fastcore.fast.ai/basics.html#showprint).

The code for [`Int`](https://fastcore.fast.ai/basics.html#int) is shown
below:

Examples:

``` python
Int(0).show()
Float(2.0).show()
Str('Hello').show()
```

    0
    2.0
    Hello

## Collection functions

Functions that manipulate popular python collections.

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L559"
target="_blank" style="float:right; font-size:smaller">source</a>

### partition

>      partition (coll, f)

*Partition a collection by a predicate*

``` python
ts,fs = partition(range(10), mod(2))
test_eq(fs, [0,2,4,6,8])
test_eq(ts, [1,3,5,7,9])
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L569"
target="_blank" style="float:right; font-size:smaller">source</a>

### flatten

>      flatten (o)

*Concatenate all collections and items as a generator*

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L577"
target="_blank" style="float:right; font-size:smaller">source</a>

### concat

>      concat (colls)

*Concatenate all collections and items as a list*

``` python
concat([(o for o in range(2)),[2,3,4], 5])
```

    [0, 1, 2, 3, 4, 5]

``` python
concat([["abc", "xyz"], ["foo", "bar"]])
```

    ['abc', 'xyz', 'foo', 'bar']

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L582"
target="_blank" style="float:right; font-size:smaller">source</a>

### strcat

>      strcat (its, sep:str='')

*Concatenate stringified items `its`*

``` python
test_eq(strcat(['a',2]), 'a2')
test_eq(strcat(['a',2], ';'), 'a;2')
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L587"
target="_blank" style="float:right; font-size:smaller">source</a>

### detuplify

>      detuplify (x)

*If `x` is a tuple with one thing, extract it*

``` python
test_eq(detuplify(()),None)
test_eq(detuplify([1]),1)
test_eq(detuplify([1,2]), [1,2])
test_eq(detuplify(np.array([[1,2]])), np.array([[1,2]]))
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L592"
target="_blank" style="float:right; font-size:smaller">source</a>

### replicate

>      replicate (item, match)

*Create tuple of `item` copied `len(match)` times*

``` python
t = [1,1]
test_eq(replicate([1,2], t),([1,2],[1,2]))
test_eq(replicate(1, t),(1,1))
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L597"
target="_blank" style="float:right; font-size:smaller">source</a>

### setify

>      setify (o)

*Turn any list like-object into a set.*

``` python
# test
test_eq(setify(None),set())
test_eq(setify('abc'),{'abc'})
test_eq(setify([1,2,2]),{1,2})
test_eq(setify(range(0,3)),{0,1,2})
test_eq(setify({1,2}),{1,2})
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L602"
target="_blank" style="float:right; font-size:smaller">source</a>

### merge

>      merge (*ds)

*Merge all dictionaries in `ds`*

``` python
test_eq(merge(), {})
test_eq(merge(dict(a=1,b=2)), dict(a=1,b=2))
test_eq(merge(dict(a=1,b=2), dict(b=3,c=4), None), dict(a=1, b=3, c=4))
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L686"
target="_blank" style="float:right; font-size:smaller">source</a>

### range_of

>      range_of (x)

*All indices of collection `x` (i.e. `list(range(len(x)))`)*

``` python
test_eq(range_of([1,1,1,1]), [0,1,2,3])
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L612"
target="_blank" style="float:right; font-size:smaller">source</a>

### groupby

>      groupby (x, key, val=<function noop>)

*Like `itertools.groupby` but doesn’t need to be sorted, and isn’t lazy,
plus some extensions*

``` python
test_eq(groupby('aa ab bb'.split(), itemgetter(0)), {'a':['aa','ab'], 'b':['bb']})
```

Here’s an example of how to *invert* a grouping, using an `int` as `key`
(which uses `itemgetter`; passing a `str` will use `attrgetter`), and
using a `val` function:

``` python
d = {0: [1, 3, 7], 2: [3], 3: [5], 4: [8], 5: [4], 7: [5]}
groupby(((o,k) for k,v in d.items() for o in v), 0, 1)
```

    {1: [0], 3: [0, 2], 7: [0], 5: [3, 7], 8: [4], 4: [5]}

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L623"
target="_blank" style="float:right; font-size:smaller">source</a>

### last_index

>      last_index (x, o)

*Finds the last index of occurence of `x` in `o` (returns -1 if no
occurence)*

``` python
test_eq(last_index(9, [1, 2, 9, 3, 4, 9, 10]), 5)
test_eq(last_index(6, [1, 2, 9, 3, 4, 9, 10]), -1)
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L629"
target="_blank" style="float:right; font-size:smaller">source</a>

### filter_dict

>      filter_dict (d, func)

*Filter a `dict` using `func`, applied to keys and values*

``` python
letters = {o:chr(o) for o in range(65,73)}
letters
```

    {65: 'A', 66: 'B', 67: 'C', 68: 'D', 69: 'E', 70: 'F', 71: 'G', 72: 'H'}

``` python
filter_dict(letters, lambda k,v: k<67 or v in 'FG')
```

    {65: 'A', 66: 'B', 70: 'F', 71: 'G'}

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L634"
target="_blank" style="float:right; font-size:smaller">source</a>

### filter_keys

>      filter_keys (d, func)

*Filter a `dict` using `func`, applied to keys*

``` python
filter_keys(letters, lt(67))
```

    {65: 'A', 66: 'B'}

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L639"
target="_blank" style="float:right; font-size:smaller">source</a>

### filter_values

>      filter_values (d, func)

*Filter a `dict` using `func`, applied to values*

``` python
filter_values(letters, in_('FG'))
```

    {70: 'F', 71: 'G'}

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/foundation.py#L70"
target="_blank" style="float:right; font-size:smaller">source</a>

### cycle

>      cycle (o)

*Like `itertools.cycle` except creates list of `None`s if `o` is empty*

``` python
test_eq(itertools.islice(cycle([1,2,3]),5), [1,2,3,1,2])
test_eq(itertools.islice(cycle([]),3), [None]*3)
test_eq(itertools.islice(cycle(None),3), [None]*3)
test_eq(itertools.islice(cycle(1),3), [1,1,1])
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/foundation.py#L76"
target="_blank" style="float:right; font-size:smaller">source</a>

### zip_cycle

>      zip_cycle (x, *args)

*Like `itertools.zip_longest` but
[`cycle`](https://fastcore.fast.ai/foundation.html#cycle)s through
elements of all but first argument*

``` python
test_eq(zip_cycle([1,2,3,4],list('abc')), [(1, 'a'), (2, 'b'), (3, 'c'), (4, 'a')])
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L655"
target="_blank" style="float:right; font-size:smaller">source</a>

### sorted_ex

>      sorted_ex (iterable, key=None, reverse=False)

*Like `sorted`, but if key is str use `attrgetter`; if int use
`itemgetter`*

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L663"
target="_blank" style="float:right; font-size:smaller">source</a>

### not\_

>      not_ (f)

*Create new function that negates result of `f`*

``` python
def f(a): return a>0
test_eq(f(1),True)
test_eq(not_(f)(1),False)
test_eq(not_(f)(a=-1),True)
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L669"
target="_blank" style="float:right; font-size:smaller">source</a>

### argwhere

>      argwhere (iterable, f, negate=False, **kwargs)

*Like [`filter_ex`](https://fastcore.fast.ai/basics.html#filter_ex), but
return indices for matching items*

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L676"
target="_blank" style="float:right; font-size:smaller">source</a>

### filter_ex

>      filter_ex (iterable, f=<function noop>, negate=False, gen=False,
>                 **kwargs)

*Like `filter`, but passing `kwargs` to `f`, defaulting `f` to `noop`,
and adding `negate` and
[`gen`](https://fastcore.fast.ai/basics.html#gen)*

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L686"
target="_blank" style="float:right; font-size:smaller">source</a>

### range_of

>      range_of (a, b=None, step=None)

*All indices of collection `a`, if `a` is a collection, otherwise
`range`*

``` python
test_eq(range_of([1,1,1,1]), [0,1,2,3])
test_eq(range_of(4), [0,1,2,3])
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L692"
target="_blank" style="float:right; font-size:smaller">source</a>

### renumerate

>      renumerate (iterable, start=0)

*Same as `enumerate`, but returns index as 2nd element instead of 1st*

``` python
test_eq(renumerate('abc'), (('a',0),('b',1),('c',2)))
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L697"
target="_blank" style="float:right; font-size:smaller">source</a>

### first

>      first (x, f=None, negate=False, **kwargs)

*First element of `x`, optionally filtered by `f`, or None if missing*

``` python
test_eq(first(['a', 'b', 'c', 'd', 'e']), 'a')
test_eq(first([False]), False)
test_eq(first([False], noop), None)
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L704"
target="_blank" style="float:right; font-size:smaller">source</a>

### only

>      only (o)

*Return the only item of `o`, raise if `o` doesn’t have exactly one
item*

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L714"
target="_blank" style="float:right; font-size:smaller">source</a>

### nested_attr

>      nested_attr (o, attr, default=None)

*Same as `getattr`, but if `attr` includes a `.`, then looks inside
nested objects*

``` python
a = SimpleNamespace(b=(SimpleNamespace(c=1)))
test_eq(nested_attr(a, 'b.c'), getattr(getattr(a, 'b'), 'c'))
test_eq(nested_attr(a, 'b.d'), None)
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L722"
target="_blank" style="float:right; font-size:smaller">source</a>

### nested_setdefault

>      nested_setdefault (o, attr, default)

*Same as `setdefault`, but if `attr` includes a `.`, then looks inside
nested objects*

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L729"
target="_blank" style="float:right; font-size:smaller">source</a>

### nested_callable

>      nested_callable (o, attr)

*Same as
[`nested_attr`](https://fastcore.fast.ai/basics.html#nested_attr) but if
not found will return `noop`*

``` python
a = SimpleNamespace(b=(SimpleNamespace(c=1)))
test_eq(nested_callable(a, 'b.c'), getattr(getattr(a, 'b'), 'c'))
test_eq(nested_callable(a, 'b.d'), noop)
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L752"
target="_blank" style="float:right; font-size:smaller">source</a>

### nested_idx

>      nested_idx (coll, *idxs)

*Index into nested collections, dicts, etc, with `idxs`*

``` python
a = {'b':[1,{'c':2}]}
test_eq(nested_idx(a, 'nope'), None)
test_eq(nested_idx(a, 'nope', 'nup'), None)
test_eq(nested_idx(a, 'b', 3), None)
test_eq(nested_idx(a), a)
test_eq(nested_idx(a, 'b'), [1,{'c':2}])
test_eq(nested_idx(a, 'b', 1), {'c':2})
test_eq(nested_idx(a, 'b', 1, 'c'), 2)
```

``` python
a = SimpleNamespace(b=[1,{'c':2}])
test_eq(nested_idx(a, 'nope'), None)
test_eq(nested_idx(a, 'nope', 'nup'), None)
test_eq(nested_idx(a, 'b', 3), None)
test_eq(nested_idx(a), a)
test_eq(nested_idx(a, 'b'), [1,{'c':2}])
test_eq(nested_idx(a, 'b', 1), {'c':2})
test_eq(nested_idx(a, 'b', 1, 'c'), 2)
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L760"
target="_blank" style="float:right; font-size:smaller">source</a>

### set_nested_idx

>      set_nested_idx (coll, value, *idxs)

*Set value indexed like \`nested_idx*

``` python
set_nested_idx(a, 3, 'b', 0)
test_eq(nested_idx(a, 'b', 0), 3)
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L766"
target="_blank" style="float:right; font-size:smaller">source</a>

### val2idx

>      val2idx (x)

*Dict from value to index*

``` python
test_eq(val2idx([1,2,3]), {3:2,1:0,2:1})
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L771"
target="_blank" style="float:right; font-size:smaller">source</a>

### uniqueify

>      uniqueify (x, sort=False, bidir=False, start=None)

*Unique elements in `x`, optional `sort`, optional return reverse
correspondence, optional prepend with elements.*

``` python
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})
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L780"
target="_blank" style="float:right; font-size:smaller">source</a>

### loop_first_last

>      loop_first_last (values)

*Iterate and generate a tuple with a flag for first and last value.*

``` python
test_eq(loop_first_last(range(3)), [(True,False,0), (False,False,1), (False,True,2)])
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L792"
target="_blank" style="float:right; font-size:smaller">source</a>

### loop_first

>      loop_first (values)

*Iterate and generate a tuple with a flag for first value.*

``` python
test_eq(loop_first(range(3)), [(True,0), (False,1), (False,2)])
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L797"
target="_blank" style="float:right; font-size:smaller">source</a>

### loop_last

>      loop_last (values)

*Iterate and generate a tuple with a flag for last value.*

``` python
test_eq(loop_last(range(3)), [(False,0), (False,1), (True,2)])
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L802"
target="_blank" style="float:right; font-size:smaller">source</a>

### first_match

>      first_match (lst, f, default=None)

*First element of `lst` matching predicate `f`, or `default` if none*

``` python
a = [0,2,4,5,6,7,10]
test_eq(first_match(a, lambda o:o%2), 3)
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L807"
target="_blank" style="float:right; font-size:smaller">source</a>

### last_match

>      last_match (lst, f, default=None)

*Last element of `lst` matching predicate `f`, or `default` if none*

``` python
test_eq(last_match(a, lambda o:o%2), 5)
```

## fastuple

A tuple with extended functionality.

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L826"
target="_blank" style="float:right; font-size:smaller">source</a>

#### fastuple

>      fastuple (x=None, *rest)

*A `tuple` with elementwise ops and more friendly **init** behavior*

#### Friendly init behavior

Common failure modes when trying to initialize a tuple in python:

``` py
tuple(3)
> TypeError: 'int' object is not iterable
```

or

``` py
tuple(3, 4)
> TypeError: tuple expected at most 1 arguments, got 2
```

However, [`fastuple`](https://fastcore.fast.ai/basics.html#fastuple)
allows you to define tuples like this and in the usual way:

``` python
test_eq(fastuple(3), (3,))
test_eq(fastuple(3,4), (3, 4))
test_eq(fastuple((3,4)), (3, 4))
```

#### Elementwise operations

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L845"
target="_blank" style="float:right; font-size:smaller">source</a>

##### fastuple.add

>      fastuple.add (*args)

*`+` is already defined in `tuple` for concat, so use `add` instead*

``` python
test_eq(fastuple.add((1,1),(2,2)), (3,3))
test_eq_type(fastuple(1,1).add(2), fastuple(3,3))
test_eq(fastuple('1','2').add('2'), fastuple('12','22'))
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L841"
target="_blank" style="float:right; font-size:smaller">source</a>

##### fastuple.mul

>      fastuple.mul (*args)

*`*` is already defined in `tuple` for replicating, so use `mul`
instead*

``` python
test_eq_type(fastuple(1,1).mul(2), fastuple(2,2))
```

#### Other Elementwise Operations

Additionally, the following elementwise operations are available: -
`le`: less than or equal - `eq`: equal - `gt`: greater than - `min`:
minimum of

``` python
test_eq(fastuple(3,1).le(1), (False, True))
test_eq(fastuple(3,1).eq(1), (False, True))
test_eq(fastuple(3,1).gt(1), (True, False))
test_eq(fastuple(3,1).min(2), (2,1))
```

You can also do other elementwise operations like negate a
[`fastuple`](https://fastcore.fast.ai/basics.html#fastuple), or subtract
two [`fastuple`](https://fastcore.fast.ai/basics.html#fastuple)s:

``` python
test_eq(-fastuple(1,2), (-1,-2))
test_eq(~fastuple(1,0,1), (False,True,False))

test_eq(fastuple(1,1)-fastuple(2,2), (-1,-1))
```

``` python
test_eq(type(fastuple(1)), fastuple)
test_eq_type(fastuple(1,2), fastuple(1,2))
test_ne(fastuple(1,2), fastuple(1,3))
test_eq(fastuple(), ())
```

## Functions on Functions

Utilities for functional programming or for defining, modifying, or
debugging functions.

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L872"
target="_blank" style="float:right; font-size:smaller">source</a>

### bind

>      bind (func, *pargs, **pkwargs)

*Same as `partial`, except you can use `arg0` `arg1` etc param
placeholders*

[`bind`](https://fastcore.fast.ai/basics.html#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`](https://fastcore.fast.ai/basics.html#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.

``` python
def myfn(a,b,c,d=1,e=2): return(a,b,c,d,e)
```

In the below example we bind the positional arguments of `myfn` as
follows:

- The second input `14`, referenced by `arg1`, is substituted for the
  first positional argument.
- We supply a default value of `17` for the second positional argument.
- The first input `19`, referenced by `arg0`, is subsituted for the
  third positional argument.

``` python
test_eq(bind(myfn, arg1, 17, arg0, e=3)(19,14), (14,17,19,1,3))
```

In this next example:

- We set the default value to `17` for the first positional argument.
- The first input `19` refrenced by `arg0`, becomes the second
  positional argument.
- The second input `14` becomes the third positional argument.
- We override the default the value for named argument `e` to `3`.

``` python
test_eq(bind(myfn, 17, arg0, e=3)(19,14), (17,19,14,1,3))
```

This is an example of using
[`bind`](https://fastcore.fast.ai/basics.html#bind) like `partial` and
do not reorder any arguments:

``` python
test_eq(bind(myfn)(17,19,14), (17,19,14,1,2))
```

[`bind`](https://fastcore.fast.ai/basics.html#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:

``` python
test_eq(bind(myfn, 17,19,14,e=arg0)(3), (17,19,14,1,3))
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L887"
target="_blank" style="float:right; font-size:smaller">source</a>

### mapt

>      mapt (func, *iterables)

*Tuplified `map`*

``` python
t = [0,1,2,3]
test_eq(mapt(operator.neg, t), (0,-1,-2,-3))
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L892"
target="_blank" style="float:right; font-size:smaller">source</a>

### map_ex

>      map_ex (iterable, f, *args, gen=False, **kwargs)

*Like `map`, but use
[`bind`](https://fastcore.fast.ai/basics.html#bind), and supports `str`
and indexing*

``` python
test_eq(map_ex(t,operator.neg), [0,-1,-2,-3])
```

If `f` is a string then it is treated as a format string to create the
mapping:

``` python
test_eq(map_ex(t, '#{}#'), ['#0#','#1#','#2#','#3#'])
```

If `f` is a dictionary (or anything supporting `__getitem__`) then it is
indexed to create the mapping:

``` python
test_eq(map_ex(t, list('abcd')), list('abcd'))
```

You can also pass the same `arg` params that
[`bind`](https://fastcore.fast.ai/basics.html#bind) accepts:

``` python
def f(a=None,b=None): return b
test_eq(map_ex(t, f, b=arg0), range(4))
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L902"
target="_blank" style="float:right; font-size:smaller">source</a>

### compose

>      compose (*funcs, order=None)

*Create a function that composes all functions in `funcs`, passing along
remaining `*args` and `**kwargs` to all*

``` python
f1 = lambda o,p=0: (o*2)+p
f2 = lambda o,p=1: (o+1)/p
test_eq(f2(f1(3)), compose(f1,f2)(3))
test_eq(f2(f1(3,p=3),p=3), compose(f1,f2)(3,p=3))
test_eq(f2(f1(3,  3),  3), compose(f1,f2)(3,  3))

f1.order = 1
test_eq(f1(f2(3)), compose(f1,f2, order="order")(3))
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L914"
target="_blank" style="float:right; font-size:smaller">source</a>

### maps

>      maps (*args, retain=<function noop>)

*Like `map`, except funcs are composed first*

``` python
test_eq(maps([1]), [1])
test_eq(maps(operator.neg, [1,2]), [-1,-2])
test_eq(maps(operator.neg, operator.neg, [1,2]), [1,2])
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L921"
target="_blank" style="float:right; font-size:smaller">source</a>

### partialler

>      partialler (f, *args, order=None, **kwargs)

*Like `functools.partial` but also copies over docstring*

``` python
def _f(x,a=1):
    "test func"
    return x-a
_f.order=1

f = partialler(_f, 2)
test_eq(f.order, 1)
test_eq(f(3), -1)
f = partialler(_f, a=2, order=3)
test_eq(f.__doc__, "test func")
test_eq(f.order, 3)
test_eq(f(3), _f(3,2))
```

``` python
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)
```

``` python
f = partial0(_f, 2)
test_eq(f.order, 1)
test_eq(f(3), 1) # NB: different to `partialler` example
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L930"
target="_blank" style="float:right; font-size:smaller">source</a>

### instantiate

>      instantiate (t)

*Instantiate `t` if it’s a type, otherwise do nothing*

``` python
test_eq_type(instantiate(int), 0)
test_eq_type(instantiate(1), 1)
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L938"
target="_blank" style="float:right; font-size:smaller">source</a>

### using_attr

>      using_attr (f, attr)

*Construct a function which applies `f` to the argument’s attribute
`attr`*

``` python
t = Path('/a/b.txt')
f = using_attr(str.upper, 'name')
test_eq(f(t), 'B.TXT')
```

### Self (with an *uppercase* S)

A Concise Way To Create Lambdas

This is a concise way to create lambdas that are calling methods on an
object (note the capitalization!)

`Self.sum()`, for instance, is a shortcut for `lambda o: o.sum()`.

``` python
f = Self.sum()
x = np.array([3.,1])
test_eq(f(x), 4.)

# This is equivalent to above
f = lambda o: o.sum()
x = np.array([3.,1])
test_eq(f(x), 4.)

f = Self.argmin()
arr = np.array([1,2,3,4,5])
test_eq(f(arr), arr.argmin())

f = Self.sum().is_integer()
x = np.array([3.,1])
test_eq(f(x), True)

f = Self.sum().real.is_integer()
x = np.array([3.,1])
test_eq(f(x), True)

f = Self.imag()
test_eq(f(3), 0)

f = Self[1]
test_eq(f(x), 1)
```

`Self` is also callable, which creates a function which calls any
function passed to it, using the arguments passed to `Self`:

``` python
def f(a, b=3): return a+b+2
def g(a, b=3): return a*b
fg = Self(1,b=2)
list(map(fg, [f,g]))
```

    [5, 2]

## Patching

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L986"
target="_blank" style="float:right; font-size:smaller">source</a>

### copy_func

>      copy_func (f)

*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:

``` python
import copy as cp
```

``` python
def foo(): pass
a = cp.copy(foo)
b = cp.deepcopy(foo)

a.someattr = 'hello' # since a and b point at the same object, updating a will update b
test_eq(b.someattr, 'hello')

assert a is foo and b is foo
```

However, with
[`copy_func`](https://fastcore.fast.ai/basics.html#copy_func), you can
retrieve a copy of a function without a reference to the original
object:

``` python
c = copy_func(foo) # c is an indpendent object
assert c is not foo
```

``` python
def g(x, *, y=3): return x+y
test_eq(copy_func(g)(4), 7)
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L1002"
target="_blank" style="float:right; font-size:smaller">source</a>

### patch_to

>      patch_to (cls, as_prop=False, cls_method=False)

*Decorator: add `f` to `cls`*

The `@patch_to` decorator allows you to [monkey
patch](https://stackoverflow.com/questions/5626193/what-is-monkey-patching)
a function into a class as a method:

``` python
class _T3(int): pass  

@patch_to(_T3)
def func1(self, a): return self+a

t = _T3(1) # we initialized `t` to a type int = 1
test_eq(t.func1(2), 3) # we add 2 to `t`, so 2 + 1 = 3
```

You can access instance properties in the usual way via `self`:

``` python
class _T4():
    def __init__(self, g): self.g = g
        
@patch_to(_T4)
def greet(self, x): return self.g + x
        
t = _T4('hello ') # this sets self.g = 'hello '
test_eq(t.greet('world'), 'hello world') #t.greet('world') will append 'world' to 'hello '
```

You can instead specify that the method should be a class method by
setting `cls_method=True`:

``` python
class _T5(int): attr = 3 # attr is a class attribute we will access in a later method
    
@patch_to(_T5, cls_method=True)
def func(cls, x): return cls.attr + x # you can access class attributes in the normal way

test_eq(_T5.func(4), 7)
```

Additionally you can specify that the function you want to patch should
be a class attribute with `as_prop=True`:

``` python
@patch_to(_T5, as_prop=True)
def add_ten(self): return self + 10

t = _T5(4)
test_eq(t.add_ten, 14)
```

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:

``` python
class _T6(int): pass
class _T7(int): pass

@patch_to((_T6,_T7))
def func_mult(self, a): return self*a

t = _T6(2)
test_eq(t.func_mult(4), 8)
t = _T7(2)
test_eq(t.func_mult(4), 8)
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L1024"
target="_blank" style="float:right; font-size:smaller">source</a>

### patch

>      patch (f=None, as_prop=False, cls_method=False)

*Decorator: add `f` to the first parameter’s class (based on f’s type
annotations)*

`@patch` is an alternative to `@patch_to` that allows you similarly
monkey patch class(es) by using [type
annotations](https://docs.python.org/3/library/typing.html):

``` python
class _T8(int): pass  

@patch
def func(self:_T8, a): return self+a

t = _T8(1)  # we initilized `t` to a type int = 1
test_eq(t.func(3), 4) # we add 3 to `t`, so 3 + 1 = 4
test_eq(t.func.__qualname__, '_T8.func')
```

Similarly to
[`patch_to`](https://fastcore.fast.ai/basics.html#patch_to), you can
supply a union of classes instead of a single class in your type
annotations to patch multiple classes:

``` python
class _T9(int): pass 

@patch
def func2(x:_T8|_T9, a): return x*a # will patch both _T8 and _T9

t = _T8(2)
test_eq(t.func2(4), 8)
test_eq(t.func2.__qualname__, '_T8.func2')

t = _T9(2)
test_eq(t.func2(4), 8)
test_eq(t.func2.__qualname__, '_T9.func2')
```

Just like [`patch_to`](https://fastcore.fast.ai/basics.html#patch_to)
decorator you can use `as_prop` and `cls_method` parameters with
[`patch`](https://fastcore.fast.ai/basics.html#patch) decorator:

``` python
@patch(as_prop=True)
def add_ten(self:_T5): return self + 10

t = _T5(4)
test_eq(t.add_ten, 14)
```

``` python
class _T5(int): attr = 3 # attr is a class attribute we will access in a later method
    
@patch(cls_method=True)
def func(cls:_T5, x): return cls.attr + x # you can access class attributes in the normal way

test_eq(_T5.func(4), 7)
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L1032"
target="_blank" style="float:right; font-size:smaller">source</a>

### patch_property

>      patch_property (f)

*Deprecated; use `patch(as_prop=True)` instead*

Patching `classmethod` shouldn’t affect how python’s inheritance works

``` python
class FastParent: pass

@patch(cls_method=True)
def type_cls(cls: FastParent): return cls

class FastChild(FastParent): pass

parent = FastParent()
test_eq(parent.type_cls(), FastParent)

child = FastChild()
test_eq(child.type_cls(), FastChild)
```

## Other Helpers

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L1039"
target="_blank" style="float:right; font-size:smaller">source</a>

### compile_re

>      compile_re (pat)

*Compile `pat` if it’s not None*

``` python
assert compile_re(None) is None
assert compile_re('a').match('ab')
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L1044"
target="_blank" style="float:right; font-size:smaller">source</a>

#### ImportEnum

>      ImportEnum (value, names=None, module=None, qualname=None, type=None,
>                  start=1)

*An `Enum` that can have its values imported*

``` python
_T = ImportEnum('_T', {'foobar':1, 'goobar':2})
_T.imports()
test_eq(foobar, _T.foobar)
test_eq(goobar, _T.goobar)
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L1052"
target="_blank" style="float:right; font-size:smaller">source</a>

#### StrEnum

>      StrEnum (value, names=None, module=None, qualname=None, type=None,
>               start=1)

*An [`ImportEnum`](https://fastcore.fast.ai/basics.html#importenum) that
behaves like a `str`*

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L1057"
target="_blank" style="float:right; font-size:smaller">source</a>

### str_enum

>      str_enum (name, *vals)

*Simplified creation of
[`StrEnum`](https://fastcore.fast.ai/basics.html#strenum) types*

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L1062"
target="_blank" style="float:right; font-size:smaller">source</a>

#### ValEnum

>      ValEnum (value, names=None, module=None, qualname=None, type=None,
>               start=1)

*An [`ImportEnum`](https://fastcore.fast.ai/basics.html#importenum) that
stringifies using values*

``` python
_T = str_enum('_T', 'a', 'b')
test_eq(f'{_T.a}', 'a')
test_eq(_T.a, 'a')
test_eq(list(_T.__members__), ['a','b'])
print(_T.a, _T.a.upper())
```

    a A

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L1067"
target="_blank" style="float:right; font-size:smaller">source</a>

#### Stateful

>      Stateful (*args, **kwargs)

*A base class/mixin for objects that should not serialize all their
state*

``` python
class _T(Stateful):
    def __init__(self):
        super().__init__()
        self.a=1
        self._state['test']=2

t = _T()
t2 = pickle.loads(pickle.dumps(t))
test_eq(t.a,1)
test_eq(t._state['test'],2)
test_eq(t2.a,1)
test_eq(t2._state,{})
```

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`](https://fastcore.fast.ai/basics.html#stateful) simplifies
the official Python example for [Handling Stateful
Objects](https://docs.python.org/3/library/pickle.html#handling-stateful-objects).

``` python
class TextReader(Stateful):
    """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()
```

``` python
reader = TextReader("00_test.ipynb")
print(reader.readline())
print(reader.readline())

new_reader = pickle.loads(pickle.dumps(reader))
print(reader.readline())
```

    1: {
    2: "cells": [
    3: {

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L1087"
target="_blank" style="float:right; font-size:smaller">source</a>

### NotStr

>      NotStr (s)

*Behaves like a `str`, but isn’t an instance of one*

``` python
s = NotStr("hello")
assert not isinstance(s, str)
test_eq(s, 'hello')
test_eq(s*2, 'hellohello')
test_eq(len(s), 5)
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L1104"
target="_blank" style="float:right; font-size:smaller">source</a>

#### PrettyString

*Little hack to get strings to show properly in Jupyter.*

Allow strings with special characters to render properly in Jupyter.
Without calling `print()` strings with special characters are displayed
like so:

``` python
with_special_chars='a string\nwith\nnew\nlines and\ttabs'
with_special_chars
```

    'a string\nwith\nnew\nlines and\ttabs'

We can correct this with
[`PrettyString`](https://fastcore.fast.ai/basics.html#prettystring):

``` python
PrettyString(with_special_chars)
```

    a string
    with
    new
    lines and   tabs

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L1109"
target="_blank" style="float:right; font-size:smaller">source</a>

### even_mults

>      even_mults (start, stop, n)

*Build log-stepped array from `start` to
[`stop`](https://fastcore.fast.ai/basics.html#stop) in `n` steps.*

``` python
test_eq(even_mults(2,8,3), [2,4,8])
test_eq(even_mults(2,32,5), [2,4,8,16,32])
test_eq(even_mults(2,8,1), 8)
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L1117"
target="_blank" style="float:right; font-size:smaller">source</a>

### num_cpus

>      num_cpus ()

*Get number of cpus*

``` python
num_cpus()
```

    8

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L1125"
target="_blank" style="float:right; font-size:smaller">source</a>

### add_props

>      add_props (f, g=None, n=2)

*Create properties passing each of `range(n)` to f*

``` python
class _T(): a,b = add_props(lambda i,x:i*2)

t = _T()
test_eq(t.a,0)
test_eq(t.b,2)
```

``` python
class _T(): 
    def __init__(self, v): self.v=v
    def _set(i, self, v): self.v[i] = v
    a,b = add_props(lambda i,x: x.v[i], _set)

t = _T([0,2])
test_eq(t.a,0)
test_eq(t.b,2)
t.a = t.a+1
t.b = 3
test_eq(t.a,1)
test_eq(t.b,3)
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L1134"
target="_blank" style="float:right; font-size:smaller">source</a>

### typed

>      typed (f)

*Decorator to check param and return types at runtime*

[`typed`](https://fastcore.fast.ai/basics.html#typed) validates argument
types at **runtime**. This is in contrast to
[MyPy](http://mypy-lang.org/) 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:

``` python
@typed
def discount(price:int, pct:float): 
    return (1-pct) * price

with ExceptionExpected(TypeError): discount(100.0, .1)
```

We can also optionally allow multiple types by enumarating the types in
a tuple as illustrated below:

``` python
def discount(price:int|float, pct:float): 
    return (1-pct) * price

assert 90.0 == discount(100.0, .1)
```

``` python
@typed
def foo(a:int, b:str='a'): return a
test_eq(foo(1, '2'), 1)

with ExceptionExpected(TypeError): foo(1,2)

@typed
def foo()->str: return 1
with ExceptionExpected(TypeError): foo()

@typed
def foo()->str: return '1'
assert foo()
```

[`typed`](https://fastcore.fast.ai/basics.html#typed) works with
classes, too:

``` python
class Foo:
    @typed
    def __init__(self, a:int, b: int, c:str): pass
    @typed
    def test(cls, d:str): return d

with ExceptionExpected(TypeError): Foo(1, 2, 3) 
with ExceptionExpected(TypeError): Foo(1,2, 'a string').test(10)
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L1151"
target="_blank" style="float:right; font-size:smaller">source</a>

### exec_new

>      exec_new (code)

*Execute `code` in a new environment and return it*

``` python
g = exec_new('a=1')
test_eq(g['a'], 1)
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L1159"
target="_blank" style="float:right; font-size:smaller">source</a>

### exec_import

>      exec_import (mod, sym)

*Import `sym` from `mod` in a new environment*

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L1165"
target="_blank" style="float:right; font-size:smaller">source</a>

### str2bool

>      str2bool (s)

*Case-insensitive convert string `s` too a bool
(`y`,`yes`,`t`,[`true`](https://fastcore.fast.ai/basics.html#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.

``` python
for o in "y YES t True on 1".split(): assert str2bool(o)
for o in "n no FALSE off 0".split(): assert not str2bool(o)
for o in 0,None,'',False: assert not str2bool(o)
for o in 1,True: assert str2bool(o)
```

## Notebook functions

------------------------------------------------------------------------

### ipython_shell

>      ipython_shell ()

*Same as `get_ipython` but returns `False` if not in IPython*

------------------------------------------------------------------------

### in_ipython

>      in_ipython ()

*Check if code is running in some kind of IPython environment*

------------------------------------------------------------------------

### in_colab

>      in_colab ()

*Check if the code is running in Google Colaboratory*

------------------------------------------------------------------------

### in_jupyter

>      in_jupyter ()

*Check if the code is running in a jupyter notebook*

------------------------------------------------------------------------

### in_notebook

>      in_notebook ()

*Check if the code is running in a jupyter notebook*

These variables are available as booleans in `fastcore.basics` as
`IN_IPYTHON`, `IN_JUPYTER`, `IN_COLAB` and `IN_NOTEBOOK`.

``` python
IN_IPYTHON, IN_JUPYTER, IN_COLAB, IN_NOTEBOOK
```

    (True, True, False, True)</doc>
    <doc title="fastcore.foundation" desc="The L class and helpers for it"># Foundation



## Foundational Functions

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/foundation.py#L20"
target="_blank" style="float:right; font-size:smaller">source</a>

### working_directory

>      working_directory (path)

*Change working directory to `path` and return to previous on exit.*

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/foundation.py#L28"
target="_blank" style="float:right; font-size:smaller">source</a>

### add_docs

>      add_docs (cls, cls_doc=None, **docs)

*Copy values from
[`docs`](https://fastcore.fast.ai/foundation.html#docs) to `cls`
docstrings, and confirm all public methods are documented*

[`add_docs`](https://fastcore.fast.ai/foundation.html#add_docs) allows
you to add docstrings to a class and its associated methods. This
function allows you to group docstrings together seperate from your
code, which enables you to define one-line functions as well as organize
your code more succintly. We believe this confers a number of benefits
which we discuss in [our style
guide](https://docs.fast.ai/dev/style.html).

Suppose you have the following undocumented class:

``` python
class T:
    def foo(self): pass
    def bar(self): pass
```

You can add documentation to this class like so:

``` python
add_docs(T, cls_doc="A docstring for the class.",
            foo="The foo method.",
            bar="The bar method.")
```

Now, docstrings will appear as expected:

``` python
test_eq(T.__doc__, "A docstring for the class.")
test_eq(T.foo.__doc__, "The foo method.")
test_eq(T.bar.__doc__, "The bar method.")
```

[`add_docs`](https://fastcore.fast.ai/foundation.html#add_docs) also
validates that all of your public methods contain a docstring. If one of
your methods is not documented, it will raise an error:

``` python
class T:
    def foo(self): pass
    def bar(self): pass

f=lambda: add_docs(T, "A docstring for the class.", foo="The foo method.")
test_fail(f, contains="Missing docs")
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/foundation.py#L42"
target="_blank" style="float:right; font-size:smaller">source</a>

### docs

>      docs (cls)

*Decorator version of
[`add_docs`](https://fastcore.fast.ai/foundation.html#add_docs), using
`_docs` dict*

Instead of using
[`add_docs`](https://fastcore.fast.ai/foundation.html#add_docs), you can
use the decorator
[`docs`](https://fastcore.fast.ai/foundation.html#docs) as shown below.
Note that the docstring for the class can be set with the argument
`cls_doc`:

``` python
@docs
class _T:
    def f(self): pass
    def g(cls): pass
    
    _docs = dict(cls_doc="The class docstring", 
                 f="The docstring for method f.",
                 g="A different docstring for method g.")

    
test_eq(_T.__doc__, "The class docstring")
test_eq(_T.f.__doc__, "The docstring for method f.")
test_eq(_T.g.__doc__, "A different docstring for method g.")
```

For either the [`docs`](https://fastcore.fast.ai/foundation.html#docs)
decorator or the
[`add_docs`](https://fastcore.fast.ai/foundation.html#add_docs)
function, you can still define your docstrings in the normal way. Below
we set the docstring for the class as usual, but define the method
docstrings through the `_docs` attribute:

``` python
@docs
class _T:
    "The class docstring"
    def f(self): pass
    _docs = dict(f="The docstring for method f.")

    
test_eq(_T.__doc__, "The class docstring")
test_eq(_T.f.__doc__, "The docstring for method f.")
```

------------------------------------------------------------------------

### is_iter

>      is_iter (o)

*Test whether `o` can be used in a `for` loop*

``` python
assert is_iter([1])
assert not is_iter(array(1))
assert is_iter(array([1,2]))
assert (o for o in range(3))
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/foundation.py#L48"
target="_blank" style="float:right; font-size:smaller">source</a>

### coll_repr

>      coll_repr (c, max_n=10)

*String repr of up to `max_n` items of (possibly lazy) collection `c`*

[`coll_repr`](https://fastcore.fast.ai/foundation.html#coll_repr) is
used to provide a more informative
[`__repr__`](https://stackoverflow.com/questions/1984162/purpose-of-pythons-repr)
about list-like objects.
[`coll_repr`](https://fastcore.fast.ai/foundation.html#coll_repr) and is
used by [`L`](https://fastcore.fast.ai/foundation.html#l) to build a
`__repr__` that displays the length of a list in addition to a preview
of a list.

Below is an example of the `__repr__` string created for a list of 1000
elements:

``` python
test_eq(coll_repr(range(1000)),    '(#1000) [0,1,2,3,4,5,6,7,8,9...]')
test_eq(coll_repr(range(1000), 5), '(#1000) [0,1,2,3,4...]')
test_eq(coll_repr(range(10),   5),   '(#10) [0,1,2,3,4...]')
test_eq(coll_repr(range(5),    5),    '(#5) [0,1,2,3,4]')
```

We can set the option `max_n` to optionally preview a specified number
of items instead of the default:

``` python
test_eq(coll_repr(range(1000), max_n=5), '(#1000) [0,1,2,3,4...]')
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/foundation.py#L54"
target="_blank" style="float:right; font-size:smaller">source</a>

### is_bool

>      is_bool (x)

*Check whether `x` is a bool or None*

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/foundation.py#L59"
target="_blank" style="float:right; font-size:smaller">source</a>

### mask2idxs

>      mask2idxs (mask)

*Convert bool mask or index list to index
[`L`](https://fastcore.fast.ai/foundation.html#l)*

``` python
test_eq(mask2idxs([False,True,False,True]), [1,3])
test_eq(mask2idxs(array([False,True,False,True])), [1,3])
test_eq(mask2idxs(array([1,2,3])), [1,2,3])
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/foundation.py#L70"
target="_blank" style="float:right; font-size:smaller">source</a>

### cycle

>      cycle (o)

*Like `itertools.cycle` except creates list of `None`s if `o` is empty*

``` python
test_eq(itertools.islice(cycle([1,2,3]),5), [1,2,3,1,2])
test_eq(itertools.islice(cycle([]),3), [None]*3)
test_eq(itertools.islice(cycle(None),3), [None]*3)
test_eq(itertools.islice(cycle(1),3), [1,1,1])
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/foundation.py#L76"
target="_blank" style="float:right; font-size:smaller">source</a>

### zip_cycle

>      zip_cycle (x, *args)

*Like `itertools.zip_longest` but
[`cycle`](https://fastcore.fast.ai/foundation.html#cycle)s through
elements of all but first argument*

``` python
test_eq(zip_cycle([1,2,3,4],list('abc')), [(1, 'a'), (2, 'b'), (3, 'c'), (4, 'a')])
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/foundation.py#L81"
target="_blank" style="float:right; font-size:smaller">source</a>

### is_indexer

>      is_indexer (idx)

*Test whether `idx` will index a single item in a list*

You can, for example index a single item in a list with an integer or a
0-dimensional numpy array:

``` python
assert is_indexer(1)
assert is_indexer(np.array(1))
```

However, you cannot index into single item in a list with another list
or a numpy array with ndim \> 0.

``` python
assert not is_indexer([1, 2])
assert not is_indexer(np.array([[1, 2], [3, 4]]))
```

## [`L`](https://fastcore.fast.ai/foundation.html#l) helpers

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/foundation.py#L86"
target="_blank" style="float:right; font-size:smaller">source</a>

### CollBase

>      CollBase (items)

*Base class for composing a list of `items`*

`ColBase` is a base class that emulates the functionality of a python
`list`:

``` python
class _T(CollBase): pass
l = _T([1,2,3,4,5])

test_eq(len(l), 5) # __len__
test_eq(l[-1], 5); test_eq(l[0], 1) #__getitem__
l[2] = 100; test_eq(l[2], 100)      # __set_item__
del l[0]; test_eq(len(l), 4)        # __delitem__
test_eq(str(l), '[2, 100, 4, 5]')   # __repr__
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/foundation.py#L103"
target="_blank" style="float:right; font-size:smaller">source</a>

### L

>      L (x=None, *args, **kwargs)

*Behaves like a list of `items` but can also index with list of indices
or masks*

[`L`](https://fastcore.fast.ai/foundation.html#l) is a drop in
replacement for a python `list`. Inspired by
[NumPy](http://www.numpy.org/),
[`L`](https://fastcore.fast.ai/foundation.html#l), supports advanced
indexing and has additional methods (outlined below) that provide
additional functionality and encourage simple expressive code. For
example, the code below takes a list of pairs, selects the second item
of each pair, takes its absolute value, filters items greater than 4,
and adds them up:

``` python
from fastcore.utils import gt
```

``` python
d = dict(a=1,b=-5,d=6,e=9).items()
test_eq(L(d).itemgot(1).map(abs).filter(gt(4)).sum(), 20) # abs(-5) + abs(6) + abs(9) = 20; 1 was filtered out.
```

Read [this overview section](https://fastcore.fast.ai/tour.html#L) for a
quick tutorial of [`L`](https://fastcore.fast.ai/foundation.html#l), as
well as background on the name.

You can create an [`L`](https://fastcore.fast.ai/foundation.html#l) from
an existing iterable (e.g. a list, range, etc) and access or modify it
with an int list/tuple index, mask, int, or slice. All `list` methods
can also be used with [`L`](https://fastcore.fast.ai/foundation.html#l).

``` python
t = L(range(12))
test_eq(t, list(range(12)))
test_ne(t, list(range(11)))
t.reverse()
test_eq(t[0], 11)
t[3] = "h"
test_eq(t[3], "h")
t[3,5] = ("j","k")
test_eq(t[3,5], ["j","k"])
test_eq(t, L(t))
test_eq(L(L(1,2),[3,4]), ([1,2],[3,4]))
t
```

    (#12) [11,10,9,'j',7,'k',5,4,3,2...]

Any [`L`](https://fastcore.fast.ai/foundation.html#l) is a `Sequence` so
you can use it with methods like `random.sample`:

``` python
assert isinstance(t, Sequence)
```

``` python
import random
```

``` python
random.seed(0)
random.sample(t, 3)
```

    [5, 0, 11]

There are optimized indexers for arrays, tensors, and DataFrames.

``` python
import pandas as pd
```

``` python
arr = np.arange(9).reshape(3,3)
t = L(arr, use_list=None)
test_eq(t[1,2], arr[[1,2]])

df = pd.DataFrame({'a':[1,2,3]})
t = L(df, use_list=None)
test_eq(t[1,2], L(pd.DataFrame({'a':[2,3]}, index=[1,2]), use_list=None))
```

You can also modify an [`L`](https://fastcore.fast.ai/foundation.html#l)
with `append`, `+`, and `*`.

``` python
t = L()
test_eq(t, [])
t.append(1)
test_eq(t, [1])
t += [3,2]
test_eq(t, [1,3,2])
t = t + [4]
test_eq(t, [1,3,2,4])
t = 5 + t
test_eq(t, [5,1,3,2,4])
test_eq(L(1,2,3), [1,2,3])
test_eq(L(1,2,3), L(1,2,3))
t = L(1)*5
t = t.map(operator.neg)
test_eq(t,[-1]*5)
test_eq(~L([True,False,False]), L([False,True,True]))
t = L(range(4))
test_eq(zip(t, L(1).cycle()), zip(range(4),(1,1,1,1)))
t = L.range(100)
test_shuffled(t,t.shuffle())
```

``` python
test_eq(L([]).sum(), 0)
test_eq(L([]).product(), 1)
```

``` python
def _f(x,a=0): return x+a
t = L(1)*5
test_eq(t.map(_f), t)
test_eq(t.map(_f,1), [2]*5)
test_eq(t.map(_f,a=2), [3]*5)
```

An [`L`](https://fastcore.fast.ai/foundation.html#l) can be constructed
from anything iterable, although tensors and arrays will not be iterated
over on construction, unless you pass `use_list` to the constructor.

``` python
test_eq(L([1,2,3]),[1,2,3])
test_eq(L(L([1,2,3])),[1,2,3])
test_ne(L([1,2,3]),[1,2,])
test_eq(L('abc'),['abc'])
test_eq(L(range(0,3)),[0,1,2])
test_eq(L(o for o in range(0,3)),[0,1,2])
test_eq(L(array(0)),[array(0)])
test_eq(L([array(0),array(1)]),[array(0),array(1)])
test_eq(L(array([0.,1.1]))[0],array([0.,1.1]))
test_eq(L(array([0.,1.1]), use_list=True), [array(0.),array(1.1)])  # `use_list=True` to unwrap arrays/arrays
```

If `match` is not `None` then the created list is same len as `match`,
either by:

- If `len(items)==1` then `items` is replicated,
- Otherwise an error is raised if `match` and `items` are not already
  the same size.

``` python
test_eq(L(1,match=[1,2,3]),[1,1,1])
test_eq(L([1,2],match=[2,3]),[1,2])
test_fail(lambda: L([1,2],match=[1,2,3]))
```

If you create an [`L`](https://fastcore.fast.ai/foundation.html#l) from
an existing [`L`](https://fastcore.fast.ai/foundation.html#l) then
you’ll get back the original object (since
[`L`](https://fastcore.fast.ai/foundation.html#l) uses the
[`NewChkMeta`](https://fastcore.fast.ai/meta.html#newchkmeta)
metaclass).

``` python
test_is(L(t), t)
```

An [`L`](https://fastcore.fast.ai/foundation.html#l) is considred equal
to a list if they have the same elements. It’s never considered equal to
a `str` a `set` or a `dict` even if they have the same elements/keys.

``` python
test_eq(L(['a', 'b']), ['a', 'b'])
test_ne(L(['a', 'b']), 'ab')
test_ne(L(['a', 'b']), {'a':1, 'b':2})
```

### [`L`](https://fastcore.fast.ai/foundation.html#l) Methods

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/foundation.py#L114"
target="_blank" style="float:right; font-size:smaller">source</a>

### L.\_\_getitem\_\_

>      L.__getitem__ (idx)

*Retrieve `idx` (can be list of indices, or mask, or int) items*

``` python
t = L(range(12))
test_eq(t[1,2], [1,2])                # implicit tuple
test_eq(t[[1,2]], [1,2])              # list
test_eq(t[:3], [0,1,2])               # slice
test_eq(t[[False]*11 + [True]], [11]) # mask
test_eq(t[array(3)], 3)
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/foundation.py#L124"
target="_blank" style="float:right; font-size:smaller">source</a>

### L.\_\_setitem\_\_

>      L.__setitem__ (idx, o)

*Set `idx` (can be list of indices, or mask, or int) items to `o` (which
is broadcast if not iterable)*

``` python
t[4,6] = 0
test_eq(t[4,6], [0,0])
t[4,6] = [1,2]
test_eq(t[4,6], [1,2])
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/foundation.py#L169"
target="_blank" style="float:right; font-size:smaller">source</a>

### L.unique

>      L.unique (sort=False, bidir=False, start=None)

*Unique items, in stable order*

``` python
test_eq(L(4,1,2,3,4,4).unique(), [4,1,2,3])
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/foundation.py#L170"
target="_blank" style="float:right; font-size:smaller">source</a>

### L.val2idx

>      L.val2idx ()

*Dict from value to index*

``` python
test_eq(L(1,2,3).val2idx(), {3:2,1:0,2:1})
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/foundation.py#L164"
target="_blank" style="float:right; font-size:smaller">source</a>

### L.filter

>      L.filter (f=<function noop>, negate=False, **kwargs)

*Create new [`L`](https://fastcore.fast.ai/foundation.html#l) filtered
by predicate `f`, passing `args` and `kwargs` to `f`*

``` python
list(t)
```

    [0, 1, 2, 3, 1, 5, 2, 7, 8, 9, 10, 11]

``` python
test_eq(t.filter(lambda o:o<5), [0,1,2,3,1,2])
test_eq(t.filter(lambda o:o<5, negate=True), [5,7,8,9,10,11])
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/foundation.py#L160"
target="_blank" style="float:right; font-size:smaller">source</a>

### L.argwhere

>      L.argwhere (f, negate=False, **kwargs)

*Like `filter`, but return indices for matching items*

``` python
test_eq(t.argwhere(lambda o:o<5), [0,1,2,3,4,6])
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/foundation.py#L161"
target="_blank" style="float:right; font-size:smaller">source</a>

### L.argfirst

>      L.argfirst (f, negate=False)

*Return index of first matching item*

``` python
test_eq(t.argfirst(lambda o:o>4), 5)
test_eq(t.argfirst(lambda o:o>4,negate=True),0)
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/foundation.py#L159"
target="_blank" style="float:right; font-size:smaller">source</a>

### L.map

>      L.map (f, *args, **kwargs)

*Create new [`L`](https://fastcore.fast.ai/foundation.html#l) with `f`
applied to all `items`, passing `args` and `kwargs` to `f`*

``` python
test_eq(L.range(4).map(operator.neg), [0,-1,-2,-3])
```

If `f` is a string then it is treated as a format string to create the
mapping:

``` python
test_eq(L.range(4).map('#{}#'), ['#0#','#1#','#2#','#3#'])
```

If `f` is a dictionary (or anything supporting `__getitem__`) then it is
indexed to create the mapping:

``` python
test_eq(L.range(4).map(list('abcd')), list('abcd'))
```

You can also pass the same `arg` params that
[`bind`](https://fastcore.fast.ai/basics.html#bind) accepts:

``` python
def f(a=None,b=None): return b
test_eq(L.range(4).map(f, b=arg0), range(4))
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/foundation.py#L172"
target="_blank" style="float:right; font-size:smaller">source</a>

### L.map_dict

>      L.map_dict (f=<function noop>, *args, **kwargs)

*Like `map`, but creates a dict from `items` to function results*

``` python
test_eq(L(range(1,5)).map_dict(), {1:1, 2:2, 3:3, 4:4})
test_eq(L(range(1,5)).map_dict(operator.neg), {1:-1, 2:-2, 3:-3, 4:-4})
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/foundation.py#L184"
target="_blank" style="float:right; font-size:smaller">source</a>

### L.zip

>      L.zip (cycled=False)

*Create new [`L`](https://fastcore.fast.ai/foundation.html#l) with
`zip(*items)`*

``` python
t = L([[1,2,3],'abc'])
test_eq(t.zip(), [(1, 'a'),(2, 'b'),(3, 'c')])
```

``` python
t = L([[1,2,3,4],['a','b','c']])
test_eq(t.zip(cycled=True ), [(1, 'a'),(2, 'b'),(3, 'c'),(4, 'a')])
test_eq(t.zip(cycled=False), [(1, 'a'),(2, 'b'),(3, 'c')])
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/foundation.py#L186"
target="_blank" style="float:right; font-size:smaller">source</a>

### L.map_zip

>      L.map_zip (f, *args, cycled=False, **kwargs)

*Combine `zip` and `starmap`*

``` python
t = L([1,2,3],[2,3,4])
test_eq(t.map_zip(operator.mul), [2,6,12])
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/foundation.py#L185"
target="_blank" style="float:right; font-size:smaller">source</a>

### L.zipwith

>      L.zipwith (*rest, cycled=False)

*Create new [`L`](https://fastcore.fast.ai/foundation.html#l) with
`self` zip with each of `*rest`*

``` python
b = [[0],[1],[2,2]]
t = L([1,2,3]).zipwith(b)
test_eq(t, [(1,[0]), (2,[1]), (3,[2,2])])
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/foundation.py#L187"
target="_blank" style="float:right; font-size:smaller">source</a>

### L.map_zipwith

>      L.map_zipwith (f, *rest, cycled=False, **kwargs)

*Combine `zipwith` and `starmap`*

``` python
test_eq(L(1,2,3).map_zipwith(operator.mul, [2,3,4]), [2,6,12])
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/foundation.py#L176"
target="_blank" style="float:right; font-size:smaller">source</a>

### L.itemgot

>      L.itemgot (*idxs)

*Create new [`L`](https://fastcore.fast.ai/foundation.html#l) with item
`idx` of all `items`*

``` python
test_eq(t.itemgot(1), b)
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/foundation.py#L180"
target="_blank" style="float:right; font-size:smaller">source</a>

### L.attrgot

>      L.attrgot (k, default=None)

*Create new [`L`](https://fastcore.fast.ai/foundation.html#l) with attr
`k` (or value `k` for dicts) of all `items`.*

``` python
# Example when items are not a dict
a = [SimpleNamespace(a=3,b=4),SimpleNamespace(a=1,b=2)]
test_eq(L(a).attrgot('b'), [4,2])

#Example of when items are a dict
b =[{'id': 15, 'name': 'nbdev'}, {'id': 17, 'name': 'fastcore'}]
test_eq(L(b).attrgot('id'), [15, 17])
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/foundation.py#L139"
target="_blank" style="float:right; font-size:smaller">source</a>

### L.sorted

>      L.sorted (key=None, reverse=False)

*New [`L`](https://fastcore.fast.ai/foundation.html#l) sorted by `key`.
If key is str use `attrgetter`; if int use `itemgetter`*

``` python
test_eq(L(a).sorted('a').attrgot('b'), [2,4])
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/foundation.py#L155"
target="_blank" style="float:right; font-size:smaller">source</a>

### L.split

>      L.split (s, sep=None, maxsplit=-1)

*Class Method: Same as `str.split`, but returns an
[`L`](https://fastcore.fast.ai/foundation.html#l)*

``` python
test_eq(L.split('a b c'), list('abc'))
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/foundation.py#L157"
target="_blank" style="float:right; font-size:smaller">source</a>

### L.range

>      L.range (a, b=None, step=None)

*Class Method: Same as `range`, but returns
[`L`](https://fastcore.fast.ai/foundation.html#l). Can pass collection
for `a`, to use `len(a)`*

``` python
test_eq_type(L.range([1,1,1]), L(range(3)))
test_eq_type(L.range(5,2,2), L(range(5,2,2)))
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/foundation.py#L193"
target="_blank" style="float:right; font-size:smaller">source</a>

### L.concat

>      L.concat ()

*Concatenate all elements of list*

``` python
test_eq(L([0,1,2,3],4,L(5,6)).concat(), range(7))
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/foundation.py#L115"
target="_blank" style="float:right; font-size:smaller">source</a>

### L.copy

>      L.copy ()

*Same as `list.copy`, but returns an
[`L`](https://fastcore.fast.ai/foundation.html#l)*

``` python
t = L([0,1,2,3],4,L(5,6)).copy()
test_eq(t.concat(), range(7))
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/foundation.py#L173"
target="_blank" style="float:right; font-size:smaller">source</a>

### L.map_first

>      L.map_first (f=<function noop>, g=<function noop>, *args, **kwargs)

*First element of `map_filter`*

``` python
t = L(0,1,2,3)
test_eq(t.map_first(lambda o:o*2 if o>2 else None), 6)
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/foundation.py#L197"
target="_blank" style="float:right; font-size:smaller">source</a>

### L.setattrs

>      L.setattrs (attr, val)

*Call `setattr` on all items*

``` python
t = L(SimpleNamespace(),SimpleNamespace())
t.setattrs('foo', 'bar')
test_eq(t.attrgot('foo'), ['bar','bar'])
```

## Config

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/foundation.py#L242"
target="_blank" style="float:right; font-size:smaller">source</a>

### save_config_file

>      save_config_file (file, d, **kwargs)

*Write settings dict to a new config file, or overwrite the existing
one.*

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/foundation.py#L249"
target="_blank" style="float:right; font-size:smaller">source</a>

### read_config_file

>      read_config_file (file, **kwargs)

Config files are saved and read using Python’s
`configparser.ConfigParser`, inside the `DEFAULT` section.

``` python
_d = dict(user='fastai', lib_name='fastcore', some_path='test', some_bool=True, some_num=3)
try:
    save_config_file('tmp.ini', _d)
    res = read_config_file('tmp.ini')
finally: os.unlink('tmp.ini')
dict(res)
```

    {'user': 'fastai',
     'lib_name': 'fastcore',
     'some_path': 'test',
     'some_bool': 'True',
     'some_num': '3'}

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/foundation.py#L255"
target="_blank" style="float:right; font-size:smaller">source</a>

### Config

>      Config (cfg_path, cfg_name, create=None, save=True, extra_files=None,
>              types=None)

*Reading and writing `ConfigParser` ini files*

[`Config`](https://fastcore.fast.ai/foundation.html#config) is a
convenient wrapper around `ConfigParser` ini files with a single section
(`DEFAULT`).

Instantiate a
[`Config`](https://fastcore.fast.ai/foundation.html#config) from an ini
file at `cfg_path/cfg_name`:

``` python
save_config_file('../tmp.ini', _d)
try: cfg = Config('..', 'tmp.ini')
finally: os.unlink('../tmp.ini')
cfg
```

    {'user': 'fastai', 'lib_name': 'fastcore', 'some_path': 'test', 'some_bool': 'True', 'some_num': '3'}

You can create a new file if one doesn’t exist by providing a `create`
dict:

``` python
try: cfg = Config('..', 'tmp.ini', create=_d)
finally: os.unlink('../tmp.ini')
cfg
```

    {'user': 'fastai', 'lib_name': 'fastcore', 'some_path': 'test', 'some_bool': 'True', 'some_num': '3'}

If you additionally pass `save=False`, the
[`Config`](https://fastcore.fast.ai/foundation.html#config) will contain
the items from `create` without writing a new file:

``` python
cfg = Config('..', 'tmp.ini', create=_d, save=False)
test_eq(cfg.user,'fastai')
assert not Path('../tmp.ini').exists()
```

Keys can be accessed as attributes, items, or with `get` and an optional
default:

``` python
test_eq(cfg.user,'fastai')
test_eq(cfg['some_path'], 'test')
test_eq(cfg.get('foo','bar'),'bar')
```

Extra files can be read *before* `cfg_path/cfg_name` using
`extra_files`, in the order they appear:

``` python
with tempfile.TemporaryDirectory() as d:
    a = Config(d, 'a.ini', {'a':0,'b':0})
    b = Config(d, 'b.ini', {'a':1,'c':0})
    c = Config(d, 'c.ini', {'a':2,'d':0}, extra_files=[a.config_file,b.config_file])
    test_eq(c.d, {'a':'2','b':'0','c':'0','d':'0'})
```

If you pass a dict `types`, then the values of that dict will be used as
types to instantiate all values returned. `Path` is a special case – in
that case, the path returned will be relative to the path containing the
config file (assuming the value is relative). `bool` types use
[`str2bool`](https://fastcore.fast.ai/basics.html#str2bool) to convert
to boolean.

``` python
_types = dict(some_path=Path, some_bool=bool, some_num=int)
cfg = Config('..', 'tmp.ini', create=_d, save=False, types=_types)

test_eq(cfg.user,'fastai')
test_eq(cfg['some_path'].resolve(), (Path('..')/'test').resolve())
test_eq(cfg.get('some_num'), 3)
```</doc>
    <doc title="fastcore.xtras" desc="Utility functions used in the fastai library"># Utility functions



## File Functions

Utilities (other than extensions to Pathlib.Path) for dealing with IO.

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L33"
target="_blank" style="float:right; font-size:smaller">source</a>

### walk

>      walk (path:pathlib.Path|str, symlinks:bool=True, keep_file:<built-
>            infunctioncallable>=<function ret_true>, keep_folder:<built-
>            infunctioncallable>=<function ret_true>, skip_folder:<built-
>            infunctioncallable>=<function ret_false>, func:<built-
>            infunctioncallable>=<function join>, ret_folders:bool=False)

*Generator version of `os.walk`, using functions to filter files and
folders*

<table>
<colgroup>
<col style="width: 6%" />
<col style="width: 25%" />
<col style="width: 34%" />
<col style="width: 34%" />
</colgroup>
<thead>
<tr class="header">
<th></th>
<th><strong>Type</strong></th>
<th><strong>Default</strong></th>
<th><strong>Details</strong></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>path</td>
<td>pathlib.Path | str</td>
<td></td>
<td>path to start searching</td>
</tr>
<tr class="even">
<td>symlinks</td>
<td>bool</td>
<td>True</td>
<td>follow symlinks?</td>
</tr>
<tr class="odd">
<td>keep_file</td>
<td>callable</td>
<td>ret_true</td>
<td>function that returns True for wanted files</td>
</tr>
<tr class="even">
<td>keep_folder</td>
<td>callable</td>
<td>ret_true</td>
<td>function that returns True for folders to enter</td>
</tr>
<tr class="odd">
<td>skip_folder</td>
<td>callable</td>
<td>ret_false</td>
<td>function that returns True for folders to skip</td>
</tr>
<tr class="even">
<td>func</td>
<td>callable</td>
<td>join</td>
<td>function to apply to each matched file</td>
</tr>
<tr class="odd">
<td>ret_folders</td>
<td>bool</td>
<td>False</td>
<td>return folders, not just files</td>
</tr>
</tbody>
</table>

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L52"
target="_blank" style="float:right; font-size:smaller">source</a>

### globtastic

>      globtastic (path:pathlib.Path|str, recursive:bool=True,
>                  symlinks:bool=True, file_glob:str=None, file_re:str=None,
>                  folder_re:str=None, skip_file_glob:str=None,
>                  skip_file_re:str=None, skip_folder_re:str=None, func:<built-
>                  infunctioncallable>=<function join>, ret_folders:bool=False)

*A more powerful `glob`, including regex matches, symlink handling, and
skip parameters*

<table>
<thead>
<tr class="header">
<th></th>
<th><strong>Type</strong></th>
<th><strong>Default</strong></th>
<th><strong>Details</strong></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>path</td>
<td>pathlib.Path | str</td>
<td></td>
<td>path to start searching</td>
</tr>
<tr class="even">
<td>recursive</td>
<td>bool</td>
<td>True</td>
<td>search subfolders</td>
</tr>
<tr class="odd">
<td>symlinks</td>
<td>bool</td>
<td>True</td>
<td>follow symlinks?</td>
</tr>
<tr class="even">
<td>file_glob</td>
<td>str</td>
<td>None</td>
<td>Only include files matching glob</td>
</tr>
<tr class="odd">
<td>file_re</td>
<td>str</td>
<td>None</td>
<td>Only include files matching regex</td>
</tr>
<tr class="even">
<td>folder_re</td>
<td>str</td>
<td>None</td>
<td>Only enter folders matching regex</td>
</tr>
<tr class="odd">
<td>skip_file_glob</td>
<td>str</td>
<td>None</td>
<td>Skip files matching glob</td>
</tr>
<tr class="even">
<td>skip_file_re</td>
<td>str</td>
<td>None</td>
<td>Skip files matching regex</td>
</tr>
<tr class="odd">
<td>skip_folder_re</td>
<td>str</td>
<td>None</td>
<td>Skip folders matching regex,</td>
</tr>
<tr class="even">
<td>func</td>
<td>callable</td>
<td>join</td>
<td>function to apply to each matched file</td>
</tr>
<tr class="odd">
<td>ret_folders</td>
<td>bool</td>
<td>False</td>
<td>return folders, not just files</td>
</tr>
<tr class="even">
<td><strong>Returns</strong></td>
<td><strong>L</strong></td>
<td></td>
<td><strong>Paths to matched files</strong></td>
</tr>
</tbody>
</table>

``` python
globtastic('.', skip_folder_re='^[_.]', folder_re='core', file_glob='*.*py*', file_re='c')
```

    (#5) ['./fastcore/docments.py','./fastcore/dispatch.py','./fastcore/basics.py','./fastcore/docscrape.py','./fastcore/script.py']

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L84"
target="_blank" style="float:right; font-size:smaller">source</a>

### maybe_open

>      maybe_open (f, mode='r', **kwargs)

*Context manager: open `f` if it is a path (and close on exit)*

This is useful for functions where you want to accept a path *or* file.
[`maybe_open`](https://fastcore.fast.ai/xtras.html#maybe_open) will not
close your file handle if you pass one in.

``` python
def _f(fn):
    with maybe_open(fn) as f: return f.encoding

fname = '00_test.ipynb'
sys_encoding = 'cp1252' if sys.platform == 'win32' else 'UTF-8'
test_eq(_f(fname), sys_encoding)
with open(fname) as fh: test_eq(_f(fh), sys_encoding)
```

For example, we can use this to reimplement
[`imghdr.what`](https://docs.python.org/3/library/imghdr.html#imghdr.what)
from the Python standard library, which is [written in Python
3.9](https://github.com/python/cpython/blob/3.9/Lib/imghdr.py#L11) as:

``` python
from fastcore import imghdr
```

``` python
def what(file, h=None):
    f = None
    try:
        if h is None:
            if isinstance(file, (str,os.PathLike)):
                f = open(file, 'rb')
                h = f.read(32)
            else:
                location = file.tell()
                h = file.read(32)
                file.seek(location)
        for tf in imghdr.tests:
            res = tf(h, f)
            if res: return res
    finally:
        if f: f.close()
    return None
```

Here’s an example of the use of this function:

``` python
fname = 'images/puppy.jpg'
what(fname)
```

    'jpeg'

With [`maybe_open`](https://fastcore.fast.ai/xtras.html#maybe_open),
`Self`, and
[`L.map_first`](https://fastcore.fast.ai/foundation.html#l.map_first),
we can rewrite this in a much more concise and (in our opinion) clear
way:

``` python
def what(file, h=None):
    if h is None:
        with maybe_open(file, 'rb') as f: h = f.peek(32)
    return L(imghdr.tests).map_first(Self(h,file))
```

…and we can check that it still works:

``` python
test_eq(what(fname), 'jpeg')
```

…along with the version passing a file handle:

``` python
with open(fname,'rb') as f: test_eq(what(f), 'jpeg')
```

…along with the `h` parameter version:

``` python
with open(fname,'rb') as f: test_eq(what(None, h=f.read(32)), 'jpeg')
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L91"
target="_blank" style="float:right; font-size:smaller">source</a>

### mkdir

>      mkdir (path, exist_ok=False, parents=False, overwrite=False, **kwargs)

*Creates and returns a directory defined by `path`, optionally removing
previous existing directory if `overwrite` is `True`*

``` python
with tempfile.TemporaryDirectory() as d:
    path = Path(os.path.join(d, 'new_dir'))
    new_dir = mkdir(path)
    assert new_dir.exists()
    test_eq(new_dir, path)
        
    # test overwrite
    with open(new_dir/'test.txt', 'w') as f: f.writelines('test')
    test_eq(len(list(walk(new_dir))), 1) # assert file is present
    new_dir = mkdir(new_dir, overwrite=True)
    test_eq(len(list(walk(new_dir))), 0) # assert file was deleted
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L100"
target="_blank" style="float:right; font-size:smaller">source</a>

### image_size

>      image_size (fn)

*Tuple of (w,h) for png, gif, or jpg; `None` otherwise*

``` python
test_eq(image_size(fname), (1200,803))
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L125"
target="_blank" style="float:right; font-size:smaller">source</a>

### bunzip

>      bunzip (fn)

*bunzip `fn`, raising exception if output already exists*

``` python
f = Path('files/test.txt')
if f.exists(): f.unlink()
bunzip('files/test.txt.bz2')
t = f.open().readlines()
test_eq(len(t),1)
test_eq(t[0], 'test\n')
f.unlink()
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L136"
target="_blank" style="float:right; font-size:smaller">source</a>

### loads

>      loads (s, **kw)

*Same as `json.loads`, but handles `None`*

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L144"
target="_blank" style="float:right; font-size:smaller">source</a>

### loads_multi

>      loads_multi (s:str)

*Generator of \>=0 decoded json dicts, possibly with non-json ignored
text at start and end*

``` python
tst = """
# ignored
{ "a":1 }
hello
{
"b":2
}
"""

test_eq(list(loads_multi(tst)), [{'a': 1}, {'b': 2}])
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L156"
target="_blank" style="float:right; font-size:smaller">source</a>

### dumps

>      dumps (obj, **kw)

*Same as `json.dumps`, but uses `ujson` if available*

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L171"
target="_blank" style="float:right; font-size:smaller">source</a>

### untar_dir

>      untar_dir (fname, dest, rename=False, overwrite=False)

*untar `file` into `dest`, creating a directory if the root contains
more than one item*

``` python
def test_untar(foldername, rename=False, **kwargs):
    with tempfile.TemporaryDirectory() as d:
        nm = os.path.join(d, 'a')
        shutil.make_archive(nm, 'gztar', **kwargs)
        with tempfile.TemporaryDirectory() as d2:
            d2 = Path(d2)
            untar_dir(nm+'.tar.gz', d2, rename=rename)
            test_eq(d2.ls(), [d2/foldername])
```

If the contents of `fname` contain just one file or directory, it is
placed directly in `dest`:

``` python
# using `base_dir` in `make_archive` results in `images` directory included in file names
test_untar('images', base_dir='images')
```

If `rename` then the directory created is named based on the archive,
without extension:

``` python
test_untar('a', base_dir='images', rename=True)
```

If the contents of `fname` contain multiple files and directories, a new
folder in `dest` is created with the same name as `fname` (but without
extension):

``` python
# using `root_dir` in `make_archive` results in `images` directory *not* included in file names
test_untar('a', root_dir='images')
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L189"
target="_blank" style="float:right; font-size:smaller">source</a>

### repo_details

>      repo_details (url)

*Tuple of `owner,name` from ssh or https git repo `url`*

``` python
test_eq(repo_details('https://github.com/fastai/fastai.git'), ['fastai', 'fastai'])
test_eq(repo_details('git@github.com:fastai/nbdev.git\n'), ['fastai', 'nbdev'])
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L196"
target="_blank" style="float:right; font-size:smaller">source</a>

### run

>      run (cmd, *rest, same_in_win=False, ignore_ex=False, as_bytes=False,
>           stderr=False)

*Pass `cmd` (splitting with `shlex` if string) to `subprocess.run`;
return `stdout`; raise `IOError` if fails*

You can pass a string (which will be split based on standard shell
rules), a list, or pass args directly:

``` python
run('echo', same_in_win=True)
run('pip', '--version', same_in_win=True)
run(['pip', '--version'], same_in_win=True)
```

    'pip 24.0 from /Users/daniel.roy.greenfeld/.virtualenvs/fastcore/lib/python3.10/site-packages/pip (python 3.10)'

``` python
if sys.platform == 'win32':
    assert 'ipynb' in run('cmd /c dir /p')
    assert 'ipynb' in run(['cmd', '/c', 'dir', '/p'])
    assert 'ipynb' in run('cmd', '/c', 'dir',  '/p')
else:
    assert 'ipynb' in run('ls -ls')
    assert 'ipynb' in run(['ls', '-l'])
    assert 'ipynb' in run('ls', '-l')
```

Some commands fail in non-error situations, like `grep`. Use `ignore_ex`
in those cases, which will return a tuple of stdout and returncode:

``` python
if sys.platform == 'win32':
    test_eq(run('cmd /c findstr asdfds 00_test.ipynb', ignore_ex=True)[0], 1)
else:
    test_eq(run('grep asdfds 00_test.ipynb', ignore_ex=True)[0], 1)
```

[`run`](https://fastcore.fast.ai/xtras.html#run) automatically decodes
returned bytes to a `str`. Use `as_bytes` to skip that:

``` python
if sys.platform == 'win32':
    test_eq(run('cmd /c echo hi'), 'hi')
else:
    test_eq(run('echo hi', as_bytes=True), b'hi\n')
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L220"
target="_blank" style="float:right; font-size:smaller">source</a>

### open_file

>      open_file (fn, mode='r', **kwargs)

*Open a file, with optional compression if gz or bz2 suffix*

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L231"
target="_blank" style="float:right; font-size:smaller">source</a>

### save_pickle

>      save_pickle (fn, o)

*Save a pickle file, to a file name or opened file*

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L237"
target="_blank" style="float:right; font-size:smaller">source</a>

### load_pickle

>      load_pickle (fn)

*Load a pickle file from a file name or opened file*

``` python
for suf in '.pkl','.bz2','.gz':
    # delete=False is added for Windows
    # https://stackoverflow.com/questions/23212435/permission-denied-to-write-to-my-temporary-file
    with tempfile.NamedTemporaryFile(suffix=suf, delete=False) as f:
        fn = Path(f.name)
        save_pickle(fn, 't')
        t = load_pickle(fn)
    f.close()
    test_eq(t,'t')
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L243"
target="_blank" style="float:right; font-size:smaller">source</a>

### parse_env

>      parse_env (s:str=None, fn:Union[str,pathlib.Path]=None)

*Parse a shell-style environment string or file*

``` python
testf = """# comment
   # another comment
 export FOO="bar#baz"
BAR=thing # comment "ok"
  baz='thong'
QUX=quux
export ZAP = "zip" # more comments
   FOOBAR = 42   # trailing space and comment"""

exp = dict(FOO='bar#baz', BAR='thing', baz='thong', QUX='quux', ZAP='zip', FOOBAR='42')

test_eq(parse_env(testf),  exp)
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L254"
target="_blank" style="float:right; font-size:smaller">source</a>

### expand_wildcards

>      expand_wildcards (code)

*Expand all wildcard imports in the given code string.*

``` python
inp = """from math import *
from os import *
from random import *
def func(): return sin(pi) + path.join('a', 'b') + randint(1, 10)"""

exp = """from math import pi, sin
from os import path
from random import randint
def func(): return sin(pi) + path.join('a', 'b') + randint(1, 10)"""

test_eq(expand_wildcards(inp), exp)

inp = """from itertools import *
def func(): pass"""
test_eq(expand_wildcards(inp), inp)

inp = """def outer():
    from math import *
    def inner():
        from os import *
        return sin(pi) + path.join('a', 'b')"""

exp = """def outer():
    from math import pi, sin
    def inner():
        from os import path
        return sin(pi) + path.join('a', 'b')"""

test_eq(expand_wildcards(inp), exp)
```

## Collections

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L288"
target="_blank" style="float:right; font-size:smaller">source</a>

### dict2obj

>      dict2obj (d, list_func=<class 'fastcore.foundation.L'>, dict_func=<class
>                'fastcore.basics.AttrDict'>)

*Convert (possibly nested) dicts (or lists of dicts) to
[`AttrDict`](https://fastcore.fast.ai/basics.html#attrdict)*

This is a convenience to give you “dotted” access to (possibly nested)
dictionaries, e.g:

``` python
d1 = dict(a=1, b=dict(c=2,d=3))
d2 = dict2obj(d1)
test_eq(d2.b.c, 2)
test_eq(d2.b['c'], 2)
```

It can also be used on lists of dicts.

``` python
_list_of_dicts = [d1, d1]
ds = dict2obj(_list_of_dicts)
test_eq(ds[0].b.c, 2)
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L295"
target="_blank" style="float:right; font-size:smaller">source</a>

### obj2dict

>      obj2dict (d)

*Convert (possibly nested) AttrDicts (or lists of AttrDicts) to `dict`*

[`obj2dict`](https://fastcore.fast.ai/xtras.html#obj2dict) can be used
to reverse what is done by
[`dict2obj`](https://fastcore.fast.ai/xtras.html#dict2obj):

``` python
test_eq(obj2dict(d2), d1)
test_eq(obj2dict(ds), _list_of_dicts)
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L310"
target="_blank" style="float:right; font-size:smaller">source</a>

### repr_dict

>      repr_dict (d)

*Print nested dicts and lists, such as returned by
[`dict2obj`](https://fastcore.fast.ai/xtras.html#dict2obj)*

``` python
print(repr_dict(d2))
```

    - a: 1
    - b: 
      - c: 2
      - d: 3

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L315"
target="_blank" style="float:right; font-size:smaller">source</a>

### is_listy

>      is_listy (x)

*`isinstance(x, (tuple,list,L,slice,Generator))`*

``` python
assert is_listy((1,))
assert is_listy([1])
assert is_listy(L([1]))
assert is_listy(slice(2))
assert not is_listy(array([1]))
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L320"
target="_blank" style="float:right; font-size:smaller">source</a>

### mapped

>      mapped (f, it)

*map `f` over `it`, unless it’s not listy, in which case return `f(it)`*

``` python
def _f(x,a=1): return x-a

test_eq(mapped(_f,1),0)
test_eq(mapped(_f,[1,2]),[0,1])
test_eq(mapped(_f,(1,)),(0,))
```

## Extensions to Pathlib.Path

The following methods are added to the standard python libary
[Pathlib.Path](https://docs.python.org/3/library/pathlib.html#basic-use).

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L326"
target="_blank" style="float:right; font-size:smaller">source</a>

### Path.readlines

>      Path.readlines (hint=-1, encoding='utf8')

*Read the content of `self`*

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L332"
target="_blank" style="float:right; font-size:smaller">source</a>

### Path.read_json

>      Path.read_json (encoding=None, errors=None)

*Same as `read_text` followed by
[`loads`](https://fastcore.fast.ai/xtras.html#loads)*

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L338"
target="_blank" style="float:right; font-size:smaller">source</a>

### Path.mk_write

>      Path.mk_write (data, encoding=None, errors=None, mode=511)

*Make all parent dirs of `self`, and write `data`*

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L345"
target="_blank" style="float:right; font-size:smaller">source</a>

### Path.relpath

>      Path.relpath (start=None)

*Same as `os.path.relpath`, but returns a `Path`, and resolves symlinks*

``` python
p = Path('../fastcore/').resolve()
p
```

    Path('/Users/daniel.roy.greenfeld/fh/fastcore/fastcore')

``` python
p.relpath(Path.cwd())
```

    Path('../fastcore')

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L351"
target="_blank" style="float:right; font-size:smaller">source</a>

### Path.ls

>      Path.ls (n_max=None, file_type=None, file_exts=None)

*Contents of path as a list*

We add an `ls()` method to `pathlib.Path` which is simply defined as
`list(Path.iterdir())`, mainly for convenience in REPL environments such
as notebooks.

``` python
path = Path()
t = path.ls()
assert len(t)>0
t1 = path.ls(10)
test_eq(len(t1), 10)
t2 = path.ls(file_exts='.ipynb')
assert len(t)>len(t2)
t[0]
```

    Path('000_tour.ipynb')

You can also pass an optional `file_type` MIME prefix and/or a list of
file extensions.

``` python
lib_path = (path/'../fastcore')
txt_files=lib_path.ls(file_type='text')
assert len(txt_files) > 0 and txt_files[0].suffix=='.py'
ipy_files=path.ls(file_exts=['.ipynb'])
assert len(ipy_files) > 0 and ipy_files[0].suffix=='.ipynb'
txt_files[0],ipy_files[0]
```

    (Path('../fastcore/shutil.py'), Path('000_tour.ipynb'))

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L363"
target="_blank" style="float:right; font-size:smaller">source</a>

### Path.\_\_repr\_\_

>      Path.__repr__ ()

*Return repr(self).*

fastai also updates the `repr` of `Path` such that, if `Path.BASE_PATH`
is defined, all paths are printed relative to that path (as long as they
are contained in `Path.BASE_PATH`:

``` python
t = ipy_files[0].absolute()
try:
    Path.BASE_PATH = t.parent.parent
    test_eq(repr(t), f"Path('nbs/{t.name}')")
finally: Path.BASE_PATH = None
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L372"
target="_blank" style="float:right; font-size:smaller">source</a>

### Path.delete

>      Path.delete ()

*Delete a file, symlink, or directory tree*

## Reindexing Collections

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L387"
target="_blank" style="float:right; font-size:smaller">source</a>

#### ReindexCollection

>      ReindexCollection (coll, idxs=None, cache=None, tfm=<function noop>)

*Reindexes collection `coll` with indices `idxs` and optional LRU cache
of size `cache`*

This is useful when constructing batches or organizing data in a
particular manner (i.e. for deep learning). This class is primarly used
in organizing data for language models in fastai.

You can supply a custom index upon instantiation with the `idxs`
argument, or you can call the `reindex` method to supply a new index for
your collection.

Here is how you can reindex a list such that the elements are reversed:

``` python
rc=ReindexCollection(['a', 'b', 'c', 'd', 'e'], idxs=[4,3,2,1,0])
list(rc)
```

    ['e', 'd', 'c', 'b', 'a']

Alternatively, you can use the `reindex` method:

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L398"
target="_blank" style="float:right; font-size:smaller">source</a>

###### ReindexCollection.reindex

>      ReindexCollection.reindex (idxs)

*Replace `self.idxs` with idxs*

``` python
rc=ReindexCollection(['a', 'b', 'c', 'd', 'e'])
rc.reindex([4,3,2,1,0])
list(rc)
```

    ['e', 'd', 'c', 'b', 'a']

You can optionally specify a LRU cache, which uses
[functools.lru_cache](https://docs.python.org/3/library/functools.html#functools.lru_cache)
upon instantiation:

``` python
sz = 50
t = ReindexCollection(L.range(sz), cache=2)

#trigger a cache hit by indexing into the same element multiple times
t[0], t[0]
t._get.cache_info()
```

    CacheInfo(hits=1, misses=1, maxsize=2, currsize=1)

You can optionally clear the LRU cache by calling the `cache_clear`
method:

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L402"
target="_blank" style="float:right; font-size:smaller">source</a>

##### ReindexCollection.cache_clear

>      ReindexCollection.cache_clear ()

*Clear LRU cache*

``` python
sz = 50
t = ReindexCollection(L.range(sz), cache=2)

#trigger a cache hit by indexing into the same element multiple times
t[0], t[0]
t.cache_clear()
t._get.cache_info()
```

    CacheInfo(hits=0, misses=0, maxsize=2, currsize=0)

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L399"
target="_blank" style="float:right; font-size:smaller">source</a>

##### ReindexCollection.shuffle

>      ReindexCollection.shuffle ()

*Randomly shuffle indices*

Note that an ordered index is automatically constructed for the data
structure even if one is not supplied.

``` python
rc=ReindexCollection(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'])
rc.shuffle()
list(rc)
```

    ['a', 'd', 'h', 'c', 'e', 'b', 'f', 'g']

``` python
sz = 50
t = ReindexCollection(L.range(sz), cache=2)
test_eq(list(t), range(sz))
test_eq(t[sz-1], sz-1)
test_eq(t._get.cache_info().hits, 1)
t.shuffle()
test_eq(t._get.cache_info().hits, 1)
test_ne(list(t), range(sz))
test_eq(set(t), set(range(sz)))
t.cache_clear()
test_eq(t._get.cache_info().hits, 0)
test_eq(t.count(0), 1)
```

## Other Helpers

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L424"
target="_blank" style="float:right; font-size:smaller">source</a>

### get_source_link

>      get_source_link (func)

*Return link to `func` in source code*

[`get_source_link`](https://fastcore.fast.ai/xtras.html#get_source_link)
allows you get a link to source code related to an object. For
[nbdev](https://github.com/fastai/nbdev) related projects such as
fastcore, we can get the full link to a GitHub repo. For `nbdev`
projects, be sure to properly set the `git_url` in `settings.ini`
(derived from `lib_name` and `branch` on top of the prefix you will need
to adapt) so that those links are correct.

For example, below we get the link to
[`fastcore.test.test_eq`](https://fastcore.fast.ai/test.html#test_eq):

``` python
from fastcore.test import test_eq
```

``` python
assert 'fastcore/test.py' in get_source_link(test_eq)
assert get_source_link(test_eq).startswith('https://github.com/fastai/fastcore')
get_source_link(test_eq)
```

    'https://github.com/fastai/fastcore/tree/master/fastcore/test.py#L35'

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L438"
target="_blank" style="float:right; font-size:smaller">source</a>

### truncstr

>      truncstr (s:str, maxlen:int, suf:str='…', space='')

*Truncate `s` to length `maxlen`, adding suffix `suf` if truncated*

``` python
w = 'abacadabra'
test_eq(truncstr(w, 10), w)
test_eq(truncstr(w, 5), 'abac…')
test_eq(truncstr(w, 5, suf=''), 'abaca')
test_eq(truncstr(w, 11, space='_'), w+"_")
test_eq(truncstr(w, 10, space='_'), w[:-1]+'…')
test_eq(truncstr(w, 5, suf='!!'), 'aba!!')
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L455"
target="_blank" style="float:right; font-size:smaller">source</a>

### sparkline

>      sparkline (data, mn=None, mx=None, empty_zero=False)

*Sparkline for `data`, with `None`s (and zero, if `empty_zero`) shown as
empty column*

``` python
data = [9,6,None,1,4,0,8,15,10]
print(f'without "empty_zero": {sparkline(data, empty_zero=False)}')
print(f'   with "empty_zero": {sparkline(data, empty_zero=True )}')
```

    without "empty_zero": ▅▂ ▁▂▁▃▇▅
       with "empty_zero": ▅▂ ▁▂ ▃▇▅

You can set a maximum and minimum for the y-axis of the sparkline with
the arguments `mn` and `mx` respectively:

``` python
sparkline([1,2,3,400], mn=0, mx=3)
```

    '▂▅▇▇'

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L464"
target="_blank" style="float:right; font-size:smaller">source</a>

### modify_exception

>      modify_exception (e:Exception, msg:str=None, replace:bool=False)

*Modifies `e` with a custom message attached*

<table>
<thead>
<tr class="header">
<th></th>
<th><strong>Type</strong></th>
<th><strong>Default</strong></th>
<th><strong>Details</strong></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>e</td>
<td>Exception</td>
<td></td>
<td>An exception</td>
</tr>
<tr class="even">
<td>msg</td>
<td>str</td>
<td>None</td>
<td>A custom message</td>
</tr>
<tr class="odd">
<td>replace</td>
<td>bool</td>
<td>False</td>
<td>Whether to replace e.args with [msg]</td>
</tr>
<tr class="even">
<td><strong>Returns</strong></td>
<td><strong>Exception</strong></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>

``` python
msg = "This is my custom message!"

test_fail(lambda: (_ for _ in ()).throw(modify_exception(Exception(), None)), contains='')
test_fail(lambda: (_ for _ in ()).throw(modify_exception(Exception(), msg)), contains=msg)
test_fail(lambda: (_ for _ in ()).throw(modify_exception(Exception("The first message"), msg)), contains="The first message This is my custom message!")
test_fail(lambda: (_ for _ in ()).throw(modify_exception(Exception("The first message"), msg, True)), contains="This is my custom message!")
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L474"
target="_blank" style="float:right; font-size:smaller">source</a>

### round_multiple

>      round_multiple (x, mult, round_down=False)

*Round `x` to nearest multiple of `mult`*

``` python
test_eq(round_multiple(63,32), 64)
test_eq(round_multiple(50,32), 64)
test_eq(round_multiple(40,32), 32)
test_eq(round_multiple( 0,32),  0)
test_eq(round_multiple(63,32, round_down=True), 32)
test_eq(round_multiple((63,40),32), (64,32))
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L481"
target="_blank" style="float:right; font-size:smaller">source</a>

### set_num_threads

>      set_num_threads (nt)

*Get numpy (and others) to use `nt` threads*

This sets the number of threads consistently for many tools, by:

1.  Set the following environment variables equal to `nt`:
    `OPENBLAS_NUM_THREADS`,`NUMEXPR_NUM_THREADS`,`OMP_NUM_THREADS`,`MKL_NUM_THREADS`
2.  Sets `nt` threads for numpy and pytorch.

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L492"
target="_blank" style="float:right; font-size:smaller">source</a>

### join_path_file

>      join_path_file (file, path, ext='')

*Return `path/file` if file is a string or a `Path`, file otherwise*

``` python
path = Path.cwd()/'_tmp'/'tst'
f = join_path_file('tst.txt', path)
assert path.exists()
test_eq(f, path/'tst.txt')
with open(f, 'w') as f_: assert join_path_file(f_, path) == f_
shutil.rmtree(Path.cwd()/'_tmp')
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L499"
target="_blank" style="float:right; font-size:smaller">source</a>

### autostart

>      autostart (g)

*Decorator that automatically starts a generator*

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L509"
target="_blank" style="float:right; font-size:smaller">source</a>

#### EventTimer

>      EventTimer (store=5, span=60)

*An event timer with history of `store` items of time `span`*

Add events with `add`, and get number of `events` and their frequency
(`freq`).

``` python
# Random wait function for testing
def _randwait(): yield from (sleep(random.random()/200) for _ in range(100))

c = EventTimer(store=5, span=0.03)
for o in _randwait(): c.add(1)
print(f'Num Events: {c.events}, Freq/sec: {c.freq:.01f}')
print('Most recent: ', sparkline(c.hist), *L(c.hist).map('{:.01f}'))
```

    Num Events: 3, Freq/sec: 205.6
    Most recent:  ▁▁▃▁▇ 254.1 263.2 284.5 259.9 315.7

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L536"
target="_blank" style="float:right; font-size:smaller">source</a>

### stringfmt_names

>      stringfmt_names (s:str)

*Unique brace-delimited names in `s`*

``` python
s = '/pulls/{pull_number}/reviews/{review_id}'
test_eq(stringfmt_names(s), ['pull_number','review_id'])
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L541"
target="_blank" style="float:right; font-size:smaller">source</a>

#### PartialFormatter

>      PartialFormatter ()

*A `string.Formatter` that doesn’t error on missing fields, and tracks
missing fields and unused args*

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L557"
target="_blank" style="float:right; font-size:smaller">source</a>

### partial_format

>      partial_format (s:str, **kwargs)

*string format `s`, ignoring missing field errors, returning missing and
extra fields*

The result is a tuple of
`(formatted_string,missing_fields,extra_fields)`, e.g:

``` python
res,missing,xtra = partial_format(s, pull_number=1, foo=2)
test_eq(res, '/pulls/1/reviews/{review_id}')
test_eq(missing, ['review_id'])
test_eq(xtra, {'foo':2})
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L564"
target="_blank" style="float:right; font-size:smaller">source</a>

### utc2local

>      utc2local (dt:datetime.datetime)

*Convert `dt` from UTC to local time*

``` python
dt = datetime(2000,1,1,12)
print(f'{dt} UTC is {utc2local(dt)} local time')
```

    2000-01-01 12:00:00 UTC is 2000-01-01 22:00:00+10:00 local time

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L569"
target="_blank" style="float:right; font-size:smaller">source</a>

### local2utc

>      local2utc (dt:datetime.datetime)

*Convert `dt` from local to UTC time*

``` python
print(f'{dt} local is {local2utc(dt)} UTC time')
```

    2000-01-01 12:00:00 local is 2000-01-01 02:00:00+00:00 UTC time

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L574"
target="_blank" style="float:right; font-size:smaller">source</a>

### trace

>      trace (f)

*Add `set_trace` to an existing function `f`*

You can add a breakpoint to an existing function, e.g:

``` python
Path.cwd = trace(Path.cwd)
Path.cwd()
```

Now, when the function is called it will drop you into the debugger.
Note, you must issue the `s` command when you begin to step into the
function that is being traced.

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L586"
target="_blank" style="float:right; font-size:smaller">source</a>

### modified_env

>      modified_env (*delete, **replace)

*Context manager temporarily modifying `os.environ` by deleting `delete`
and replacing `replace`*

``` python
# USER isn't in Cloud Linux Environments
env_test = 'USERNAME' if sys.platform == "win32" else 'SHELL'
oldusr = os.environ[env_test]

replace_param = {env_test: 'a'}
with modified_env('PATH', **replace_param):
    test_eq(os.environ[env_test], 'a')
    assert 'PATH' not in os.environ

assert 'PATH' in os.environ
test_eq(os.environ[env_test], oldusr)
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L598"
target="_blank" style="float:right; font-size:smaller">source</a>

#### ContextManagers

>      ContextManagers (mgrs)

*Wrapper for `contextlib.ExitStack` which enters a collection of context
managers*

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L605"
target="_blank" style="float:right; font-size:smaller">source</a>

### shufflish

>      shufflish (x, pct=0.04)

*Randomly relocate items of `x` up to `pct` of `len(x)` from their
starting location*

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L612"
target="_blank" style="float:right; font-size:smaller">source</a>

### console_help

>      console_help (libname:str)

*Show help for all console scripts from `libname`*

<table>
<thead>
<tr class="header">
<th></th>
<th><strong>Type</strong></th>
<th><strong>Details</strong></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>libname</td>
<td>str</td>
<td>name of library for console script listing</td>
</tr>
</tbody>
</table>

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L624"
target="_blank" style="float:right; font-size:smaller">source</a>

### hl_md

>      hl_md (s, lang='xml', show=True)

*Syntax highlight `s` using `lang`.*

When we display code in a notebook, it’s nice to highlight it, so we
create a function to simplify that:

``` python
hl_md('<test><xml foo="bar">a child</xml></test>')
```

``` xml
<test><xml foo="bar">a child</xml></test>
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L634"
target="_blank" style="float:right; font-size:smaller">source</a>

### type2str

>      type2str (typ:type)

*Stringify `typ`*

``` python
test_eq(type2str(Optional[float]), 'Union[float, None]')
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L645"
target="_blank" style="float:right; font-size:smaller">source</a>

### dataclass_src

>      dataclass_src (cls)

``` python
DC = make_dataclass('DC', [('x', int), ('y', Optional[float], None), ('z', float, None)])
print(dataclass_src(DC))
```

    @dataclass
    class DC:
        x: int
        y: Union[float, None] = None
        z: float = None

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L653"
target="_blank" style="float:right; font-size:smaller">source</a>

### Unset

>      Unset (value, names=None, module=None, qualname=None, type=None, start=1)

*An enumeration.*

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L661"
target="_blank" style="float:right; font-size:smaller">source</a>

### nullable_dc

>      nullable_dc (cls)

*Like `dataclass`, but default of `UNSET` added to fields without
defaults*

``` python
@nullable_dc
class Person: name: str; age: int; city: str = "Unknown"
Person(name="Bob")
```

    Person(name='Bob', age=UNSET, city='Unknown')

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L668"
target="_blank" style="float:right; font-size:smaller">source</a>

### make_nullable

>      make_nullable (clas)

``` python
@dataclass
class Person: name: str; age: int; city: str = "Unknown"

make_nullable(Person)
Person("Bob", city='NY')
```

    Person(name='Bob', age=UNSET, city='NY')

``` python
Person(name="Bob")
```

    Person(name='Bob', age=UNSET, city='Unknown')

``` python
Person("Bob", 34)
```

    Person(name='Bob', age=34, city='Unknown')

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L690"
target="_blank" style="float:right; font-size:smaller">source</a>

### flexiclass

>      flexiclass (cls)

*Convert `cls` into a `dataclass` like
[`make_nullable`](https://fastcore.fast.ai/xtras.html#make_nullable).
Converts in place and also returns the result.*

<table>
<thead>
<tr class="header">
<th></th>
<th><strong>Type</strong></th>
<th><strong>Details</strong></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>cls</td>
<td></td>
<td>The class to convert</td>
</tr>
<tr class="even">
<td><strong>Returns</strong></td>
<td><strong>dataclass</strong></td>
<td></td>
</tr>
</tbody>
</table>

This can be used as a decorator…

``` python
@flexiclass
class Person: name: str; age: int; city: str = "Unknown"

bob = Person(name="Bob")
bob
```

    Person(name='Bob', age=UNSET, city='Unknown')

…or can update the behavior of an existing class (or dataclass):

``` python
class Person: name: str; age: int; city: str = "Unknown"

flexiclass(Person)
bob = Person(name="Bob")
bob
```

    Person(name='Bob', age=UNSET, city='Unknown')

Action occurs in-place:

``` python
class Person: name: str; age: int; city: str = "Unknown"

flexiclass(Person)
is_dataclass(Person)
```

    True

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L701"
target="_blank" style="float:right; font-size:smaller">source</a>

### asdict

>      asdict (o)

*Convert `o` to a `dict`, supporting dataclasses, namedtuples,
iterables, and `__dict__` attrs.*

Any `UNSET` values are not included.

``` python
asdict(bob)
```

    {'name': 'Bob', 'city': 'Unknown'}

To customise dict conversion behavior for a class, implement the
`_asdict` method (this is used in the Python stdlib for named tuples).

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L714"
target="_blank" style="float:right; font-size:smaller">source</a>

### is_typeddict

>      is_typeddict (cls:type)

*Check if `cls` is a `TypedDict`*

``` python
class MyDict(TypedDict): name:str

assert is_typeddict(MyDict)
assert not is_typeddict({'a':1})
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L720"
target="_blank" style="float:right; font-size:smaller">source</a>

### is_namedtuple

>      is_namedtuple (cls)

*`True` if `cls` is a namedtuple type*

``` python
assert is_namedtuple(namedtuple('tst', ['a']))
assert not is_namedtuple(tuple)
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L725"
target="_blank" style="float:right; font-size:smaller">source</a>

### flexicache

>      flexicache (*funcs, maxsize=128)

*Like `lru_cache`, but customisable with policy `funcs`*

This is a flexible lru cache function that you can pass a list of
functions to. Those functions define the cache eviction policy. For
instance,
[`time_policy`](https://fastcore.fast.ai/xtras.html#time_policy) is
provided for time-based cache eviction, and
[`mtime_policy`](https://fastcore.fast.ai/xtras.html#mtime_policy)
evicts based on a file’s modified-time changing. The policy functions
are passed the last value that function returned was (initially `None`),
and return a new value to indicate the cache has expired. When the cache
expires, all functions are called with `None` to force getting new
values.

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L758"
target="_blank" style="float:right; font-size:smaller">source</a>

### time_policy

>      time_policy (seconds)

*A [`flexicache`](https://fastcore.fast.ai/xtras.html#flexicache) policy
that expires cached items after `seconds` have passed*

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L766"
target="_blank" style="float:right; font-size:smaller">source</a>

### mtime_policy

>      mtime_policy (filepath)

*A [`flexicache`](https://fastcore.fast.ai/xtras.html#flexicache) policy
that expires cached items after `filepath` modified-time changes*

``` python
@flexicache(time_policy(10), mtime_policy('000_tour.ipynb'))
def cached_func(x, y): return x+y

cached_func(1,2)
```

    3

``` python
@flexicache(time_policy(10), mtime_policy('000_tour.ipynb'))
async def cached_func(x, y): return x+y

await cached_func(1,2)
await cached_func(1,2)
```

    3

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xtras.py#L774"
target="_blank" style="float:right; font-size:smaller">source</a>

### timed_cache

>      timed_cache (seconds=60, maxsize=128)

*Like `lru_cache`, but also with time-based eviction*

This function is a small convenience wrapper for using
[`flexicache`](https://fastcore.fast.ai/xtras.html#flexicache) with
[`time_policy`](https://fastcore.fast.ai/xtras.html#time_policy).

``` python
@timed_cache(seconds=0.05, maxsize=2)
def cached_func(x): return x * 2, time()

# basic caching
result1, time1 = cached_func(2)
test_eq(result1, 4)
sleep(0.001)
result2, time2 = cached_func(2)
test_eq(result2, 4)
test_eq(time1, time2)

# caching different values
result3, _ = cached_func(3)
test_eq(result3, 6)

# maxsize
_, time4 = cached_func(4)
_, time2_new = cached_func(2)
test_close(time2, time2_new, eps=0.1)
_, time3_new = cached_func(3)
test_ne(time3_new, time())

# time expiration
sleep(0.05)
_, time4_new = cached_func(4)
test_ne(time4_new, time())
```</doc>
    <doc title="fastcore.parallel" desc="parallel processing"># Parallel



``` python
from fastcore.test import *
from nbdev.showdoc import *
from fastcore.nb_imports import *
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/parallel.py#L25"
target="_blank" style="float:right; font-size:smaller">source</a>

### threaded

>      threaded (process=False)

*Run `f` in a `Thread` (or `Process` if `process=True`), and returns it*

``` python
@threaded
def _1():
    time.sleep(0.05)
    print("second")
    return 5

@threaded
def _2():
    time.sleep(0.01)
    print("first")

a = _1()
_2()
time.sleep(0.1)
```

    first
    second

After the thread is complete, the return value is stored in the `result`
attr.

``` python
a.result
```

    5

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/parallel.py#L45"
target="_blank" style="float:right; font-size:smaller">source</a>

### startthread

>      startthread (f)

*Like [`threaded`](https://fastcore.fast.ai/parallel.html#threaded), but
start thread immediately*

``` python
@startthread
def _():
    time.sleep(0.05)
    print("second")

@startthread
def _():
    time.sleep(0.01)
    print("first")

time.sleep(0.1)
```

    first
    second

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/parallel.py#L50"
target="_blank" style="float:right; font-size:smaller">source</a>

### startproc

>      startproc (f)

*Like `threaded(True)`, but start Process immediately*

``` python
@startproc
def _():
    time.sleep(0.05)
    print("second")

@startproc
def _():
    time.sleep(0.01)
    print("first")

time.sleep(0.1)
```

    first
    second

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/parallel.py#L66"
target="_blank" style="float:right; font-size:smaller">source</a>

### parallelable

>      parallelable (param_name, num_workers, f=None)

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/parallel.py#L75"
target="_blank" style="float:right; font-size:smaller">source</a>

#### ThreadPoolExecutor

>      ThreadPoolExecutor (max_workers=4, on_exc=<built-in function print>,
>                          pause=0, **kwargs)

*Same as Python’s ThreadPoolExecutor, except can pass `max_workers==0`
for serial execution*

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/parallel.py#L94"
target="_blank" style="float:right; font-size:smaller">source</a>

#### ProcessPoolExecutor

>      ProcessPoolExecutor (max_workers=4, on_exc=<built-in function print>,
>                           pause=0, mp_context=None, initializer=None,
>                           initargs=())

*Same as Python’s ProcessPoolExecutor, except can pass `max_workers==0`
for serial execution*

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/parallel.py#L120"
target="_blank" style="float:right; font-size:smaller">source</a>

### parallel

>      parallel (f, items, *args, n_workers=4, total=None, progress=None,
>                pause=0, method=None, threadpool=False, timeout=None,
>                chunksize=1, **kwargs)

*Applies `func` in parallel to `items`, using `n_workers`*

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/parallel.py#L137"
target="_blank" style="float:right; font-size:smaller">source</a>

### add_one

>      add_one (x, a=1)

``` python
inp,exp = range(50),range(1,51)

test_eq(parallel(add_one, inp, n_workers=2, progress=False), exp)
test_eq(parallel(add_one, inp, threadpool=True, n_workers=2, progress=False), exp)
test_eq(parallel(add_one, inp, n_workers=1, a=2), range(2,52))
test_eq(parallel(add_one, inp, n_workers=0), exp)
test_eq(parallel(add_one, inp, n_workers=0, a=2), range(2,52))
```

Use the `pause` parameter to ensure a pause of `pause` seconds between
processes starting. This is in case there are race conditions in
starting some process, or to stagger the time each process starts, for
example when making many requests to a webserver. Set `threadpool=True`
to use
[`ThreadPoolExecutor`](https://fastcore.fast.ai/parallel.html#threadpoolexecutor)
instead of
[`ProcessPoolExecutor`](https://fastcore.fast.ai/parallel.html#processpoolexecutor).

``` python
from datetime import datetime
```

``` python
def print_time(i): 
    time.sleep(random.random()/1000)
    print(i, datetime.now())

parallel(print_time, range(5), n_workers=2, pause=0.25);
```

    0 2022-08-07 05:10:05.999916
    1 2022-08-07 05:10:06.252031
    2 2022-08-07 05:10:06.503603
    3 2022-08-07 05:10:06.755216
    4 2022-08-07 05:10:07.006702

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/parallel.py#L144"
target="_blank" style="float:right; font-size:smaller">source</a>

### run_procs

>      run_procs (f, f_done, args)

*Call `f` for each item in `args` in parallel, yielding `f_done`*

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/parallel.py#L158"
target="_blank" style="float:right; font-size:smaller">source</a>

### parallel_gen

>      parallel_gen (cls, items, n_workers=4, **kwargs)

*Instantiate `cls` in `n_workers` procs & call each on a subset of
`items` in parallel.*

``` python
# class _C:
#     def __call__(self, o): return ((i+1) for i in o)

# items = range(5)

# res = L(parallel_gen(_C, items, n_workers=0))
# idxs,dat1 = zip(*res.sorted(itemgetter(0)))
# test_eq(dat1, range(1,6))

# res = L(parallel_gen(_C, items, n_workers=3))
# idxs,dat2 = zip(*res.sorted(itemgetter(0)))
# test_eq(dat2, dat1)
```

`cls` is any class with `__call__`. It will be passed `args` and
`kwargs` when initialized. Note that `n_workers` instances of `cls` are
created, one in each process. `items` are then split in `n_workers`
batches and one is sent to each `cls`. The function then returns a
generator of tuples of item indices and results.

``` python
class TestSleepyBatchFunc:
    "For testing parallel processes that run at different speeds"
    def __init__(self): self.a=1
    def __call__(self, batch):
        for k in batch:
            time.sleep(random.random()/4)
            yield k+self.a

x = np.linspace(0,0.99,20)

res = L(parallel_gen(TestSleepyBatchFunc, x, n_workers=2))
test_eq(res.sorted().itemgot(1), x+1)
```

<style>
    /* Turns off some styling */
    progress {
        /* gets rid of default border in Firefox and Opera. */
        border: none;
        /* Needs to be in here for Safari polyfill so background images work as expected. */
        background-size: auto;
    }
    progress:not([value]), progress:not([value])::-webkit-progress-bar {
        background: repeating-linear-gradient(45deg, #7e7e7e, #7e7e7e 10px, #5c5c5c 10px, #5c5c5c 20px);
    }
    .progress-bar-interrupted, .progress-bar-interrupted::-webkit-progress-bar {
        background: #F44336;
    }
</style>

``` python
# #|hide
# from subprocess import Popen, PIPE
# # test num_workers > 0 in scripts works when python process start method is spawn
# process = Popen(["python", "parallel_test.py"], stdout=PIPE)
# _, err = process.communicate(timeout=10)
# exit_code = process.wait()
# test_eq(exit_code, 0)
```</doc>
    <doc title="fastcore.net" desc="testing utilities"># Network functionality



``` python
from fastcore.test import *
from nbdev.showdoc import *
from fastcore.nb_imports import *
```

## URLs

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/net.py#L48"
target="_blank" style="float:right; font-size:smaller">source</a>

### urlquote

>      urlquote (url)

*Update url’s path with `urllib.parse.quote`*

``` python
urlquote("https://github.com/fastai/fastai/compare/master@{1.day.ago}…master")
```

    'https://github.com/fastai/fastai/compare/master@%7B1.day.ago%7D%E2%80%A6master'

``` python
urlquote("https://www.google.com/search?q=你好")
```

    'https://www.google.com/search?q=%E4%BD%A0%E5%A5%BD'

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/net.py#L59"
target="_blank" style="float:right; font-size:smaller">source</a>

### urlwrap

>      urlwrap (url, data=None, headers=None)

*Wrap `url` in a urllib `Request` with
[`urlquote`](https://fastcore.fast.ai/net.html#urlquote)*

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/net.py#L67"
target="_blank" style="float:right; font-size:smaller">source</a>

#### HTTP4xxClientError

>      HTTP4xxClientError (url, code, msg, hdrs, fp)

*Base class for client exceptions (code 4xx) from `url*` functions*

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/net.py#L72"
target="_blank" style="float:right; font-size:smaller">source</a>

#### HTTP5xxServerError

>      HTTP5xxServerError (url, code, msg, hdrs, fp)

*Base class for server exceptions (code 5xx) from `url*` functions*

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/net.py#L77"
target="_blank" style="float:right; font-size:smaller">source</a>

### urlopener

>      urlopener ()

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/net.py#L105"
target="_blank" style="float:right; font-size:smaller">source</a>

### urlopen

>      urlopen (url, data=None, headers=None, timeout=None, **kwargs)

*Like `urllib.request.urlopen`, but first
[`urlwrap`](https://fastcore.fast.ai/net.html#urlwrap) the `url`, and
encode `data`*

With [`urlopen`](https://fastcore.fast.ai/net.html#urlopen), the body of
the response will also be returned in addition to the message if there
is an error:

``` python
try: urlopen('https://api.github.com/v3')
except HTTPError as e: 
    print(e.code, e.msg)
    assert 'documentation_url' in e.msg
```

    404 Not Found
    ====Error Body====
    {
      "message": "Not Found",
      "documentation_url": "https://docs.github.com/rest"
    }

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/net.py#L117"
target="_blank" style="float:right; font-size:smaller">source</a>

### urlread

>      urlread (url, data=None, headers=None, decode=True, return_json=False,
>               return_headers=False, timeout=None, **kwargs)

*Retrieve `url`, using `data` dict or `kwargs` to `POST` if present*

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/net.py#L130"
target="_blank" style="float:right; font-size:smaller">source</a>

### urljson

>      urljson (url, data=None, timeout=None)

*Retrieve `url` and decode json*

``` python
test_eq(urljson('https://httpbin.org/get')['headers']['User-Agent'], url_default_headers['User-Agent'])
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/net.py#L136"
target="_blank" style="float:right; font-size:smaller">source</a>

### urlcheck

>      urlcheck (url, headers=None, timeout=10)

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/net.py#L145"
target="_blank" style="float:right; font-size:smaller">source</a>

### urlclean

>      urlclean (url)

*Remove fragment, params, and querystring from `url` if present*

``` python
test_eq(urlclean('http://a.com/b?c=1#d'), 'http://a.com/b')
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/net.py#L150"
target="_blank" style="float:right; font-size:smaller">source</a>

### urlretrieve

>      urlretrieve (url, filename=None, reporthook=None, data=None,
>                   headers=None, timeout=None)

*Same as `urllib.request.urlretrieve` but also works with `Request`
objects*

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/net.py#L176"
target="_blank" style="float:right; font-size:smaller">source</a>

### urldest

>      urldest (url, dest=None)

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/net.py#L183"
target="_blank" style="float:right; font-size:smaller">source</a>

### urlsave

>      urlsave (url, dest=None, reporthook=None, headers=None, timeout=None)

*Retrieve `url` and save based on its name*

``` python
#skip
with tempfile.TemporaryDirectory() as d: urlsave('http://www.google.com/index.html', d)
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/net.py#L191"
target="_blank" style="float:right; font-size:smaller">source</a>

### urlvalid

>      urlvalid (x)

*Test if `x` is a valid URL*

``` python
assert urlvalid('http://www.google.com/')
assert not urlvalid('www.google.com/')
assert not urlvalid(1)
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/net.py#L196"
target="_blank" style="float:right; font-size:smaller">source</a>

### urlrequest

>      urlrequest (url, verb, headers=None, route=None, query=None, data=None,
>                  json_data=True)

*`Request` for `url` with optional route params replaced by `route`,
plus `query` string, and post `data`*

``` python
hdr = {'Hdr1':'1', 'Hdr2':'2'}
req = urlrequest('http://example.com/{foo}/1', 'POST',
                 headers=hdr, route={'foo':'3'}, query={'q':'4'}, data={'d':'5'})

test_eq(req.headers, hdr)
test_eq(req.full_url, 'http://example.com/3/1?q=4')
test_eq(req.method, 'POST')
test_eq(req.data, b'{"d": "5"}')
```

``` python
req = urlrequest('http://example.com/{foo}/1', 'POST', data={'d':'5','e':'6'}, headers=hdr, json_data=False)
test_eq(req.data, b'd=5&e=6')
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/net.py#L205"
target="_blank" style="float:right; font-size:smaller">source</a>

### Request.summary

>      Request.summary (skip=None)

*Summary containing full_url, headers, method, and data, removing `skip`
from headers*

``` python
req.summary(skip='Hdr1')
```

    {'full_url': 'http://example.com/{foo}/1',
     'method': 'POST',
     'data': b'd=5&e=6',
     'headers': {'Hdr2': '2'}}

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/net.py#L212"
target="_blank" style="float:right; font-size:smaller">source</a>

### urlsend

>      urlsend (url, verb, headers=None, decode=True, route=None, query=None,
>               data=None, json_data=True, return_json=True,
>               return_headers=False, debug=None, timeout=None)

*Send request with
[`urlrequest`](https://fastcore.fast.ai/net.html#urlrequest), converting
result to json if `return_json`*

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/net.py#L224"
target="_blank" style="float:right; font-size:smaller">source</a>

### do_request

>      do_request (url, post=False, headers=None, **data)

*Call GET or json-encoded POST on `url`, depending on `post`*

## Basic client/server

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/net.py#L240"
target="_blank" style="float:right; font-size:smaller">source</a>

### start_server

>      start_server (port, host=None, dgram=False, reuse_addr=True,
>                    n_queue=None)

*Create a `socket` server on `port`, with optional `host`, of type
`dgram`*

You can create a TCP client and server pass an int as `port` and
optional `host`. `host` defaults to your main network interface if not
provided. You can create a Unix socket client and server by passing a
string to `port`. A `SOCK_STREAM` socket is created by default, unless
you pass `dgram=True`, in which case a `SOCK_DGRAM` socket is created.
`n_queue` sets the listening queue size.

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/net.py#L254"
target="_blank" style="float:right; font-size:smaller">source</a>

### start_client

>      start_client (port, host=None, dgram=False)

*Create a `socket` client on `port`, with optional `host`, of type
`dgram`*

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/net.py#L262"
target="_blank" style="float:right; font-size:smaller">source</a>

### tobytes

>      tobytes (s:str)

*Convert `s` into HTTP-ready bytes format*

``` python
test_eq(tobytes('foo\nbar'), b'foo\r\nbar')
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/net.py#L267"
target="_blank" style="float:right; font-size:smaller">source</a>

### http_response

>      http_response (body=None, status=200, hdrs=None, **kwargs)

*Create an HTTP-ready response, adding `kwargs` to `hdrs`*

``` python
exp = b'HTTP/1.1 200 OK\r\nUser-Agent: me\r\nContent-Length: 4\r\n\r\nbody'
test_eq(http_response('body', 200, User_Agent='me'), exp)
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/net.py#L279"
target="_blank" style="float:right; font-size:smaller">source</a>

### recv_once

>      recv_once (host:str='localhost', port:int=8000)

*Spawn a thread to receive a single HTTP request and store in `d['r']`*</doc>
    <doc title="fastcore.docments" desc="documentation utilities"># Docments



[`docments`](https://fastcore.fast.ai/docments.html#docments) provides
programmatic access to comments in function parameters and return types.
It can be used to create more developer-friendly documentation, CLI, etc
tools.

## Why?

Without docments, if you want to document your parameters, you have to
repeat param names in docstrings, since they’re already in the function
signature. The parameters have to be kept synchronized in the two places
as you change your code. Readers of your code have to look back and
forth between two places to understand what’s happening. So it’s more
work for you, and for your users.

Furthermore, to have parameter documentation formatted nicely without
docments, you have to use special magic docstring formatting, often with
[odd
quirks](https://stackoverflow.com/questions/62167540/why-do-definitions-have-a-space-before-the-colon-in-numpy-docstring-sections),
which is a pain to create and maintain, and awkward to read in code. For
instance, using [numpy-style
documentation](https://numpydoc.readthedocs.io/en/latest/format.html):

``` python
def add_np(a:int, b:int=0)->int:
    """The sum of two numbers.
    
    Used to demonstrate numpy-style docstrings.

Parameters
----------
a : int
    the 1st number to add
b : int
    the 2nd number to add (default: 0)

Returns
-------
int
    the result of adding `a` to `b`"""
    return a+b
```

By comparison, here’s the same thing using docments:

``` python
def add(
    a:int, # the 1st number to add
    b=0,   # the 2nd number to add
)->int:    # the result of adding `a` to `b`
    "The sum of two numbers."
    return a+b
```

## Numpy docstring helper functions

[`docments`](https://fastcore.fast.ai/docments.html#docments) also
supports numpy-style docstrings, or a mix or numpy-style and docments
parameter documentation. The functions in this section help get and
parse this information.

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/docments.py#L26"
target="_blank" style="float:right; font-size:smaller">source</a>

### docstring

>      docstring (sym)

*Get docstring for `sym` for functions ad classes*

``` python
test_eq(docstring(add), "The sum of two numbers.")
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/docments.py#L34"
target="_blank" style="float:right; font-size:smaller">source</a>

### parse_docstring

>      parse_docstring (sym)

*Parse a numpy-style docstring in `sym`*

``` python
# parse_docstring(add_np)
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/docments.py#L40"
target="_blank" style="float:right; font-size:smaller">source</a>

### isdataclass

>      isdataclass (s)

*Check if `s` is a dataclass but not a dataclass’ instance*

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/docments.py#L45"
target="_blank" style="float:right; font-size:smaller">source</a>

### get_dataclass_source

>      get_dataclass_source (s)

*Get source code for dataclass `s`*

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/docments.py#L50"
target="_blank" style="float:right; font-size:smaller">source</a>

### get_source

>      get_source (s)

*Get source code for string, function object or dataclass `s`*

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/docments.py#L121"
target="_blank" style="float:right; font-size:smaller">source</a>

### get_name

>      get_name (obj)

*Get the name of `obj`*

``` python
test_eq(get_name(in_ipython), 'in_ipython')
test_eq(get_name(L.map), 'map')
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/docments.py#L130"
target="_blank" style="float:right; font-size:smaller">source</a>

### qual_name

>      qual_name (obj)

*Get the qualified name of `obj`*

``` python
assert qual_name(docscrape) == 'fastcore.docscrape'
```

## Docments

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/docments.py#L157"
target="_blank" style="float:right; font-size:smaller">source</a>

### docments

>      docments (elt, full=False, returns=True, eval_str=False)

*Generates a `docment`*

The returned `dict` has parameter names as keys, docments as values. The
return value comment appears in the `return`, unless `returns=False`.
Using the `add` definition above, we get:

``` python
def add(
    a:int, # the 1st number to add
    b=0,   # the 2nd number to add
)->int:    # the result of adding `a` to `b`
    "The sum of two numbers."
    return a+b

docments(add)
```

``` json
{ 'a': 'the 1st number to add',
  'b': 'the 2nd number to add',
  'return': 'the result of adding `a` to `b`'}
```

If you pass `full=True`, the values are `dict` of defaults, types, and
docments as values. Note that the type annotation is inferred from the
default value, if the annotation is empty and a default is supplied.

``` python
docments(add, full=True)
```

``` json
{ 'a': { 'anno': <class 'int'>,
         'default': <class 'inspect._empty'>,
         'docment': 'the 1st number to add'},
  'b': { 'anno': <class 'int'>,
         'default': 0,
         'docment': 'the 2nd number to add'},
  'return': { 'anno': <class 'int'>,
              'default': <class 'inspect._empty'>,
              'docment': 'the result of adding `a` to `b`'}}
```

To evaluate stringified annotations (from python 3.10), use `eval_str`:

``` python
docments(add, full=True, eval_str=True)['a']
```

``` json
{ 'anno': <class 'int'>,
  'default': <class 'inspect._empty'>,
  'docment': 'the 1st number to add'}
```

If you need more space to document a parameter, place one or more lines
of comments above the parameter, or above the return type. You can
mix-and-match these docment styles:

``` python
def add(
    # The first operand
    a:int,
    # This is the second of the operands to the *addition* operator.
    # Note that passing a negative value here is the equivalent of the *subtraction* operator.
    b:int,
)->int: # The result is calculated using Python's builtin `+` operator.
    "Add `a` to `b`"
    return a+b
```

``` python
docments(add)
```

``` json
{ 'a': 'The first operand',
  'b': 'This is the second of the operands to the *addition* operator.\n'
       'Note that passing a negative value here is the equivalent of the '
       '*subtraction* operator.',
  'return': "The result is calculated using Python's builtin `+` operator."}
```

Docments works with async functions, too:

``` python
async def add_async(
    # The first operand
    a:int,
    # This is the second of the operands to the *addition* operator.
    # Note that passing a negative value here is the equivalent of the *subtraction* operator.
    b:int,
)->int: # The result is calculated using Python's builtin `+` operator.
    "Add `a` to `b`"
    return a+b
```

``` python
test_eq(docments(add_async), docments(add))
```

You can also use docments with classes and methods:

``` python
class Adder:
    "An addition calculator"
    def __init__(self,
        a:int, # First operand
        b:int, # 2nd operand
    ): self.a,self.b = a,b
    
    def calculate(self
                 )->int: # Integral result of addition operator
        "Add `a` to `b`"
        return a+b
```

``` python
docments(Adder)
```

``` json
{'a': 'First operand', 'b': '2nd operand', 'return': None}
```

``` python
docments(Adder.calculate)
```

``` json
{'return': 'Integral result of addition operator', 'self': None}
```

docments can also be extracted from numpy-style docstrings:

``` python
print(add_np.__doc__)
```

    The sum of two numbers.
        
        Used to demonstrate numpy-style docstrings.

    Parameters
    ----------
    a : int
        the 1st number to add
    b : int
        the 2nd number to add (default: 0)

    Returns
    -------
    int
        the result of adding `a` to `b`

``` python
docments(add_np)
```

``` json
{ 'a': 'the 1st number to add',
  'b': 'the 2nd number to add (default: 0)',
  'return': 'the result of adding `a` to `b`'}
```

You can even mix and match docments and numpy parameters:

``` python
def add_mixed(a:int, # the first number to add
              b
             )->int: # the result
    """The sum of two numbers.

Parameters
----------
b : int
    the 2nd number to add (default: 0)"""
    return a+b
```

``` python
docments(add_mixed, full=True)
```

``` json
{ 'a': { 'anno': <class 'int'>,
         'default': <class 'inspect._empty'>,
         'docment': 'the first number to add'},
  'b': { 'anno': 'int',
         'default': <class 'inspect._empty'>,
         'docment': 'the 2nd number to add (default: 0)'},
  'return': { 'anno': <class 'int'>,
              'default': <class 'inspect._empty'>,
              'docment': 'the result'}}
```

You can use docments with dataclasses, however if the class was defined
in online notebook, docments will not contain parameters’ comments. This
is because the source code is not available in the notebook. After
converting the notebook to a module, the docments will be available.
Thus, documentation will have correct parameters’ comments.

Docments even works with
[`delegates`](https://fastcore.fast.ai/meta.html#delegates):

``` python
from fastcore.meta import delegates
```

``` python
def _a(a:int=2): return a # First

@delegates(_a)
def _b(b:str, **kwargs): return b, (_a(**kwargs)) # Second

docments(_b)
```

``` json
{'a': 'First', 'b': 'Second', 'return': None}
```

## Extract docstrings

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/docments.py#L210"
target="_blank" style="float:right; font-size:smaller">source</a>

### extract_docstrings

>      extract_docstrings (code)

*Create a dict from function/class/method names to tuples of docstrings
and param lists*

``` python
sample_code = """
"This is a module."

def top_func(a, b, *args, **kw):
    "This is top-level."
    pass

class SampleClass:
    "This is a class."

    def __init__(self, x, y):
        "Constructor for SampleClass."
        pass

    def method1(self, param1):
        "This is method1."
        pass

    def _private_method(self):
        "This should not be included."
        pass

class AnotherClass:
    def __init__(self, a, b):
        "This class has no separate docstring."
        pass"""

exp = {'_module': ('This is a module.', ''),
       'top_func': ('This is top-level.', 'a, b, *args, **kw'),
       'SampleClass': ('This is a class.', 'self, x, y'),
       'SampleClass.method1': ('This is method1.', 'self, param1'),
       'AnotherClass': ('This class has no separate docstring.', 'self, a, b')}
test_eq(extract_docstrings(sample_code), exp)
```</doc>
    <doc title="fastcore.meta" desc="metaclasses"># Meta



``` python
from fastcore.foundation import *
from nbdev.showdoc import *
from fastcore.nb_imports import *
```

See this [blog post](https://realpython.com/python-metaclasses/) for
more information about metaclasses.

- [`FixSigMeta`](https://fastcore.fast.ai/meta.html#fixsigmeta)
  preserves information that enables [intropsection of
  signatures](https://www.python.org/dev/peps/pep-0362/#:~:text=Python%20has%20always%20supported%20powerful,fully%20reconstruct%20the%20function's%20signature.)
  (i.e. tab completion in IDEs) when certain types of inheritence would
  otherwise obfuscate this introspection.
- [`PrePostInitMeta`](https://fastcore.fast.ai/meta.html#prepostinitmeta)
  ensures that the classes defined with it run `__pre_init__` and
  `__post_init__` (without having to write `self.__pre_init__()` and
  `self.__post_init__()` in the actual `init`
- [`NewChkMeta`](https://fastcore.fast.ai/meta.html#newchkmeta) gives
  the
  [`PrePostInitMeta`](https://fastcore.fast.ai/meta.html#prepostinitmeta)
  functionality and ensures classes defined with it don’t re-create an
  object of their type whenever it’s passed to the constructor
- [`BypassNewMeta`](https://fastcore.fast.ai/meta.html#bypassnewmeta)
  ensures classes defined with it can easily be casted form objects they
  subclass.

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/meta.py#L17"
target="_blank" style="float:right; font-size:smaller">source</a>

### test_sig

>      test_sig (f, b)

*Test the signature of an object*

``` python
def func_1(h,i,j): pass
def func_2(h,i=3, j=[5,6]): pass

class T:
    def __init__(self, a, b): pass

test_sig(func_1, '(h, i, j)')
test_sig(func_2, '(h, i=3, j=[5, 6])')
test_sig(T, '(a, b)')
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/meta.py#L28"
target="_blank" style="float:right; font-size:smaller">source</a>

### FixSigMeta

>      FixSigMeta (name, bases, dict)

*A metaclass that fixes the signature on classes that override
`__new__`*

When you inherit from a class that defines `__new__`, or a metaclass
that defines `__call__`, the signature of your `__init__` method is
obfuscated such that tab completion no longer works.
[`FixSigMeta`](https://fastcore.fast.ai/meta.html#fixsigmeta) fixes this
issue and restores signatures.

To understand what
[`FixSigMeta`](https://fastcore.fast.ai/meta.html#fixsigmeta) does, it
is useful to inspect an object’s signature. You can inspect the
signature of an object with `inspect.signature`:

``` python
class T:
    def __init__(self, a, b, c): pass
    
inspect.signature(T)
```

    <Signature (a, b, c)>

This corresponds to tab completion working in the normal way:

<img alt="Tab completion in a Jupyter Notebook." caption="" src="images/att_00005.png">

However, when you inherhit from a class that defines `__new__` or a
metaclass that defines `__call__` this obfuscates the signature by
overriding your class with the signature of `__new__`, which prevents
tab completion from displaying useful information:

``` python
class Foo:
    def __new__(self, **args): pass

class Bar(Foo):
    def __init__(self, d, e, f): pass
    
inspect.signature(Bar)
```

    <Signature (d, e, f)>

<img alt="Tab completion in a Jupyter Notebook." caption="" src="images/att_00006.png">

Finally, the signature and tab completion can be restored by inheriting
from the metaclass
[`FixSigMeta`](https://fastcore.fast.ai/meta.html#fixsigmeta) as shown
below:

``` python
class Bar(Foo, metaclass=FixSigMeta):
    def __init__(self, d, e, f): pass
    
test_sig(Bar, '(d, e, f)')
inspect.signature(Bar)
```

    <Signature (d, e, f)>

<img alt="Tab completion in a Jupyter Notebook." caption="" src="images/att_00007.png">

If you need to define a metaclass that overrides `__call__` (as done in
[`PrePostInitMeta`](https://fastcore.fast.ai/meta.html#prepostinitmeta)),
you need to inherit from
[`FixSigMeta`](https://fastcore.fast.ai/meta.html#fixsigmeta) instead of
`type` when constructing the metaclass to preserve the signature in
`__init__`. Be careful not to override `__new__` when doing this:

``` python
class TestMeta(FixSigMeta):
    # __new__ comes from FixSigMeta
    def __call__(cls, *args, **kwargs): pass
    
class T(metaclass=TestMeta):
    def __init__(self, a, b): pass
    
test_sig(T, '(a, b)')
```

On the other hand, if you fail to inherit from
[`FixSigMeta`](https://fastcore.fast.ai/meta.html#fixsigmeta) when
inheriting from a metaclass that overrides `__call__`, your signature
will reflect that of `__call__` instead (which is often undesirable):

``` python
class GenericMeta(type):
    "A boilerplate metaclass that doesn't do anything for testing."
    def __new__(cls, name, bases, dict):
        return super().__new__(cls, name, bases, dict)
    def __call__(cls, *args, **kwargs): pass

class T2(metaclass=GenericMeta):
    def __init__(self, a, b): pass

# We can avoid this by inheriting from the metaclass `FixSigMeta`
test_sig(T2, '(*args, **kwargs)')
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/meta.py#L36"
target="_blank" style="float:right; font-size:smaller">source</a>

### PrePostInitMeta

>      PrePostInitMeta (name, bases, dict)

*A metaclass that calls optional `__pre_init__` and `__post_init__`
methods*

`__pre_init__` and `__post_init__` are useful for initializing variables
or performing tasks prior to or after `__init__` being called,
respectively. Fore example:

``` python
class _T(metaclass=PrePostInitMeta):
    def __pre_init__(self):  self.a  = 0; 
    def __init__(self,b=0):  self.b = self.a + 1; assert self.b==1
    def __post_init__(self): self.c = self.b + 2; assert self.c==3

t = _T()
test_eq(t.a, 0) # set with __pre_init__
test_eq(t.b, 1) # set with __init__
test_eq(t.c, 3) # set with __post_init__
```

One use for
[`PrePostInitMeta`](https://fastcore.fast.ai/meta.html#prepostinitmeta)
is avoiding the `__super__().__init__()` boilerplate associated with
subclassing, such as used in
[`AutoInit`](https://fastcore.fast.ai/meta.html#autoinit).

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/meta.py#L47"
target="_blank" style="float:right; font-size:smaller">source</a>

### AutoInit

>      AutoInit (*args, **kwargs)

*Same as `object`, but no need for subclasses to call
`super().__init__`*

This is normally used as a
[mixin](https://www.residentmar.io/2019/07/07/python-mixins.html), eg:

``` python
class TestParent():
    def __init__(self): self.h = 10
        
class TestChild(AutoInit, TestParent):
    def __init__(self): self.k = self.h + 2
    
t = TestChild()
test_eq(t.h, 10) # h=10 is initialized in the parent class
test_eq(t.k, 12)
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/meta.py#L52"
target="_blank" style="float:right; font-size:smaller">source</a>

### NewChkMeta

>      NewChkMeta (name, bases, dict)

*Metaclass to avoid recreating object passed to constructor*

[`NewChkMeta`](https://fastcore.fast.ai/meta.html#newchkmeta) is used
when an object of the same type is the first argument to your class’s
constructor (i.e. the `__init__` function), and you would rather it not
create a new object but point to the same exact object.

This is used in [`L`](https://fastcore.fast.ai/foundation.html#l), for
example, to avoid creating a new object when the object is already of
type [`L`](https://fastcore.fast.ai/foundation.html#l). This allows the
users to defenisvely instantiate an
[`L`](https://fastcore.fast.ai/foundation.html#l) object and just return
a reference to the same object if it already happens to be of type
[`L`](https://fastcore.fast.ai/foundation.html#l).

For example, the below class `_T` **optionally** accepts an object `o`
as its first argument. A new object is returned upon instantiation per
usual:

``` python
class _T():
    "Testing"
    def __init__(self, o): 
        # if `o` is not an object without an attribute `foo`, set foo = 1
        self.foo = getattr(o,'foo',1)
```

``` python
t = _T(3)
test_eq(t.foo,1) # 1 was not of type _T, so foo = 1

t2 = _T(t) #t1 is of type _T
assert t is not t2 # t1 and t2 are different objects
```

However, if we want `_T` to return a reference to the same object when
passed an an object of type `_T` we can inherit from the
[`NewChkMeta`](https://fastcore.fast.ai/meta.html#newchkmeta) class as
illustrated below:

``` python
class _T(metaclass=NewChkMeta):
    "Testing with metaclass NewChkMeta"
    def __init__(self, o=None, b=1):
        # if `o` is not an object without an attribute `foo`, set foo = 1
        self.foo = getattr(o,'foo',1)
        self.b = b
```

We can now test `t` and `t2` are now pointing at the same object when
using this new definition of `_T`:

``` python
t = _T(3)
test_eq(t.foo,1) # 1 was not of type _T, so foo = 1

t2 = _T(t) # t2 will now reference t

test_is(t, t2) # t and t2 are the same object
t2.foo = 5 # this will also change t.foo to 5 because it is the same object
test_eq(t.foo, 5)
test_eq(t2.foo, 5)
```

However, there is one exception to how
[`NewChkMeta`](https://fastcore.fast.ai/meta.html#newchkmeta) works.
**If you pass any additional arguments in the constructor a new object
is returned**, even if the first object is of the same type. For
example, consider the below example where we pass the additional
argument `b` into the constructor:

``` python
t3 = _T(t, b=1)
assert t3 is not t

t4 = _T(t) # without any arguments the constructor will return a reference to the same object
assert t4 is t
```

Finally, it should be noted that
[`NewChkMeta`](https://fastcore.fast.ai/meta.html#newchkmeta) as well as
all other metaclases in this section, inherit from
[`FixSigMeta`](https://fastcore.fast.ai/meta.html#fixsigmeta). This
means class signatures will always be preserved when inheriting from
this metaclass (see docs for
[`FixSigMeta`](https://fastcore.fast.ai/meta.html#fixsigmeta) for more
details):

``` python
test_sig(_T, '(o=None, b=1)')
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/meta.py#L60"
target="_blank" style="float:right; font-size:smaller">source</a>

### BypassNewMeta

>      BypassNewMeta (name, bases, dict)

*Metaclass: casts `x` to this class if it’s of type `cls._bypass_type`*

[`BypassNewMeta`](https://fastcore.fast.ai/meta.html#bypassnewmeta) is
identical to
[`NewChkMeta`](https://fastcore.fast.ai/meta.html#newchkmeta), except
for checking for a class as the same type, we instead check for a class
of type specified in attribute `_bypass_type`.

In NewChkMeta, objects of the same type passed to the constructor
(without arguments) would result into a new variable referencing the
same object. However, with
[`BypassNewMeta`](https://fastcore.fast.ai/meta.html#bypassnewmeta) this
only occurs if the type matches the `_bypass_type` of the class you are
defining:

``` python
class _TestA: pass
class _TestB: pass

class _T(_TestA, metaclass=BypassNewMeta):
    _bypass_type=_TestB
    def __init__(self,x): self.x=x
```

In the below example, `t` does not refer to `t2` because `t` is of type
`_TestA` while `_T._bypass_type` is of type `TestB`:

``` python
t = _TestA()
t2 = _T(t)
assert t is not t2
```

However, if `t` is set to `_TestB` to match `_T._bypass_type`, then both
`t` and `t2` will refer to the same object.

``` python
t = _TestB()
t2 = _T(t)
t2.new_attr = 15

test_is(t, t2)
# since t2 just references t these will be the same
test_eq(t.new_attr, t2.new_attr)

# likewise, chaning an attribute on t will also affect t2 because they both point to the same object.
t.new_attr = 9
test_eq(t2.new_attr, 9)
```

## Metaprogramming

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/meta.py#L70"
target="_blank" style="float:right; font-size:smaller">source</a>

### empty2none

>      empty2none (p)

*Replace `Parameter.empty` with `None`*

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/meta.py#L75"
target="_blank" style="float:right; font-size:smaller">source</a>

### anno_dict

>      anno_dict (f)

*`__annotation__ dictionary with`empty`cast to`None\`, returning empty
if doesn’t exist*

``` python
def _f(a:int, b:L)->str: ...
test_eq(anno_dict(_f), {'a': int, 'b': L, 'return': str})
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/meta.py#L83"
target="_blank" style="float:right; font-size:smaller">source</a>

### use_kwargs_dict

>      use_kwargs_dict (keep=False, **kwargs)

*Decorator: replace `**kwargs` in signature with `names` params*

Replace all `**kwargs` with named arguments like so:

``` python
@use_kwargs_dict(y=1,z=None)
def foo(a, b=1, **kwargs): pass

test_sig(foo, '(a, b=1, *, y=1, z=None)')
```

Add named arguments, but optionally keep `**kwargs` by setting
`keep=True`:

``` python
@use_kwargs_dict(y=1,z=None, keep=True)
def foo(a, b=1, **kwargs): pass

test_sig(foo, '(a, b=1, *, y=1, z=None, **kwargs)')
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/meta.py#L97"
target="_blank" style="float:right; font-size:smaller">source</a>

### use_kwargs

>      use_kwargs (names, keep=False)

*Decorator: replace `**kwargs` in signature with `names` params*

[`use_kwargs`](https://fastcore.fast.ai/meta.html#use_kwargs) is
different than
[`use_kwargs_dict`](https://fastcore.fast.ai/meta.html#use_kwargs_dict)
as it only replaces `**kwargs` with named parameters without any default
values:

``` python
@use_kwargs(['y', 'z'])
def foo(a, b=1, **kwargs): pass

test_sig(foo, '(a, b=1, *, y=None, z=None)')
```

You may optionally keep the `**kwargs` argument in your signature by
setting `keep=True`:

``` python
@use_kwargs(['y', 'z'], keep=True)
def foo(a, *args, b=1, **kwargs): pass
test_sig(foo, '(a, *args, b=1, y=None, z=None, **kwargs)')
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/meta.py#L111"
target="_blank" style="float:right; font-size:smaller">source</a>

### delegates

>      delegates (to:function=None, keep=False, but:list=None)

*Decorator: replace `**kwargs` in signature with params from `to`*

<table>
<thead>
<tr class="header">
<th></th>
<th><strong>Type</strong></th>
<th><strong>Default</strong></th>
<th><strong>Details</strong></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>to</td>
<td>function</td>
<td>None</td>
<td>Delegatee</td>
</tr>
<tr class="even">
<td>keep</td>
<td>bool</td>
<td>False</td>
<td>Keep <code>kwargs</code> in decorated function?</td>
</tr>
<tr class="odd">
<td>but</td>
<td>list</td>
<td>None</td>
<td>Exclude these parameters from signature</td>
</tr>
</tbody>
</table>

A common Python idiom is to accept `**kwargs` in addition to named
parameters that are passed onto other function calls. It is especially
common to use `**kwargs` when you want to give the user an option to
override default parameters of any functions or methods being called by
the parent function.

For example, suppose we have have a function `foo` that passes arguments
to `baz` like so:

``` python
def baz(a, b:int=2, c:int=3): return a + b + c

def foo(c, a, **kwargs):
    return c + baz(a, **kwargs)

assert foo(c=1, a=1) == 7
```

The problem with this approach is the api for `foo` is obfuscated. Users
cannot introspect what the valid arguments for `**kwargs` are without
reading the source code. When a user tries tries to introspect the
signature of `foo`, they are presented with this:

``` python
inspect.signature(foo)
```

    <Signature (c, a, **kwargs)>

We can address this issue by using the decorator
[`delegates`](https://fastcore.fast.ai/meta.html#delegates) to include
parameters from other functions. For example, if we apply the
[`delegates`](https://fastcore.fast.ai/meta.html#delegates) decorator to
`foo` to include parameters from `baz`:

``` python
@delegates(baz)
def foo(c, a, **kwargs):
    return c + baz(a, **kwargs)

test_sig(foo, '(c, a, *, b: int = 2)')
inspect.signature(foo)
```

    <Signature (c, a, *, b: int = 2)>

We can optionally decide to keep `**kwargs` by setting `keep=True`:

``` python
@delegates(baz, keep=True)
def foo(c, a, **kwargs):
    return c + baz(a, **kwargs)

inspect.signature(foo)
```

    <Signature (c, a, *, b: int = 2, **kwargs)>

It is important to note that **only parameters with default parameters
are included**. For example, in the below scenario only `c`, but NOT `e`
and `d` are included in the signature of `foo` after applying
[`delegates`](https://fastcore.fast.ai/meta.html#delegates):

``` python
def basefoo(e, d, c=2): pass

@delegates(basefoo)
def foo(a, b=1, **kwargs): pass
inspect.signature(foo) # e and d are not included b/c they don't have default parameters.
```

    <Signature (a, b=1, *, c=2)>

The reason that required arguments (i.e. those without default
parameters) are automatically excluded is that you should be explicitly
implementing required arguments into your function’s signature rather
than relying on
[`delegates`](https://fastcore.fast.ai/meta.html#delegates).

Additionally, you can exclude specific parameters from being included in
the signature with the `but` parameter. In the example below, we exclude
the parameter `d`:

``` python
def basefoo(e, c=2, d=3): pass

@delegates(basefoo, but= ['d'])
def foo(a, b=1, **kwargs): pass

test_sig(foo, '(a, b=1, *, c=2)')
inspect.signature(foo)
```

    <Signature (a, b=1, *, c=2)>

You can also use
[`delegates`](https://fastcore.fast.ai/meta.html#delegates) between
methods in a class. Here is an example of
[`delegates`](https://fastcore.fast.ai/meta.html#delegates) with class
methods:

``` python
# example 1: class methods
class _T():
    @classmethod
    def foo(cls, a=1, b=2):
        pass
    
    @classmethod
    @delegates(foo)
    def bar(cls, c=3, **kwargs):
        pass

test_sig(_T.bar, '(c=3, *, a=1, b=2)')
```

Here is the same example with instance methods:

``` python
# example 2: instance methods
class _T():
    def foo(self, a=1, b=2):
        pass
    
    @delegates(foo)
    def bar(self, c=3, **kwargs):
        pass

t = _T()
test_sig(t.bar, '(c=3, *, a=1, b=2)')
```

You can also delegate between classes. By default, the
[`delegates`](https://fastcore.fast.ai/meta.html#delegates) decorator
will delegate to the superclass:

``` python
class BaseFoo:
    def __init__(self, e, c=2): pass

@delegates()# since no argument was passsed here we delegate to the superclass
class Foo(BaseFoo):
    def __init__(self, a, b=1, **kwargs): super().__init__(**kwargs)

test_sig(Foo, '(a, b=1, *, c=2)')
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/meta.py#L137"
target="_blank" style="float:right; font-size:smaller">source</a>

### method

>      method (f)

*Mark `f` as a method*

The [`method`](https://fastcore.fast.ai/meta.html#method) function is
used to change a function’s type to a method. In the below example we
change the type of `a` from a function to a method:

``` python
def a(x=2): return x + 1
assert type(a).__name__ == 'function'

a = method(a)
assert type(a).__name__ == 'method'
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/meta.py#L159"
target="_blank" style="float:right; font-size:smaller">source</a>

### funcs_kwargs

>      funcs_kwargs (as_method=False)

*Replace methods in `cls._methods` with those from `kwargs`*

The `func_kwargs` decorator allows you to add a list of functions or
methods to an existing class. You must set this list as a class
attribute named `_methods` when defining your class. Additionally, you
must incldue the `**kwargs` argument in the `___init__` method of your
class.

After defining your class this way, you can add functions to your class
upon instantation as illusrated below.

For example, we define class `T` to allow adding the function `b` to
class `T` as follows (note that this function is stored as an attribute
of `T` and doesn’t have access to `cls` or `self`):

``` python
@funcs_kwargs
class T:
    _methods=['b'] # allows you to add method b upon instantiation
    def __init__(self, f=1, **kwargs): pass # don't forget to include **kwargs in __init__
    def a(self): return 1
    def b(self): return 2
    
t = T()
test_eq(t.a(), 1)
test_eq(t.b(), 2)
```

Because we defined the class `T` this way, the signature of `T`
indicates the option to add the function or method(s) specified in
`_methods`. In this example, `b` is added to the signature:

``` python
test_sig(T, '(f=1, *, b=None)')
inspect.signature(T)
```

    <Signature (f=1, *, b=None)>

You can now add the function `b` to class `T` upon instantiation:

``` python
def _new_func(): return 5

t = T(b = _new_func)
test_eq(t.b(), 5)
```

If you try to add a function with a name not listed in `_methods` it
will be ignored. In the below example, the attempt to add a function
named `a` is ignored:

``` python
t = T(a = lambda:3)
test_eq(t.a(), 1) # the attempt to add a is ignored and uses the original method instead.
```

Note that you can also add methods not defined in the original class as
long it is specified in the `_methods` attribute:

``` python
@funcs_kwargs
class T:
    _methods=['c']
    def __init__(self, f=1, **kwargs): pass

t = T(c = lambda: 4)
test_eq(t.c(), 4)
```

Until now, these examples showed how to add functions stored as an
instance attribute without access to `self`. However, if you need access
to `self` you can set `as_method=True` in the `func_kwargs` decorator to
add a method instead:

``` python
def _f(self,a=1): return self.num + a # access the num attribute from the instance

@funcs_kwargs(as_method=True)
class T: 
    _methods=['b']
    num = 5
    
t = T(b = _f) # adds method b
test_eq(t.b(5), 10) # self.num + 5 = 10
```

Here is an example of how you might use this functionality with
inheritence:

``` python
def _f(self,a=1): return self.num * a #multiply instead of add 

class T2(T):
    def __init__(self,num):
        super().__init__(b = _f) # add method b from the super class
        self.num=num
        
t = T2(num=3)
test_eq(t.b(a=5), 15) # 3 * 5 = 15
test_sig(T2, '(num)')
```</doc>
    <doc title="fastcore.script" desc="CLI script utilities"># Script - CLI



Part of [fast.ai](https://www.fast.ai)’s toolkit for delightful
developer experiences.

## Overview

Sometimes, you want to create a quick script, either for yourself, or
for others. But in Python, that involves a whole lot of boilerplate and
ceremony, especially if you want to support command line arguments,
provide help, and other niceties. You can use
[argparse](https://docs.python.org/3/library/argparse.html) for this
purpose, which comes with Python, but it’s complex and verbose.

`fastcore.script` makes life easier. There are much fancier modules to
help you write scripts (we recommend [Python
Fire](https://github.com/google/python-fire), and
[Click](https://click.palletsprojects.com/en/7.x/) is also popular), but
fastcore.script is very fast and very simple. In fact, it’s \<50 lines
of code! Basically, it’s just a little wrapper around `argparse` that
uses modern Python features and some thoughtful defaults to get rid of
the boilerplate.

For full details, see the [docs](https://fastcore.script.fast.ai) for
`core`.

## Example

Here’s a complete example (available in `examples/test_fastcore.py`):

``` python
from fastcore.script import *
@call_parse
def main(msg:str,     # The message
         upper:bool): # Convert to uppercase?
    "Print `msg`, optionally converting to uppercase"
    print(msg.upper() if upper else msg)
```

If you copy that info a file and run it, you’ll see:

    $ examples/test_fastcore.py --help
    usage: test_fastcore.py [-h] [--upper] msg

    Print `msg`, optionally converting to uppercase

    positional arguments:
      msg          The message

    optional arguments:
      -h, --help   show this help message and exit
      --upper      Convert to uppercase? (default: False)

As you see, we didn’t need any `if __name__ == "__main__"`, we didn’t
have to parse arguments, we just wrote a function, added a decorator to
it, and added some annotations to our function’s parameters. As a bonus,
we can also use this function directly from a REPL such as Jupyter
Notebook - it’s not just for command line scripts!

You should provide a default (after the `=`) for any *optional*
parameters. If you don’t provide a default for a parameter, then it will
be a *positional* parameter.

## Param annotations

If you want to use the full power of `argparse`, you can do so by using
[`Param`](https://fastcore.fast.ai/script.html#param) annotations
instead of type annotations and
[docments](https://fastcore.fast.ai/docments.html), like so:

``` python
from fastcore.script import *
@call_parse
def main(msg:Param("The message", str),
         upper:Param("Convert to uppercase?", store_true)):
    "Print `msg`, optionally converting to uppercase"
    print(msg.upper() if upper else msg)
```

If you use this approach, then each parameter in your function should
have an annotation `Param(...)` (as in the example above). You can pass
the following when calling
[`Param`](https://fastcore.fast.ai/script.html#param):
`help`,`type`,`opt`,`action`,`nargs`,`const`,`choices`,`required` .
Except for `opt`, all of these are just passed directly to `argparse`,
so you have all the power of that module at your disposal. Generally
you’ll want to pass at least `help` (since this is provided as the help
string for that parameter) and `type` (to ensure that you get the type
of data you expect). `opt` is a bool that defines whether a param is
optional or required (positional) - but you’ll generally not need to set
this manually, because fastcore.script will set it for you automatically
based on *default* values.

## setuptools scripts

There’s a really nice feature of pip/setuptools that lets you create
commandline scripts directly from functions, makes them available in the
`PATH`, and even makes your scripts cross-platform (e.g. in Windows it
creates an exe). fastcore.script supports this feature too. The trick to
making a function available as a script is to add a `console_scripts`
section to your setup file, of the form:
`script_name=module:function_name`. E.g. in this case we use:
`test_fastcore.script=fastcore.script.test_cli:main`. With this, you can
then just type `test_fastcore.script` at any time, from any directory,
and your script will be called (once it’s installed using one of the
methods below).

You don’t actually have to write a `setup.py` yourself. Instead, just
use [nbdev](https://nbdev.fast.ai). Then modify `settings.ini` as
appropriate for your module/script. To install your script directly, you
can type `pip install -e .`. Your script, when installed this way (it’s
called an [editable
install](http://codumentary.blogspot.com/2014/11/python-tip-of-year-pip-install-editable.html)),
will automatically be up to date even if you edit it - there’s no need
to reinstall it after editing. With nbdev you can even make your module
and script available for installation directly from pip and conda by
running `make release`.

## API details

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/script.py#L17"
target="_blank" style="float:right; font-size:smaller">source</a>

### store_true

>      store_true ()

*Placeholder to pass to
[`Param`](https://fastcore.fast.ai/script.html#param) for
[`store_true`](https://fastcore.fast.ai/script.html#store_true) action*

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/script.py#L22"
target="_blank" style="float:right; font-size:smaller">source</a>

### store_false

>      store_false ()

*Placeholder to pass to
[`Param`](https://fastcore.fast.ai/script.html#param) for
[`store_false`](https://fastcore.fast.ai/script.html#store_false)
action*

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/script.py#L27"
target="_blank" style="float:right; font-size:smaller">source</a>

### bool_arg

>      bool_arg (v)

*Use as `type` for [`Param`](https://fastcore.fast.ai/script.html#param)
to get `bool` behavior*

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/script.py#L32"
target="_blank" style="float:right; font-size:smaller">source</a>

### clean_type_str

>      clean_type_str (x:str)

``` python
class Test: pass

test_eq(clean_type_str(argparse.ArgumentParser), 'argparse.ArgumentParser')
test_eq(clean_type_str(Test), 'Test')
test_eq(clean_type_str(int), 'int')
test_eq(clean_type_str(float), 'float')
test_eq(clean_type_str(store_false), 'store_false')
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/script.py#L39"
target="_blank" style="float:right; font-size:smaller">source</a>

### Param

>      Param (help='', type=None, opt=True, action=None, nargs=None, const=None,
>             choices=None, required=None, default=None)

*A parameter in a function used in
[`anno_parser`](https://fastcore.fast.ai/script.html#anno_parser) or
[`call_parse`](https://fastcore.fast.ai/script.html#call_parse)*

``` python
test_eq(repr(Param("Help goes here")), '<Help goes here>')
test_eq(repr(Param("Help", int)), 'int <Help>')
test_eq(repr(Param(help=None, type=int)), 'int')
test_eq(repr(Param(help=None, type=None)), '')
```

Each parameter in your function should have an annotation `Param(...)`.
You can pass the following when calling
[`Param`](https://fastcore.fast.ai/script.html#param):
`help`,`type`,`opt`,`action`,`nargs`,`const`,`choices`,`required`
(i.e. it takes the same parameters as
`argparse.ArgumentParser.add_argument`, plus `opt`). Except for `opt`,
all of these are just passed directly to `argparse`, so you have all the
power of that module at your disposal. Generally you’ll want to pass at
least `help` (since this is provided as the help string for that
parameter) and `type` (to ensure that you get the type of data you
expect).

`opt` is a bool that defines whether a param is optional or required
(positional) - but you’ll generally not need to set this manually,
because fastcore.script will set it for you automatically based on
*default* values. You should provide a default (after the `=`) for any
*optional* parameters. If you don’t provide a default for a parameter,
then it will be a *positional* parameter.

Param’s `__repr__` also allows for more informative function annotation
when looking up the function’s doc using shift+tab. You see the type
annotation (if there is one) and the accompanying help documentation
with it.

``` python
def f(required:Param("Required param", int),
      a:Param("param 1", bool_arg),
      b:Param("param 2", str)="test"):
    "my docs"
    ...
```

``` python
help(f)
```

    Help on function f in module __main__:

    f(required: int <Required param>, a: bool_arg <param 1>, b: str <param 2> = 'test')
        my docs

``` python
p = Param(help="help", type=int)
p.set_default(1)
test_eq(p.kwargs, {'help': 'help (default: 1)', 'type': int, 'default': 1})
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/script.py#L75"
target="_blank" style="float:right; font-size:smaller">source</a>

### anno_parser

>      anno_parser (func, prog:str=None)

*Look at params (annotated with
[`Param`](https://fastcore.fast.ai/script.html#param)) in func and
return an `ArgumentParser`*

<table>
<thead>
<tr class="header">
<th></th>
<th><strong>Type</strong></th>
<th><strong>Default</strong></th>
<th><strong>Details</strong></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>func</td>
<td></td>
<td></td>
<td>Function to get arguments from</td>
</tr>
<tr class="even">
<td>prog</td>
<td>str</td>
<td>None</td>
<td>The name of the program</td>
</tr>
</tbody>
</table>

This converts a function with parameter annotations of type
[`Param`](https://fastcore.fast.ai/script.html#param) into an
`argparse.ArgumentParser` object. Function arguments with a default
provided are optional, and other arguments are positional.

``` python
_en = str_enum('_en', 'aa','bb','cc')
def f(required:Param("Required param", int),
      a:Param("param 1", bool_arg),
      b:Param("param 2", str)="test",
      c:Param("param 3", _en)=_en.aa):
    "my docs"
    ...

p = anno_parser(f, 'progname')
p.print_help()
```

    usage: progname [-h] [--b B] [--c {aa,bb,cc}] required a

    my docs

    positional arguments:
      required        Required param
      a               param 1

    optional arguments:
      -h, --help      show this help message and exit
      --b B           param 2 (default: test)
      --c {aa,bb,cc}  param 3 (default: aa)

It also works with type annotations and docments:

``` python
def g(required:int,  # Required param
      a:bool_arg,    # param 1
      b="test",      # param 2
      c:_en=_en.aa): # param 3
    "my docs"
    ...

p = anno_parser(g, 'progname')
p.print_help()
```

    usage: progname [-h] [--b B] [--c {aa,bb,cc}] required a

    my docs

    positional arguments:
      required        Required param
      a               param 1

    optional arguments:
      -h, --help      show this help message and exit
      --b B           param 2 (default: test)
      --c {aa,bb,cc}  param 3 (default: aa)

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/script.py#L89"
target="_blank" style="float:right; font-size:smaller">source</a>

### args_from_prog

>      args_from_prog (func, prog)

*Extract args from `prog`*

Sometimes it’s convenient to extract arguments from the actual name of
the called program.
[`args_from_prog`](https://fastcore.fast.ai/script.html#args_from_prog)
will do this, assuming that names and values of the params are separated
by a `#`. Optionally there can also be a prefix separated by `##`
(double underscore).

``` python
exp = {'a': False, 'b': 'baa'}
test_eq(args_from_prog(f, 'foo##a#0#b#baa'), exp)
test_eq(args_from_prog(f, 'a#0#b#baa'), exp)
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/script.py#L105"
target="_blank" style="float:right; font-size:smaller">source</a>

### call_parse

>      call_parse (func=None, nested=False)

*Decorator to create a simple CLI from `func` using
[`anno_parser`](https://fastcore.fast.ai/script.html#anno_parser)*

``` python
@call_parse
def test_add(
    a:int=0,  # param a
    b:int=0  # param 1
):
    "Add up `a` and `b`"
    return a + b
```

[`call_parse`](https://fastcore.fast.ai/script.html#call_parse)
decorated functions work as regular functions and also as command-line
interface functions.

``` python
test_eq(test_add(1,2), 3)
```

This is the main way to use `fastcore.script`; decorate your function
with [`call_parse`](https://fastcore.fast.ai/script.html#call_parse),
add [`Param`](https://fastcore.fast.ai/script.html#param) annotations
(as shown above) or type annotations and docments, and it can then be
used as a script.

Use the `nested` keyword argument to create nested parsers, where
earlier parsers consume only their known args from `sys.argv` before
later parsers are used. This is useful to create one command line
application that executes another. For example:

``` sh
myrunner --keyword 1 script.py -- <script.py args>
```

A separating `--` after the first application’s args is recommended
though not always required, otherwise args may be parsed in unexpected
ways. For example:

``` sh
myrunner script.py -h
```

would display `myrunner`’s help and not `script.py`’s.</doc>
    <doc title="fastcore.xdg" desc="XDG Base Directory Specification helpers."># XDG



See the [XDG Base Directory
Specification](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html)
for more information.

## Overview

[`xdg_cache_home`](https://fastcore.fast.ai/xdg.html#xdg_cache_home),
[`xdg_config_home`](https://fastcore.fast.ai/xdg.html#xdg_config_home),
[`xdg_data_home`](https://fastcore.fast.ai/xdg.html#xdg_data_home), and
[`xdg_state_home`](https://fastcore.fast.ai/xdg.html#xdg_state_home)
return `pathlib.Path` objects containing the value of the environment
variable named `XDG_CACHE_HOME`, `XDG_CONFIG_HOME`, `XDG_DATA_HOME`, and
`XDG_STATE_HOME` respectively, or the default defined in the
specification if the environment variable is unset, empty, or contains a
relative path rather than absolute path.

[`xdg_config_dirs`](https://fastcore.fast.ai/xdg.html#xdg_config_dirs)
and [`xdg_data_dirs`](https://fastcore.fast.ai/xdg.html#xdg_data_dirs)
return a list of `pathlib.Path` objects containing the value, split on
colons, of the environment variable named `XDG_CONFIG_DIRS` and
`XDG_DATA_DIRS` respectively, or the default defined in the
specification if the environment variable is unset or empty. Relative
paths are ignored, as per the specification.

[`xdg_runtime_dir`](https://fastcore.fast.ai/xdg.html#xdg_runtime_dir)
returns a `pathlib.Path` object containing the value of the
`XDG_RUNTIME_DIR` environment variable, or `None` if the environment
variable is not set, or contains a relative path rather than absolute
path.

## Helpers

We’ll start by defining a context manager that temporarily sets an
environment variable to demonstrate the behaviour of each helper
function:

``` python
from contextlib import contextmanager
```

``` python
@contextmanager
def env(variable, value):
    old = os.environ.get(variable, None)
    try:
        os.environ[variable] = value
        yield
    finally:
        if old is None: del os.environ[variable]
        else: os.environ[variable] = old
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xdg.py#L27"
target="_blank" style="float:right; font-size:smaller">source</a>

### xdg_cache_home

>      xdg_cache_home ()

*Path corresponding to `XDG_CACHE_HOME`*

``` python
from fastcore.test import *
```

``` python
test_eq(xdg_cache_home(), Path.home()/'.cache')
with env('XDG_CACHE_HOME', '/home/fastai/.cache'):
    test_eq(xdg_cache_home(), Path('/home/fastai/.cache'))
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xdg.py#L32"
target="_blank" style="float:right; font-size:smaller">source</a>

### xdg_config_dirs

>      xdg_config_dirs ()

*Paths corresponding to `XDG_CONFIG_DIRS`*

``` python
test_eq(xdg_config_dirs(), [Path('/etc/xdg')])
with env('XDG_CONFIG_DIRS', '/home/fastai/.xdg:/home/fastai/.config'):
    test_eq(xdg_config_dirs(), [Path('/home/fastai/.xdg'), Path('/home/fastai/.config')])
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xdg.py#L37"
target="_blank" style="float:right; font-size:smaller">source</a>

### xdg_config_home

>      xdg_config_home ()

*Path corresponding to `XDG_CONFIG_HOME`*

``` python
test_eq(xdg_config_home(), Path.home()/'.config')
with env('XDG_CONFIG_HOME', '/home/fastai/.config'):
    test_eq(xdg_config_home(), Path('/home/fastai/.config'))
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xdg.py#L42"
target="_blank" style="float:right; font-size:smaller">source</a>

### xdg_data_dirs

>      xdg_data_dirs ()

*Paths corresponding to XDG_DATA_DIRS\`*

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xdg.py#L47"
target="_blank" style="float:right; font-size:smaller">source</a>

### xdg_data_home

>      xdg_data_home ()

*Path corresponding to `XDG_DATA_HOME`*

``` python
test_eq(xdg_data_home(), Path.home()/'.local/share')
with env('XDG_DATA_HOME', '/home/fastai/.data'):
    test_eq(xdg_data_home(), Path('/home/fastai/.data'))
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xdg.py#L52"
target="_blank" style="float:right; font-size:smaller">source</a>

### xdg_runtime_dir

>      xdg_runtime_dir ()

*Path corresponding to `XDG_RUNTIME_DIR`*

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xdg.py#L58"
target="_blank" style="float:right; font-size:smaller">source</a>

### xdg_state_home

>      xdg_state_home ()

*Path corresponding to `XDG_STATE_HOME`*

``` python
test_eq(xdg_state_home(), Path.home()/'.local/state')
with env('XDG_STATE_HOME', '/home/fastai/.state'):
    test_eq(xdg_state_home(), Path('/home/fastai/.state'))
```

------------------------------------------------------------------------

Copyright © 2016-2021 Scott Stevenson <scott@stevenson.io>

Modifications copyright © 2022 onwards Jeremy Howard</doc>
    <doc title="fastcore.xml" desc="concise generation of XML"># XML



``` python
from IPython.display import Markdown
from pprint import pprint
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xml.py#L26"
target="_blank" style="float:right; font-size:smaller">source</a>

### FT

>      FT (tag:str, cs:tuple, attrs:dict=None, void_=False, **kwargs)

*A ‘Fast Tag’ structure, containing `tag`,`children`,and `attrs`*

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xml.py#L55"
target="_blank" style="float:right; font-size:smaller">source</a>

### attrmap

>      attrmap (o)

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xml.py#L62"
target="_blank" style="float:right; font-size:smaller">source</a>

### valmap

>      valmap (o)

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xml.py#L83"
target="_blank" style="float:right; font-size:smaller">source</a>

### ft

>      ft (tag:str, *c, void_:bool=False, attrmap:<built-
>          infunctioncallable>=<function attrmap>, valmap:<built-
>          infunctioncallable>=<function valmap>, ft_cls=<class '__main__.FT'>,
>          **kw)

*Create an [`FT`](https://fastcore.fast.ai/xml.html#ft) structure for
`to_xml()`*

``` python
a = Body(Div('hi', a=1, b=True, cls=()), P('hi', cls=['a',1], style=dict(a=1,b=2)))
a
```

    body((div(('hi',),{'a': 1, 'b': True, 'class': None}), p(('hi',),{'class': 'a 1', 'style': 'a:1; b:2'})),{})

``` python
a + (P('a'),P('b'))
```

    body((div(('hi',),{'a': 1, 'b': True, 'class': None}), p(('hi',),{'class': 'a 1', 'style': 'a:1; b:2'}), p(('a',),{}), p(('b',),{})),{})

The main HTML tags are exported as
[`ft`](https://fastcore.fast.ai/xml.html#ft) partials.

Attributes are passed as keywords. Use ‘klass’ and ‘fr’ instead of
‘class’ and ‘for’, to avoid Python reserved word clashes.

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xml.py#L103"
target="_blank" style="float:right; font-size:smaller">source</a>

### Html

>      Html (*c, doctype=True, **kwargs)

*An HTML tag, optionally preceeded by `!DOCTYPE HTML`*

``` python
samp = Html(
    Head(Title('Some page')),
    Body(Div('Some text\nanother line', (Input(name="jph's"), Img(src="filename", data=1)),
             cls=['myclass', 'another'],
             style={'padding':1, 'margin':2}))
)
pprint(samp)
```

    (!doctype((),{'html': True}),
     html((head((title(('Some page',),{}),),{}), body((div(('Some text\nanother line', input((),{'name': "jph's"}), img((),{'src': 'filename', 'data': 1})),{'class': 'myclass another', 'style': 'padding:1; margin:2'}),),{})),{}))

``` python
elem = P('Some text', id="myid")
print(elem.tag)
print(elem.children)
print(elem.attrs)
```

    p
    ('Some text',)
    {'id': 'myid'}

You can get and set attrs directly:

``` python
elem.id = 'newid'
print(elem.id, elem.get('id'), elem.get('foo', 'missing'))
elem
```

    newid newid missing

    p(('Some text',),{'id': 'newid'})

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xml.py#L110"
target="_blank" style="float:right; font-size:smaller">source</a>

### Safe

\*str(object=’’) -\> str str(bytes_or_buffer\[, encoding\[, errors\]\])
-\> str

Create a new string object from the given object. If encoding or errors
is specified, then the object must expose a data buffer that will be
decoded using the given encoding and error handler. Otherwise, returns
the result of object.\_\_str\_\_() (if defined) or repr(object).
encoding defaults to sys.getdefaultencoding(). errors defaults to
‘strict’.\*

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xml.py#L161"
target="_blank" style="float:right; font-size:smaller">source</a>

### to_xml

>      to_xml (elm, lvl=0, indent:bool=True, do_escape:bool=True)

*Convert [`ft`](https://fastcore.fast.ai/xml.html#ft) element tree into
an XML string*

``` python
h = to_xml(samp, do_escape=False)
print(h)
```

    <!doctype html>

    <html>
      <head>
        <title>Some page</title>
      </head>
      <body>
        <div class="myclass another" style="padding:1; margin:2">
    Some text
    another line
          <input name="jph's">
          <img src="filename" data="1">
        </div>
      </body>
    </html>

``` python
class PageTitle:
    def __ft__(self): return H1("Hello")

class HomePage:
    def __ft__(self): return Div(PageTitle(), Div('hello'))

h = to_xml(Div(HomePage()))
expected_output = """<div>
  <div>
    <h1>Hello</h1>
    <div>hello</div>
  </div>
</div>
"""
assert h == expected_output
```

``` python
h = to_xml(samp, indent=False)
print(h)
```

    <!doctype html><html><head><title>Some page</title></head><body><div class="myclass another" style="padding:1; margin:2">Some text
    another line<input name="jph's"><img src="filename" data="1"></div></body></html>

Interoperability both directions with Django and Jinja using the
[**html**()
protocol](https://jinja.palletsprojects.com/en/3.1.x/templates/#jinja-filters.escape):

``` python
def _esc(s): return s.__html__() if hasattr(s, '__html__') else Safe(escape(s))

r = Safe('<b>Hello from Django</b>')
print(to_xml(Div(r)))
print(_esc(Div(P('Hello from fastcore <3'))))
```

    <div><b>Hello from Django</b></div>

    <div>
      <p>Hello from fastcore &lt;3</p>
    </div>

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xml.py#L168"
target="_blank" style="float:right; font-size:smaller">source</a>

### highlight

>      highlight (s, lang='html')

*Markdown to syntax-highlight `s` in language `lang`*

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xml.py#L173"
target="_blank" style="float:right; font-size:smaller">source</a>

### showtags

>      showtags (s)

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xml.py#L182"
target="_blank" style="float:right; font-size:smaller">source</a>

### FT.\_\_call\_\_

>      FT.__call__ (*c, **kw)

*Call self as a function.*

You can also reorder the children to come *after* the attrs, if you use
this alternative syntax for [`FT`](https://fastcore.fast.ai/xml.html#ft)
where the children are in a second pair of `()` (behind the scenes this
is because [`FT`](https://fastcore.fast.ai/xml.html#ft) implements
`__call__` to add children).

``` python
Body(klass='myclass')(
    Div(style='padding:3px')(
        'Some text 1<2',
        I(spurious=True)('in italics'),
        Input(name='me'),
        Img(src="filename", data=1)
    )
)
```

``` html
<body class="myclass">
  <div style="padding:3px">
Some text 1&lt;2
    <i spurious>in italics</i>
    <input name="me">
    <img src="filename" data="1">
  </div>
</body>
```

------------------------------------------------------------------------

<a
href="https://github.com/fastai/fastcore/blob/master/fastcore/xml.py#L189"
target="_blank" style="float:right; font-size:smaller">source</a>

### **getattr**

>      __getattr__ (tag)</doc>
  </optional>
</project>

