



  

pake 0.17.0.3a1 documentation

 [pake](index.html#document-index) 

 latest

 

* [pake package](index.html#document-pake)

	+ [Module Contents](index.html#module-pake)

* [Submodules](index.html#submodules)

	+ [Module: pake.graph](index.html#module-pake.graph)

	+ [Module: pake.process](index.html#module-pake.process)

	+ [Module: pake.util](index.html#module-pake.util)

	+ [Module: pake.conf](index.html#module-pake.conf)

	+ [Module: pake.returncodes](index.html#module-pake.returncodes)

* [Running Pake](index.html#document-runningpake)

	+ [Manually specifying pakefile(s)](index.html#manually-specifying-pakefile-s)

	+ [Executing in another directory](index.html#executing-in-another-directory)

	+ [Running multiple tasks](index.html#running-multiple-tasks)

	+ [Specifying define values](index.html#specifying-define-values)

	+ [Reading defines from STDIN](index.html#reading-defines-from-stdin)

	+ [Environmental variables](index.html#environmental-variables)

	+ [Command line options](index.html#command-line-options)

	+ [Return codes](index.html#return-codes)

* [Writing Basic Tasks](index.html#document-basictasks)

* [Input/Output Name Generators & Globbing](index.html#document-inputandoutputgenerators)

	+ [Multiple input generators at once](index.html#multiple-input-generators-at-once)

* [Change Detection Against Directories](index.html#document-directorychangedetection)

* [Exiting Pakefiles Gracefully](index.html#document-exitingpakefiles)

	+ [Calls To exit() inside tasks](index.html#calls-to-exit-inside-tasks)

	+ [Stack traces from exit/terminate in tasks](index.html#stack-traces-from-exit-terminate-in-tasks)

* [Adding Tasks Programmatically](index.html#document-programmaticlyaddtasks)

* [Exceptions Inside Tasks](index.html#document-taskexceptions)

	+ [pake.TaskSubprocessException](index.html#pake-tasksubprocessexception)

	+ [pake.SubpakeException](index.html#pake-subpakeexception)

* [Concurrency Inside Tasks](index.html#document-multitasking)

	+ [Output synchronization with ctx.print & ctx.io.write](index.html#output-synchronization-with-ctx-print-ctx-io-write)

	+ [Output synchronization with ctx.call & ctx.subpake](index.html#output-synchronization-with-ctx-call-ctx-subpake)

	+ [Sub task exceptions](index.html#sub-task-exceptions)

* [Manipulating Files / Dirs With pake.FileHelper](index.html#document-filehelper)

	+ [File / Folder creation methods](index.html#file-folder-creation-methods)

	+ [Copy / Move methods](index.html#copy-move-methods)

	+ [Removal / Clean related methods](index.html#removal-clean-related-methods)

* [Running Commands / Sub Processes](index.html#document-subprocess)

	+ [TaskContext.call](index.html#taskcontext-call)

	+ [TaskContext.check\_output](index.html#taskcontext-check-output)

	+ [TaskContext.check\_call](index.html#taskcontext-check-call)

	+ [pake.process module methods](index.html#pake-process-module-methods)

* [Running Sub Pakefiles](index.html#document-subpake)

[pake](index.html#document-index)

* [Docs](index.html#document-index) »

* pake 0.17.0.3a1 documentation

* [Edit on GitHub](https://github.com/Teriks/pake/blob/master/docs/source/index.rst)

---

Welcome to pake’s documentation![¶](#welcome-to-pake-s-documentation "Permalink to this headline")

==================================================================================================

pake is a make-like python build utility where tasks, dependencies and build commands

can be expressed entirely in python, similar to ruby rake.

pake supports automatic file/directory change detection when dealing with

task inputs and outputs, and also parallel builds.

pake requires python3.5+

Installing[¶](#installing "Permalink to this headline")

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

Note: pake is Alpha and likely to change some.

To install the latest release use:

`sudo pip3 install python-pake --upgrade`

If you want to install the development branch you can use:

`sudo pip3 install git+git://github.com/Teriks/pake@develop`

Module Doc[¶](#module-doc "Permalink to this headline")

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

### pake package[¶](#pake-package "Permalink to this headline")

#### Module Contents[¶](#module-pake "Permalink to this headline")

`pake.``EXPORTS`[¶](#pake.EXPORTS "Permalink to this definition")

A dictionary object containing all current exports by name,

you are free to modify this dictionary directly.

See: [`pake.export()`](#pake.export "pake.export"), [`pake.subpake()`](#pake.subpake "pake.subpake") and [`pake.TaskContext.subpake()`](#pake.TaskContext.subpake "pake.TaskContext.subpake").

Be careful and make sure it remains a dictionary object.

Export values must be able to **repr()** into parsable python literals.

`pake.``init`(*args=None*, *\*\*kwargs*)[[source]](_modules/pake/program.html#init)[¶](#pake.init "Permalink to this definition")

Read command line arguments relevant to initialization, and return a [`pake.Pake`](#pake.Pake "pake.Pake") object.

This function will print information to `pake.conf.stderr` and call `exit(pake.returncodes.BAD\_ARGUMENTS)`

immediately if arguments parsed from the command line or passed to the **args** parameter do not pass validation.

| Parameters: | * **args** – Optional command line arguments as an iterable, if not provided they will be parsed from the command line.

This parameter is passed through [`pake.util.handle\_shell\_args()`](#pake.util.handle_shell_args "pake.util.handle_shell_args"), so you may pass an arguments

iterable containing nested non-string iterables, as well as plain values like Python integers if

your specifying the **–jobs** argument for example.

* **\*\*kwargs** – See below

 |

| Keyword Arguments: |

|  | * **stdout** –

Sets the value of [`pake.Pake.stdout`](#pake.Pake.stdout "pake.Pake.stdout")

* **show\_task\_headers** (`bool`) –

Sets the value of [`pake.Pake.show\_task\_headers`](#pake.Pake.show_task_headers "pake.Pake.show_task_headers")

* **sync\_output** (`bool`) –

Sets the value of [`pake.Pake.sync\_output`](#pake.Pake.sync_output "pake.Pake.sync_output"), overriding the **–sync-output** option and

the **PAKE\_SYNC\_OUTPUT** environmental variable. The default behavior of pake is to synchronize task output when

tasks are running in parallel, unless it is overridden from the environment, command line, or here (in order of

increasing override priority). Setting this value to **None** is the same as leaving it unspecified,

no override will take place, and the default value of True, the environment, or the **–sync-output** specified

value will be used in that order.

 |

| Raises: | `SystemExit` if bad command line arguments are parsed, or the **args** parameter contains bad arguments. |

| Returns: | [`pake.Pake`](#pake.Pake "pake.Pake") |

`pake.``de_init`(*clear\_conf=True*, *clear\_exports=True*, *clear\_env=True*)[[source]](_modules/pake/program.html#de_init)[¶](#pake.de_init "Permalink to this definition")

Return the pake module to a pre-initialized state.

Used primarily for unit tests.

Defines read from STDIN via the **–stdin-defines** option

are cached in memory after being read and not affected by

this function, secondary calls to [`pake.init()`](#pake.init "pake.init") will

cause them to be read back from cache.

| Parameters: | * **clear\_conf** – If **True**, call [`pake.conf.reset()`](#pake.conf.reset "pake.conf.reset").

* **clear\_exports** – If **True**, call **clear** on [`pake.EXPORTS`](#pake.EXPORTS "pake.EXPORTS").

* **clear\_env** – If **True**, clear any environmental variables pake.init has set.

 |

`pake.``is_init`()[[source]](_modules/pake/program.html#is_init)[¶](#pake.is_init "Permalink to this definition")

Check if [`pake.init()`](#pake.init "pake.init") has been called.

| Returns: | True if [`pake.init()`](#pake.init "pake.init") has been called. |

`pake.``run`(*pake\_obj*, *tasks=None*, *jobs=None*, *call\_exit=True*)[[source]](_modules/pake/program.html#run)[¶](#pake.run "Permalink to this definition")

Run pake *(the program)* given a [`pake.Pake`](#pake.Pake "pake.Pake") instance and default tasks.

This function should be used to invoke pake at the end of your pakefile.

This function will call **exit(return\_code)** upon handling any exceptions from [`pake.Pake.run()`](#pake.Pake.run "pake.Pake.run")

or [`pake.Pake.dry\_run()`](#pake.Pake.dry_run "pake.Pake.dry_run") if **call\_exit=True**, and will print information to

`pake.Pake.stderr` if necessary.

This function will not call **exit** if pake executes successfully with a return code of zero.

This function will return pake’s exit code when **call\_exit=False**.

For all return codes see: [`pake.returncodes`](#module-pake.returncodes "pake.returncodes").

This function will never return [`pake.returncodes.BAD\_ARGUMENTS`](#pake.returncodes.BAD_ARGUMENTS "pake.returncodes.BAD_ARGUMENTS"),

because [`pake.init()`](#pake.init "pake.init") will have already called **exit**.

| Raises: | [`pake.PakeUninitializedException`](#pake.PakeUninitializedException "pake.PakeUninitializedException") if [`pake.init`](#pake.init "pake.init") has not been called. |

| Raises: | `ValueError` if the **jobs** parameter is used, and is set less than 1. |

| Parameters: | * **pake\_obj** ([*pake.Pake*](index.html#pake.Pake "pake.Pake")) – A [`pake.Pake`](#pake.Pake "pake.Pake") instance, created by [`pake.init()`](#pake.init "pake.init").

* **tasks** – A list of, or a single default task to run if no tasks are specified on the command line.

Tasks specified on the command line completely override this argument.

* **jobs** – Call with an arbitrary number of max jobs, overriding the command line value of **–jobs**.

The default value of this parameter is **None**, which means the command line value or default of 1 is not overridden.

* **call\_exit** – Whether or not **exit(return\_code)** should be called by this function on error.

This defaults to **True** and when set to **False** the return code is instead

returned to the caller.

 |

| Returns: | A return code from [`pake.returncodes`](#module-pake.returncodes "pake.returncodes"). |

`pake.``terminate`(*pake\_obj*, *return\_code=0*)[[source]](_modules/pake/program.html#terminate)[¶](#pake.terminate "Permalink to this definition")

Preform a graceful exit from a pakefile, printing the leaving directory or exit subpake message if

needed, then exiting with a given return code. The default return code is [`pake.returncodes.SUCCESS`](#pake.returncodes.SUCCESS "pake.returncodes.SUCCESS").

This should be used as opposed to a raw **exit** call to ensure the output of pake remains consistent.

Use Case:

```

import os

import pake

from pake import returncodes

pk = pake.init()

# Say you need to wimp out of a build for some reason

# But not inside of a task. pake.terminate will make sure the

# 'leaving directory/exiting subpake' message is printed

# if it needs to be.

if os.name == 'nt':

    pk.print('You really thought you could '

             'build my software on windows? nope!')

    pake.terminate(pk, returncodes.ERROR)

    # or

    # pk.terminate(returncodes.ERROR)

# Define some tasks...

@pk.task

def build(ctx):

     # You can use pake.terminate() inside of a task as well as exit()

     # pake.terminate() may offer more functionality than a raw exit()

     # in the future, however exit() will always work as well.

     something\_bad\_happened = True

     if something\_bad\_happened:

         pake.terminate(pk, returncodes.ERROR)

         # Or:

         # pk.terminate(returncodes.ERROR)

pake.run(pk, tasks=build)

```

[`pake.Pake.terminate()`](#pake.Pake.terminate "pake.Pake.terminate") is a shortcut method which passes the **pake\_obj** instance to this function for you.

| Parameters: | * **pake\_obj** ([*pake.Pake*](index.html#pake.Pake "pake.Pake")) – A [`pake.Pake`](#pake.Pake "pake.Pake") instance, created by [`pake.init()`](#pake.init "pake.init").

* **return\_code** – Return code to exit the pakefile with, see [`pake.returncodes`](#module-pake.returncodes "pake.returncodes") for standard return codes.

The default return code for this function is [`pake.returncodes.SUCCESS`](#pake.returncodes.SUCCESS "pake.returncodes.SUCCESS").

[`pake.returncodes.ERROR`](#pake.returncodes.ERROR "pake.returncodes.ERROR") is intended to be used with **terminate** to indicate a

generic error, but other return codes may be used.

 |

| Raises: | [`pake.PakeUninitializedException`](#pake.PakeUninitializedException "pake.PakeUninitializedException") if [`pake.init`](#pake.init "pake.init") has not been called. |

`pake.``get_subpake_depth`()[[source]](_modules/pake/program.html#get_subpake_depth)[¶](#pake.get_subpake_depth "Permalink to this definition")

Get the depth of execution, which increases for nested calls to [`pake.subpake()`](#pake.subpake "pake.subpake")

The depth of execution starts at 0.

| Raises: | [`pake.PakeUninitializedException`](#pake.PakeUninitializedException "pake.PakeUninitializedException") if [`pake.init`](#pake.init "pake.init") has not been called. |

| Returns: | The current depth of execution (an integer >= 0) |

`pake.``get_max_jobs`()[[source]](_modules/pake/program.html#get_max_jobs)[¶](#pake.get_max_jobs "Permalink to this definition")

Get the max number of jobs passed from the **–jobs** command line argument.

The minimum number of jobs allowed is 1.

Be aware, the value this function returns will not be affected by the optional

**jobs** argument of [`pake.run()`](#pake.run "pake.run") and [`pake.Pake.run()`](#pake.Pake.run "pake.Pake.run"). It is purely

for retrieving the value passed on the command line.

If you have overridden the command line or default job count using the **jobs** argument

of the methods mentioned above, you can use the [`pake.Pake.max\_jobs`](#pake.Pake.max_jobs "pake.Pake.max_jobs") property on the

[`pake.Pake`](#pake.Pake "pake.Pake") instance returned by [`pake.init()`](#pake.init "pake.init") to get the correct value inside

of a task while pake is running.

| Raises: | [`pake.PakeUninitializedException`](#pake.PakeUninitializedException "pake.PakeUninitializedException") if [`pake.init`](#pake.init "pake.init") has not been called. |

| Returns: | The max number of jobs from the **–jobs** command line argument. (an integer >= 1) |

`pake.``get_init_file`()[[source]](_modules/pake/program.html#get_init_file)[¶](#pake.get_init_file "Permalink to this definition")

Gets the full path to the file [`pake.init()`](#pake.init "pake.init") was called in.

| Raises: | [`pake.PakeUninitializedException`](#pake.PakeUninitializedException "pake.PakeUninitializedException") if [`pake.init`](#pake.init "pake.init") has not been called. |

| Returns: | Full path to pakes entrypoint file, or **None** |

`pake.``get_init_dir`()[[source]](_modules/pake/program.html#get_init_dir)[¶](#pake.get_init_dir "Permalink to this definition")

Gets the full path to the directory pake started running in.

If pake preformed any directory changes, this returns the working path before that happened.

| Raises: | [`pake.PakeUninitializedException`](#pake.PakeUninitializedException "pake.PakeUninitializedException") if [`pake.init`](#pake.init "pake.init") has not been called. |

| Returns: | Full path to init dir, or **None** |

`pake.``export`(*name*, *value*)[[source]](_modules/pake/subpake.html#export)[¶](#pake.export "Permalink to this definition")

Exports a define that can be retrieved in subpake scripts via [`pake.Pake.get\_define()`](#pake.Pake.get_define "pake.Pake.get_define").

This function can redefine the value of an existing export as well.

The [`pake.EXPORTS`](#pake.EXPORTS "pake.EXPORTS") dictionary can also be manipulated directly.

Export values must be able to **repr()** into parsable python literals.

| Parameters: | * **name** – The name of the define.

* **value** – The value of the define.

 |

`pake.``subpake`(*\*args*, *stdout=None*, *silent=False*, *ignore\_errors=False*, *call\_exit=True*, *readline=True*, *collect\_output=False*, *collect\_output\_lock=None*)[[source]](_modules/pake/subpake.html#subpake)[¶](#pake.subpake "Permalink to this definition")

Execute a `pakefile.py` script, changing directories if necessary.

This function should not be used inside tasks, use: [`pake.TaskContext.subpake()`](#pake.TaskContext.subpake "pake.TaskContext.subpake") instead.

A [`pake.TaskContext()`](#pake.TaskContext "pake.TaskContext") instance is passed into the single parameter of each task, usually named **ctx**.

[`pake.subpake()`](#pake.subpake "pake.subpake") allows similar syntax to [`pake.TaskContext.call()`](#pake.TaskContext.call "pake.TaskContext.call") for its **\*args** parameter.

Subpake scripts do not inherit the **–jobs** argument from the parent script, if you want

to run them with multithreading enabled you need to pass your own **–jobs** argument manually.

Example:

```

# These are all equivalent

pake.subpake('dir/pakefile.py', 'task\_a', '-C', 'some\_dir')

pake.subpake(['dir/pakefile.py', 'task\_a', '-C', 'some\_dir'])

# note the nested iterable containing string arguments

pake.subpake(['dir/pakefile.py', 'task\_a', ['-C', 'some\_dir']])

pake.subpake('dir/pakefile.py task\_a -C some\_dir')

```

| Parameters: | * **args** – The script, and additional arguments to pass to the script.

You may pass the command words as a single iterable, a string, or as

variadic arguments.

* **stdout** – The file output to write all of the pakefile’s output to. (defaults to `pake.conf.stdout`)

The pakefile’s **stderr** will be redirected to its **stdout**, so the passed file object will

receive all output from the pakefile including error messages.

* **silent** – Whether or not to silence all output from the subpake script.

* **ignore\_errors** – If this is **True**, this function will never call **exit** or throw

[`pake.SubpakeException`](#pake.SubpakeException "pake.SubpakeException") if the executed pakefile returns with a

non-zero exit code. It will instead return the exit code from the

subprocess to the caller.

* **call\_exit** – Whether or not to print to `pake.conf.stderr` and immediately

call **exit** if the pakefile script encounters an error. The value

of this parameter will be disregarded when **ignore\_errors=True**.

* **readline** – Whether or not to use **readline** for reading process output when **ignore\_errors**

and **silent** are **False**, this is necessary for live output in that case. When live

output to a terminal is not required, such as when writing to a file on disk, setting

this parameter to **False** results in more efficient writes. This parameter defaults to **True**

* **collect\_output** – Whether or not to collect all subpake output to a temporary file

and then write it incrementally to the **stdout** parameter when

the process finishes. This can help prevent crashes when dealing with lots of output.

When you pass **True** to this parameter, the **readline** parameter is ignored.

See: [Output synchronization with ctx.call & ctx.subpake](index.html#output-synchronization-with-ctx-call-ctx-subpake)

* **collect\_output\_lock** – If you provide a lockable object such as `threading.Lock` or

`threading.RLock`, The subpake function will try to acquire the lock before

incrementally writing to the **stdout** parameter when **collect\_output=True**.

The lock you pass is only required to implement a context manager and be usable

in a **with** statement, no methods are called on the lock. [`pake.TaskContext.subpake()`](#pake.TaskContext.subpake "pake.TaskContext.subpake")

will pass [`pake.TaskContext.io\_lock`](#pake.TaskContext.io_lock "pake.TaskContext.io_lock") for you if **collect\_output=True**.

 |

| Raises: | `ValueError` if no command + optional command arguments are provided. |

| Raises: | `FileNotFoundError` if the first argument *(the pakefile)* is not found. |

| Raises: | [`pake.SubpakeException`](#pake.SubpakeException "pake.SubpakeException") if the called pakefile script encounters an error

and the following is true: **exit\_on\_error=False** and **ignore\_errors=False**. |

*class* `pake.``Pake`(*stdout=None*, *sync\_output=True*, *show\_task\_headers=True*)[[source]](_modules/pake/pake.html#Pake)[¶](#pake.Pake "Permalink to this definition")

Bases: `object`

Pake’s main instance, which should not be initialized directly.

Use: [`pake.init()`](#pake.init "pake.init") to create a [`pake.Pake`](#pake.Pake "pake.Pake") object

and initialize the pake module.

`stdout`[¶](#pake.Pake.stdout "Permalink to this definition")

The file object that task output gets written to, as well as ‘changing directory/entering & leaving subpake’ messages.

If you set this, make sure that you set it to an actual file object that implements **fileno()**. `io.StringIO`

and pseudo file objects with no **fileno()** will not work with all of pake’s subprocess spawning functions.

This attribute can be modified directly.

`sync_output`[¶](#pake.Pake.sync_output "Permalink to this definition")

Whether or not the pake instance should queue task output and write it in

a synchronized fashion when running with more than one job. This defaults

to **True** unless the environmental variable `PAKE\_SYNC\_OUTPUT` is set to **0**,

or the command line option **–output-sync False** is specified.

If this is disabled (Set to **False**), task output may become interleaved

and scrambled when running pake with more than one job. Pake will run

somewhat faster however.

This attribute can be modified directly.

`show_task_headers`[¶](#pake.Pake.show_task_headers "Permalink to this definition")

Whether or not pake should print **Executing Task:** headers for tasks that are

about to execute, the default value is **True**. If you set this to **False** task

headers will be disabled for all tasks except ones that explicitly specify **show\_header=True**.

See the **show\_header** parameter of [`pake.Pake.task()`](#pake.Pake.task "pake.Pake.task") and [`pake.Pake.add\_task()`](#pake.Pake.add_task "pake.Pake.add_task"),

which allows you to disable or force enable the task header for a specific task.

This attribute can be modified directly.

`add_task`(*name*, *func*, *dependencies=None*, *inputs=None*, *outputs=None*, *show\_header=None*)[[source]](_modules/pake/pake.html#Pake.add_task)[¶](#pake.Pake.add_task "Permalink to this definition")

Method for programmatically registering pake tasks.

This method expects for the most part the same argument types as the [`pake.Pake.task()`](#pake.Pake.task "pake.Pake.task") decorator.

Example:

```

 # A contrived example using a callable class

 

 class FileToucher:

     """Task Documentation Here"""

     

     def \_\_init\_\_(self, tag):

         self.\_tag = tag

     

     def \_\_call\_\_(self, ctx):

         ctx.print('Toucher {}'.format(self.\_tag))

         

         fp = pake.FileHelper(ctx)

         

         for i in ctx.outputs:

             fp.touch(i)

         

         

task\_instance\_a = FileToucher('A')

task\_instance\_b = FileToucher('B')

pk.add\_task('task\_a', task\_instance\_a, outputs=['file\_1', 'file\_2'])

pk.add\_task('task\_b', task\_instance\_b, dependencies=task\_instance\_a, outputs='file\_3')

# Note: you can refer to dependencies by name (by string) as well as reference.

# Equivalent calls:

# pk.add\_task('task\_b', task\_instance\_b, dependencies='task\_a', outputs='file\_3')

# pk.add\_task('task\_b', task\_instance\_b, dependencies=['task\_a'], outputs='file\_3')

# pk.add\_task('task\_b', task\_instance\_b, dependencies=[task\_instance\_a], outputs='file\_3')

# Example using a function

def my\_task\_func\_c(ctx):

    ctx.print('my\_task\_func\_c')

    

pk.add\_task('task\_c', my\_task\_func\_c, dependencies='task\_b')

pake.run(pk, tasks=my\_task\_func\_c)

# Or equivalently:

# pake.run(pk, tasks='task\_c')

```

| Parameters: | * **name** – The name of the task

* **func** – The task function (or callable class)

* **dependencies** – List of task dependencies or single task, by name or by reference

* **inputs** – List of input files/directories, or a single input (accepts input file generators like [`pake.glob()`](#pake.glob "pake.glob"))

* **outputs** – List of output files/directories, or a single output (accepts output file generators like [`pake.pattern()`](#pake.pattern "pake.pattern"))

* **show\_header** – Whether or not to print an **Executing Task:** header when the task begins executing.

This defaults to **None**, which means the header is printed unless `pake.Pake.show\_task\_header` is set to **False**.

If you specify **True** and `pake.Pake.show\_task\_header` is set to **False**, it will force the task header to print

anyway. By explicitly specifying **True** you override `pake.Pake.show\_task\_header`.

 |

| Returns: | The [`pake.TaskContext`](#pake.TaskContext "pake.TaskContext") for the new task. |

`dry_run`(*tasks*)[[source]](_modules/pake/pake.html#Pake.dry_run)[¶](#pake.Pake.dry_run "Permalink to this definition")

Dry run over task, print a ‘visited’ message for each visited task.

When using change detection, only out of date tasks will be visited.

| Raises: | `ValueError` If **tasks** is **None** or an empty list. |

| Raises: | [`pake.MissingOutputsException`](#pake.MissingOutputsException "pake.MissingOutputsException") if a task defines input files/directories without specifying any output files/directories. |

| Raises: | [`pake.InputNotFoundException`](#pake.InputNotFoundException "pake.InputNotFoundException") if a task defines input files/directories but one of them was not found on disk. |

| Raises: | [`pake.UndefinedTaskException`](#pake.UndefinedTaskException "pake.UndefinedTaskException") if one of the default tasks given in the **tasks** parameter is unregistered. |

| Parameters: | **tasks** – Single task, or Iterable of task functions to run (by ref or name). |

`get_define`(*name*, *default=None*)[[source]](_modules/pake/pake.html#Pake.get_define)[¶](#pake.Pake.get_define "Permalink to this definition")

Get a defined value.

This is used to get defines off the command line, as well as retrieve

values exported from top level pake scripts.

If the define is not found, then **None** is returned by default.

The indexer operator can also be used on the pake instance to fetch defines, IE:

```

import pake

pk = pake.init()

value = pk['YOURDEFINE']

```

Which also produces **None** if the define does not exist.

See: [Specifying define values](index.html#specifying-define-values) for documentation covering how

to specify defines on the command line, as well as what types

of values you can use for your defines.

| Parameters: | * **name** – Name of the define

* **default** – The default value to return if the define does not exist

 |

| Returns: | The defines value as a python literal corresponding to the defines type. |

`get_task_context`(*task*)[[source]](_modules/pake/pake.html#Pake.get_task_context)[¶](#pake.Pake.get_task_context "Permalink to this definition")

Get the [`pake.TaskContext`](#pake.TaskContext "pake.TaskContext") object for a specific task.

| Raises: | `ValueError` if the **task** parameter is not a string or a callable function/object. |

| Raises: | [`pake.UndefinedTaskException`](#pake.UndefinedTaskException "pake.UndefinedTaskException") if the task in not registered. |

| Parameters: | **task** – Task function or function name as a string |

| Returns: | [`pake.TaskContext`](#pake.TaskContext "pake.TaskContext") |

`get_task_name`(*task*)[[source]](_modules/pake/pake.html#Pake.get_task_name)[¶](#pake.Pake.get_task_name "Permalink to this definition")

Returns the name of a task by the task function or callable reference used to define it.

The name of the task may be different than the name of the task function/callable when

[`pake.Pake.add\_task()`](#pake.Pake.add_task "pake.Pake.add_task") is used to register the task.

If a string is passed it is returned unmodified as long as the task exists, otherwise

a [`pake.UndefinedTaskException`](#pake.UndefinedTaskException "pake.UndefinedTaskException") is raised.

Example:

```

@pk.task

def my\_task(ctx):

    pass

    

def different\_name(ctx):

    pass

    

pk.add\_task("my\_task2", different\_name)

    

pk.get\_task\_name(my\_task) # -> "my\_task"

pk.get\_task\_name(different\_name) # -> "my\_task2"

```

| Parameters: | **task** – Task name string, or registered task callable. |

| Raises: | `ValueError` if the **task** parameter is not a string or a callable function/object. |

| Raises: | [`pake.UndefinedTaskException`](#pake.UndefinedTaskException "pake.UndefinedTaskException") if the task function/callable is not registered to the pake context. |

| Returns: | Task name string. |

`has_define`(*name*)[[source]](_modules/pake/pake.html#Pake.has_define)[¶](#pake.Pake.has_define "Permalink to this definition")

Test if a define with a given name was provided to pake.

This is useful if **None** might be a valid value for your define,

and you just want to know if it was actually specified on the command

line or with **–stdin-defines**.

| Parameters: | **name** – The name of the define. |

| Returns: | **True** if a define with the given name exists. |

`is_running`[¶](#pake.Pake.is_running "Permalink to this definition")

Check if pake is currently running tasks.

This can be used to determine if code is executing inside of a task.

Example:

```

import pake

pk = pake.init()

pk.print(pk.is\_running) # -> False

@pk.task

def my\_task(ctx):

    ctx.print(pk.is\_running) # -> True

pake.run(pk, tasks=my\_task, call\_exit=False)

pk.print(pk.is\_running) # -> False

```

| Returns: | **True** if pake is currently running tasks, **False** otherwise. |

`max_jobs`[¶](#pake.Pake.max_jobs "Permalink to this definition")

Returns the value of the **jobs** parameter used in the last invocation of [`pake.Pake.run()`](#pake.Pake.run "pake.Pake.run").

This can be used inside of a task to determine if pake is running in multithreaded mode, and the

maximum amount of threads it has been allowed to use for the current invocation.

A **max\_jobs** value of **1** indicates that pake is running all tasks in the current thread,

anything greater than **1** means pake is sending tasks to a threadpool.

See Also: [`pake.Pake.threadpool`](#pake.Pake.threadpool "pake.Pake.threadpool")

`merge_defines_dict`(*dictionary*)[[source]](_modules/pake/pake.html#Pake.merge_defines_dict)[¶](#pake.Pake.merge_defines_dict "Permalink to this definition")

Merge the current defines with another dictionary, overwriting anything

that is already defined with the value from the new dictionary.

| Parameters: | **dictionary** – The dictionary to merge into the current defines. |

`print`(*\*args*, *\*\*kwargs*)[[source]](_modules/pake/pake.html#Pake.print)[¶](#pake.Pake.print "Permalink to this definition")

Print to the file object assigned to [`pake.Pake.stdout`](#pake.Pake.stdout "pake.Pake.stdout")

Shorthand for: `print(..., file=pk.stdout)`

`run`(*tasks*, *jobs=1*)[[source]](_modules/pake/pake.html#Pake.run)[¶](#pake.Pake.run "Permalink to this definition")

Run all given tasks, with an optional level of concurrency.

| Raises: | `ValueError` if **jobs** is less than 1,

or if **tasks** is **None** or an empty list. |

| Raises: | [`pake.TaskException`](#pake.TaskException "pake.TaskException") if an exception occurred while running a task. |

| Raises: | [`pake.TaskExitException`](#pake.TaskExitException "pake.TaskExitException") if `SystemExit` or an exception derived from it

such as [`pake.TerminateException`](#pake.TerminateException "pake.TerminateException") is raised inside of a task. |

| Raises: | [`pake.MissingOutputsException`](#pake.MissingOutputsException "pake.MissingOutputsException") if a task defines input files/directories without specifying any output files/directories. |

| Raises: | [`pake.InputNotFoundException`](#pake.InputNotFoundException "pake.InputNotFoundException") if a task defines input files/directories but one of them was not found on disk. |

| Raises: | [`pake.UndefinedTaskException`](#pake.UndefinedTaskException "pake.UndefinedTaskException") if one of the default tasks given in the *tasks* parameter is unregistered. |

| Parameters: | * **tasks** – Single task, or Iterable of task functions to run (by ref or name).

* **jobs** – Maximum number of threads, defaults to 1. (must be >= 1)

 |

`run_count`[¶](#pake.Pake.run_count "Permalink to this definition")

Contains the number of tasks ran/visited by the last invocation of [`pake.Pake.run()`](#pake.Pake.run "pake.Pake.run") or [`pake.Pake.dry\_run()`](#pake.Pake.dry_run "pake.Pake.dry_run")

If a task did not run because change detection decided it did not need to, then it does not count towards this total.

This also applies when doing a dry run with [`pake.Pake.dry\_run()`](#pake.Pake.dry_run "pake.Pake.dry_run")

| Returns: | Number of tasks last run. |

`set_define`(*name*, *value*)[[source]](_modules/pake/pake.html#Pake.set_define)[¶](#pake.Pake.set_define "Permalink to this definition")

Set a defined value.

| Parameters: | * **name** – The name of the define.

* **value** – The value of the define.

 |

`set_defines_dict`(*dictionary*)[[source]](_modules/pake/pake.html#Pake.set_defines_dict)[¶](#pake.Pake.set_defines_dict "Permalink to this definition")

Set and overwrite all defines with a dictionary object.

| Parameters: | **dictionary** – The dictionary object |

`task`(*\*args*, *i=None*, *o=None*, *show\_header=None*)[[source]](_modules/pake/pake.html#Pake.task)[¶](#pake.Pake.task "Permalink to this definition")

Decorator for registering pake tasks.

Any input files specified must be accompanied by at least one output file.

A callable object, or list of callable objects may be passed to **i** or **o** in addition to

a raw file/directory name or names. This is how **pake.glob** and **pake.pattern** work.

Input/Output Generation Example:

```

def gen\_inputs(pattern):

    def input\_generator():

        return glob.glob(pattern)

    return input\_generator

    

def gen\_output(pattern):

    def output\_generator(inputs):

        # inputs is always a flat list, and a copy

        # inputs is safe to mutate if you want

        for inp in inputs:

            dir = os.path.dirname(inp)

            name, ext = os.path.splitext(os.path.basename(inp))

            yield pattern.replace('{dir}', dir).replace('%', name).replace('{ext}', ext)

    return output\_generator

@pk.task(i=gen\_inputs('\*.c'), o=gen\_outputs('%.o'))

def my\_task(ctx):

    # Do your build task here

    pass

    

@pk.task(i=[gen\_inputs('src\_a/\*.c'), gen\_inputs('src\_b/\*.c')], o=gen\_outputs('{dir}/%.o'))

def my\_task(ctx):

    # Do your build task here

    pass

```

Dependencies Only Example:

```

@pk.task(dependency\_task\_a, dependency\_task\_b)

def my\_task(ctx):

    # Do your build task here

    pass

```

Change Detection Examples:

```

# Dependencies come before input and output files.

@pk.task(dependency\_task\_a, dependency\_task\_b, i='main.c', o='main')

def my\_task(ctx):

    # Do your build task here

    pass

    

# Tasks without input or output files will always run when specified.

@pk.task

def my\_task(ctx):

    # I will always run when specified!

    pass

    

    

# Tasks with dependencies but no input or output files will also

# always run when specified.

@pk.task(dependency\_task\_a, dependency\_task\_b)

def my\_task(ctx):

    # I will always run when specified!

    pass

 

 

# Having an output with no input is allowed, this task

# will always run. The opposite (having an input file with no output file)

# will cause an error. ctx.outdated\_outputs is populated with 'main' in this case.

@pk.task(o='main')

def my\_task(ctx):

    # Do your build task here

    pass

# Single input and single output, 'main.c' has its creation time checked

# against 'main'

@pk.task(i='main.c', o='main')

def my\_task(ctx):

    # Do your build task here

    pass

    

    

# When multiple input files exist and there is only one output file, each input file

# has its creation time checked against the output files creation time.

@pk.task(i=['otherstuff.c', 'main.c'], o='main')

def my\_task(ctx):

    # Do your build task here

    pass

    

    

# all files in 'src/\*.c' have their creation date checked against 'main' 

@pk.task(i=pake.glob('src/\*.c'), o='main')

def my\_task(ctx):

    # Do your build task here

    pass

    

    

# each input file has its creation date checked against its corresponding

# output file in this case. Out of date file names can be found in 

# ctx.outdated\_inputs and ctx.outdated\_outputs. ctx.outdated\_pairs is a

# convenience property which returns: zip(ctx.outdated\_inputs, ctx.outdated\_outputs)

@pk.task(i=['file\_b.c', 'file\_b.c'], o=['file\_b.o', 'file\_b.o'])

def my\_task(ctx):

    # Do your build task here

    pass

    

    

# Similar to the above, inputs and outputs end up being of the same

# length when using pake.glob with pake.pattern

@pk.task(i=pake.glob('src/\*.c'), o=pake.pattern('obj/%.o'))

def my\_task(ctx):

    # Do your build task here

    pass

    

# All input files have their creation date checked against all output files

# if there are more inputs than outputs, in general.

@pk.task(i=['a.c', 'b.c', 'c.c'], o=['main', 'what\_are\_you\_planning'])

def my\_task(ctx):

    # Do your build task here

    pass

    

    

# Leaving the inputs and outputs as empty list will cause the task

# to never run.

@pk.task(i=[], o=[])

def my\_task(ctx):

    # I will never run!

    pass

# If an input generator produces no results 

# (IE, something like pake.glob returns no files) and the tasks 

# outputs also end up being empty such as in this case, 

# then the task will never run.

@pk.task(i=pake.glob('\*.some\_extension\_that\_no\_file\_has'), o=pake.pattern('%.o'))

def my\_task(ctx):

    # I will never run!

    pass

```

| Raises: | [`pake.UndefinedTaskException`](#pake.UndefinedTaskException "pake.UndefinedTaskException") if a given dependency is not a registered task function. |

| Parameters: | * **args** – Tasks which this task depends on, this may be passed as variadic arguments or a single iterable object.

* **i** – Optional input files/directories for change detection.

* **o** – Optional output files/directories for change detection.

* **show\_header** – Whether or not to print an **Executing Task:** header when the task begins executing.

This defaults to **None**, which means the header is printed unless `pake.Pake.show\_task\_header`

is set to **False**. If you specify **True** and `pake.Pake.show\_task\_header` is set to

**False**, it will force the task header to print anyway. By explicitly specifying **True** you

override the `pake.Pake.show\_task\_header` setting.

 |

`task_contexts`[¶](#pake.Pake.task_contexts "Permalink to this definition")

Retrieve the task context objects for all registered tasks.

| Returns: | List of [`pake.TaskContext`](#pake.TaskContext "pake.TaskContext"). |

`task_count`[¶](#pake.Pake.task_count "Permalink to this definition")

Returns the number of registered tasks.

| Returns: | Number of tasks registered to the [`pake.Pake`](#pake.Pake "pake.Pake") instance. |

`terminate`(*return\_code=0*)[[source]](_modules/pake/pake.html#Pake.terminate)[¶](#pake.Pake.terminate "Permalink to this definition")

Shorthand for `pake.terminate(this, return\_code=return\_code)`.

See for more details: [`pake.terminate()`](#pake.terminate "pake.terminate")

| Parameters: | **return\_code** – Return code to exit the pakefile with.

The default return code is [`pake.returncodes.SUCCESS`](#pake.returncodes.SUCCESS "pake.returncodes.SUCCESS"). |

`threadpool`[¶](#pake.Pake.threadpool "Permalink to this definition")

Current execution thread pool.

This will never be anything other than **None** unless pake is running, and its max job count is greater than 1.

Pake is considered to be running when [`pake.Pake.is\_running`](#pake.Pake.is_running "pake.Pake.is_running") equals **True**.

If pake is running with a job count of 1, no threadpool is used so this property will be **None**.

*class* `pake.``TaskContext`(*pake\_obj*, *node*)[[source]](_modules/pake/pake.html#TaskContext)[¶](#pake.TaskContext "Permalink to this definition")

Bases: `object`

Contextual object passed to each task.

`inputs`[¶](#pake.TaskContext.inputs "Permalink to this definition")

> 

> All file inputs, or an empty list.

**Note:**

Not available outside of a task, may only be used while a task is executing.

`outputs`[¶](#pake.TaskContext.outputs "Permalink to this definition")

> 

> All file outputs, or an empty list.

**Note:**

Not available outside of a task, may only be used while a task is executing.

`outdated_inputs`[¶](#pake.TaskContext.outdated_inputs "Permalink to this definition")

> 

> All changed file inputs (or inputs who’s corresponding output is missing), or an empty list.

**Note:**

Not available outside of a task, may only be used while a task is executing.

`oudated_outputs`[¶](#pake.TaskContext.oudated_outputs "Permalink to this definition")

> 

> All out of date file outputs, or an empty list

**Note:**

Not available outside of a task, may only be used while a task is executing.

`call`(*\*args*, *stdin=None*, *shell=False*, *ignore\_errors=False*, *silent=False*, *print\_cmd=True*, *collect\_output=False*)[[source]](_modules/pake/pake.html#TaskContext.call)[¶](#pake.TaskContext.call "Permalink to this definition")

Calls a sub process and returns its return code.

all **stdout/stderr** is written to the task IO file stream. The full command line 

which was used to start the process is printed to the task IO queue before the 

output of the command, unless **print\_cmd=False**.

You can prevent the process from sending its **stdout/stderr** to the task IO queue

by specifying **silent=True**

If a process returns a non-zero return code, this method will raise 

[`pake.TaskSubprocessException`](#pake.TaskSubprocessException "pake.TaskSubprocessException") by default.

If you want the value of non-zero return codes to be returned then you must

pass **ignore\_errors=True** to prevent [`pake.TaskSubprocessException`](#pake.TaskSubprocessException "pake.TaskSubprocessException") from

being thrown, or instead catch the exception and get the return code from it.

**Note:**

[`pake.TaskSubprocessException.output\_stream`](#pake.TaskSubprocessException.output_stream "pake.TaskSubprocessException.output_stream") will be available for retrieving

the output of the process (**stdout** and **stderr** combined) if you handle the exception,

the file stream will be a text mode file object at **seek(0)**.

Example:

```

# strings are parsed using shlex.parse

ctx.call('gcc -c test.c -o test.o')

ctx.call('gcc -c {} -o {}'.format('test.c', 'test.o'))

# pass the same command as a list

ctx.call(['gcc', '-c', 'test.c', '-o', 'test.o'])

# pass the same command using the variadic argument \*args

ctx.call('gcc', '-c', 'test.c', '-o', 'test.o')

# non string iterables in command lists will be flattened, 

# allowing for this syntax to work. ctx.inputs and ctx.outputs

# are both list objects, but anything that is iterable will work

ctx.call(['gcc', '-c', ctx.inputs, '-o', ctx.outputs])

# Fetch a non-zero return code without a 

# pake.TaskSubprocessException. ctx.check\_call

# is better used for this task.

code = ctx.call('which', 'am\_i\_here', 

                ignore\_errors=True,  # Ignore errors (non-zero return codes)

                print\_cmd=False,   # Don't print the command line executed

                silent=True)  # Don't print stdout/stderr to task IO

```

| Parameters: | * **args** – The process command/executable, and additional arguments to pass

to the process. You may pass the command words as a single iterable,

a string, or as variadic arguments.

* **stdin** – Optional file object to pipe into the called process’s **stdin**.

* **shell** – Whether or not to use the system shell for execution of the command.

* **ignore\_errors** – Whether or not to raise a [`pake.TaskSubprocessException`](#pake.TaskSubprocessException "pake.TaskSubprocessException") on non-zero exit codes.

* **silent** – Whether or not to silence **stdout/stderr** from the command. This does keep pake

from printing what command line was run, see the **print\_cmd** argument for that.

* **print\_cmd** – Whether or not to print the executed command line to the tasks output.

The **silent** argument will not keep pake from printing the executed command,

only this argument can do that.

* **collect\_output** – Whether or not to collect all process output to a temporary file

and then incrementally write it back to [`pake.TaskContext.io`](#pake.TaskContext.io "pake.TaskContext.io")

in a synchronized fashion, so that all command output is guaranteed to

come in order and not become interleaved with the output of other tasks

when using [`pake.TaskContext.multitask()`](#pake.TaskContext.multitask "pake.TaskContext.multitask").

See: [Output synchronization with ctx.call & ctx.subpake](index.html#output-synchronization-with-ctx-call-ctx-subpake)

 |

| Returns: | The process return code. |

| Raises: | [`pake.TaskSubprocessException`](#pake.TaskSubprocessException "pake.TaskSubprocessException") if *ignore\_errors* is *False* and the process exits with a non-zero exit code. |

| Raises: | `OSError` (commonly) if a the executed command or file does not exist.

This exception will still be raised even if **ignore\_errors** is **True**. |

| Raises: | `ValueError` if no command + optional arguments are provided. |

*static* `check_call`(*\*args*, *stdin=None*, *shell=False*, *ignore\_errors=False*)[[source]](_modules/pake/pake.html#TaskContext.check_call)[¶](#pake.TaskContext.check_call "Permalink to this definition")

Get the return code of an executed system command, without printing 

any output to the tasks IO queue by default.

None of the process’s **stdout/stderr** will go to the task IO queue, 

and the command that was run will not be printed either.

This function raises [`pake.TaskSubprocessException`](#pake.TaskSubprocessException "pake.TaskSubprocessException") on non-zero

return codes by default.

You should pass pass **ignore\_errors=True** if you want this method to return 

the non-zero value, or instead catch the exception and get the return code from it.

**Note:**

[`pake.TaskSubprocessException.output`](#pake.TaskSubprocessException.output "pake.TaskSubprocessException.output") and [`pake.TaskSubprocessException.output\_stream`](#pake.TaskSubprocessException.output_stream "pake.TaskSubprocessException.output_stream")

will **not** be available in the exception if you handle it.

| Raises: | [`pake.TaskSubprocessException`](#pake.TaskSubprocessException "pake.TaskSubprocessException") if **ignore\_errors** is **False**

and the process exits with a non-zero return code. |

| Raises: | `OSError` (commonly) if a the executed command or file does not exist.

This exception will still be raised even if **ignore\_errors** is **True**. |

| Raises: | `ValueError` if no command + optional arguments are provided. |

| Parameters: | * **args** – Command arguments, same syntax as [`pake.TaskContext.call()`](#pake.TaskContext.call "pake.TaskContext.call")

* **stdin** – Optional file object to pipe into the called process’s **stdin**.

* **shell** – Whether or not to use the system shell for execution of the command.

* **ignore\_errors** – Whether to ignore non-zero return codes and return the code anyway.

 |

| Returns: | Integer return code. |

*static* `check_output`(*\*args*, *stdin=None*, *shell=False*, *ignore\_errors=False*)[[source]](_modules/pake/pake.html#TaskContext.check_output)[¶](#pake.TaskContext.check_output "Permalink to this definition")

Return the output of a system command as a bytes object, without printing

its **stdout/stderr** to the task IO queue. The process command line that

was run will not be printed either.

The returned bytes output will include **stdout** and **stderr** combined, and 

it can be decoded into a string by using the **decode()** method on pythons built 

in **bytes** object.

This function raises [`pake.TaskSubprocessException`](#pake.TaskSubprocessException "pake.TaskSubprocessException") on non-zero

return codes by default.

If you want to return possible error output from the called process’s **stderr** 

you should pass **ignore\_errors=True**, or instead catch the exception and get the 

process output from it.

**Note:**

[`pake.TaskSubprocessException.output`](#pake.TaskSubprocessException.output "pake.TaskSubprocessException.output") will be available for retrieving

the output of the process if you handle the exception, the value will be 

all of **stdout/stderr** as a **bytes** object that must be decoded into a string.

| Raises: | [`pake.TaskSubprocessException`](#pake.TaskSubprocessException "pake.TaskSubprocessException") if **ignore\_errors** is False

and the process exits with a non-zero return code. |

| Raises: | `OSError` (commonly) if a the executed command or file does not exist.

This exception will still be raised even if **ignore\_errors** is **True**. |

| Raises: | `ValueError` if no command + optional arguments are provided. |

| Parameters: | * **args** – Command arguments, same syntax as [`pake.TaskContext.call()`](#pake.TaskContext.call "pake.TaskContext.call")

* **stdin** – Optional file object to pipe into the called process’s **stdin**.

* **shell** – Whether or not to use the system shell for execution of the command.

* **ignore\_errors** – Whether to ignore non-zero return codes and return the output anyway.

 |

| Returns: | Bytes object (program output data) |

`dependencies`[¶](#pake.TaskContext.dependencies "Permalink to this definition")

Immediate dependencies of this task.

returns a list of [`pake.TaskContext`](#pake.TaskContext "pake.TaskContext") representing each

immediate dependency of this task.

**Note:**

This property **will** return a meaningful value outside of a task.

`dependency_outputs`[¶](#pake.TaskContext.dependency_outputs "Permalink to this definition")

Returns a list of output files/directories which represent the outputs of

the tasks immediate dependencies.

**Note:**

Not available outside of a task, may only be used while a task is executing.

`func`[¶](#pake.TaskContext.func "Permalink to this definition")

Task function reference.

This function will be an internal wrapper around

the one you specified and you should not call it.

There is not currently a way to get a reference

to your actual unwrapped task function from the

[`pake.Pake`](#pake.Pake "pake.Pake") object or elsewhere.

However since the `functools.wraps()` decorator is used

when wrapping your task function, metadata such as **func.\_\_doc\_\_** 

will be maintained on this function reference.

`io`[¶](#pake.TaskContext.io "Permalink to this definition")

The task IO file stream, a file like object that is only open for writing during a tasks execution.

Any output to be displayed for the task should be written to this file object.

This file object is a text mode stream, it can be used with the built in **print** function

and other methods that can write text data to a file like object.

When you run pake with more than one job, this will be a reference to a temporary file unless

[`pake.Pake.sync\_output`](#pake.Pake.sync_output "pake.Pake.sync_output") is **False** (It is **False** when **–no-sync-output** is used on the command line).

The temporary file queues up task output when in use, and the task context acquires a lock

and writes it incrementally to [`pake.Pake.stdout`](#pake.Pake.stdout "pake.Pake.stdout") when the task finishes. This is

done to avoid having concurrent task’s writing interleaved output to [`pake.Pake.stdout`](#pake.Pake.stdout "pake.Pake.stdout").

If you run pake with only 1 job or [`pake.Pake.sync\_output`](#pake.Pake.sync_output "pake.Pake.sync_output") is **False**, this

property will return a direct reference to [`pake.Pake.stdout`](#pake.Pake.stdout "pake.Pake.stdout").

`io_lock`[¶](#pake.TaskContext.io_lock "Permalink to this definition")

A contextual lock for acquiring exclusive access to [`pake.TaskContext.io`](#pake.TaskContext.io "pake.TaskContext.io").

This context manager acquires an internal lock for [`pake.Pake.stdout`](#pake.Pake.stdout "pake.Pake.stdout")

that exists on the [`pake.Pake`](#pake.Pake "pake.Pake") object when [`pake.Pake.max\_jobs`](#pake.Pake.max_jobs "pake.Pake.max_jobs") is **1**.

Otherwise, it will acquire a lock for [`pake.TaskContext.io`](#pake.TaskContext.io "pake.TaskContext.io") that

exists inside of the task context, since the task will be buffering output

to an individual temporary file when [`pake.Pake.max\_jobs`](#pake.Pake.max_jobs "pake.Pake.max_jobs") is greater

than **1**.

If [`pake.Pake.sync\_output`](#pake.Pake.sync_output "pake.Pake.sync_output") is **False**, the context manager

returned by this property will not attempt to acquire any lock.

| Returns: | A context manager object that can be used in a **with** statement. |

`multitask`(*aggregate\_exceptions=False*)[[source]](_modules/pake/pake.html#TaskContext.multitask)[¶](#pake.TaskContext.multitask "Permalink to this definition")

Returns a contextual object for submitting work to pake’s current thread pool.

```

@pk.task(i=pake.glob('src/\*.c'), o=pake.pattern('obj/%.o'))

    def build\_c(ctx):

        with ctx.multitask() as mt:

            for i, o in ctx.outdated\_pairs:

                mt.submit(ctx.call, ['gcc', '-c', i, '-o', o])

```

At the end of the **with** statement, all submitted tasks are simultaneously waited on.

The tasks will be checked in order of submission for exceptions, if an exception is

found then the default behavior is to re-raise it on the foreground thread.

You can specify **aggregate\_exceptions=True** if you want all of the exceptions

to be collected into a [`pake.AggregateException`](#pake.AggregateException "pake.AggregateException"), which will then be raised

when [`pake.MultitaskContext.shutdown()`](#pake.MultitaskContext.shutdown "pake.MultitaskContext.shutdown") is called with **wait=True**.

**shutdown** is called at the end of your **with** statement with the **wait**

parameter set to **True**.

| Parameters: | **aggregate\_exceptions** – Whether or not the returned executor should collect

exceptions from all tasks that ended due to an exception,

and then raise a [`pake.AggregateException`](#pake.AggregateException "pake.AggregateException") containing

them upon shutdown. |

| Returns: | [`pake.MultitaskContext`](#pake.MultitaskContext "pake.MultitaskContext") |

`name`[¶](#pake.TaskContext.name "Permalink to this definition")

The task name.

| Returns: | The task name, as a string. |

`node`[¶](#pake.TaskContext.node "Permalink to this definition")

The [`pake.TaskGraph`](#pake.TaskGraph "pake.TaskGraph") node for the task.

`outdated_pairs`[¶](#pake.TaskContext.outdated_pairs "Permalink to this definition")

Short hand for: `zip(ctx.outdated\_inputs, ctx.outdated\_outputs)`

Returns a generator object over outdated (input, output) pairs.

This is only useful when the task has the same number of inputs as it does outputs.

Example:

```

@pk.task(i=pake.glob('src/\*.c'), o=pake.pattern('obj/%.o'))

def build\_c(ctx):

    for i, o in ctx.outdated\_pairs:

        ctx.call(['gcc', '-c', i, '-o', o])

```

**Note:**

Not available outside of a task, may only be used while a task is executing.

`pake`[¶](#pake.TaskContext.pake "Permalink to this definition")

The [`pake.Pake`](#pake.Pake "pake.Pake") instance the task is registered to.

`print`(*\*args*, *\*\*kwargs*)[[source]](_modules/pake/pake.html#TaskContext.print)[¶](#pake.TaskContext.print "Permalink to this definition")

Prints to the task IO file stream using the builtin print function.

Shorthand for: `print(..., file=ctx.io)`

`subpake`(*\*args*, *silent=False*, *ignore\_errors=False*, *collect\_output=False*)[[source]](_modules/pake/pake.html#TaskContext.subpake)[¶](#pake.TaskContext.subpake "Permalink to this definition")

Run [`pake.subpake()`](#pake.subpake "pake.subpake") and direct all output to the task IO file stream.

| Parameters: | * **args** – The script, and additional arguments to pass to the script.

You may pass a list, or use variadic arguments.

* **silent** – If **True**, avoid printing output from the sub-pakefile to the tasks IO queue.

* **ignore\_errors** – If this is **True**, this function will not throw [`pake.SubpakeException`](#pake.SubpakeException "pake.SubpakeException") if

the executed pakefile returns with a non-zero exit code. It will instead return the

exit code from the subprocess to the caller.

* **collect\_output** – Whether or not to collect all subpake output to a temporary file

and then incrementally write it back to [`pake.TaskContext.io`](#pake.TaskContext.io "pake.TaskContext.io")

in a synchronized fashion, so that all command output is guaranteed to

come in order and not become interleaved with the output of other tasks

when using [`pake.TaskContext.multitask()`](#pake.TaskContext.multitask "pake.TaskContext.multitask").

See: [Output synchronization with ctx.call & ctx.subpake](index.html#output-synchronization-with-ctx-call-ctx-subpake)

 |

| Raises: | `ValueError` if no command + optional command arguments are provided. |

| Raises: | `FileNotFoundError` if the first argument (the pakefile) is not found. |

| Raises: | [`pake.SubpakeException`](#pake.SubpakeException "pake.SubpakeException") if the called pakefile script encounters an

error and **ignore\_errors=False** . |

*class* `pake.``MultitaskContext`(*ctx*, *aggregate\_exceptions=False*)[[source]](_modules/pake/pake.html#MultitaskContext)[¶](#pake.MultitaskContext "Permalink to this definition")

Bases: `concurrent.futures.\_base.Executor`

Returned by [`pake.TaskContext.multitask()`](#pake.TaskContext.multitask "pake.TaskContext.multitask") (see for more details).

This object has (for the most part) has the exact same behavior and interface as

`concurrent.futures.ThreadPoolExecutor` from the built in Python module

`concurrent.futures`.

If you need further reference on how its member functions behave, you can also consult

the official Python doc for that class.

This object is meant to be used in a **with** statement. At the end of the **with**

statement all of your submitted work will be waited on, so you do not have to do it

manually with [`pake.MultitaskContext.shutdown()`](#pake.MultitaskContext.shutdown "pake.MultitaskContext.shutdown").

Using a **with** statement is also exception safe.

`aggregate_exceptions`[¶](#pake.MultitaskContext.aggregate_exceptions "Permalink to this definition")

Whether or not the multitasking context should collect all exceptions

that occurred inside of submitted tasks upon shutdown, and then raise

a [`pake.AggregateException`](#pake.AggregateException "pake.AggregateException") containing them.

This is **False** by default, the normal behaviour is to search

the tasks in the order of submission for exceptions upon shutdown, and

then re-raise the first exception that was encountered on the foreground thread.

`map`(*fn*, *\*iterables*, *timeout=None*, *chunksize=1*)[[source]](_modules/pake/pake.html#MultitaskContext.map)[¶](#pake.MultitaskContext.map "Permalink to this definition")

Returns an iterator equivalent to `map(fn, iter)`.

| Parameters: | * **fn** – A callable that will take as many arguments as there are passed iterables.

* **timeout** – The maximum number of seconds to wait. If **None**, then there is no limit on the wait time.

* **chunksize** – The size of the chunks the iterable will be broken into.

 |

| Returns: | An iterator equivalent to: `map(func, \*iterables)` but the calls may be evaluated out-of-order. |

| Raises: | `TimeoutError` If the entire result iterator could not be generated before the given timeout. |

| Raises: | `Exception` If `fn(\*args)` raises for any values. |

`shutdown`(*wait=True*)[[source]](_modules/pake/pake.html#MultitaskContext.shutdown)[¶](#pake.MultitaskContext.shutdown "Permalink to this definition")

Shutdown multitasking and free resources, optionally wait on all submitted tasks.

It is not necessary to call this function if you are using the context in a **with** statement.

If you specify **wait=False**, this method will not propagate any exceptions out of your submitted tasks.

| Parameters: | **wait** – Whether or not to wait on all submitted tasks, default is true. |

`submit`(*fn*, *\*args*, *\*\*kwargs*)[[source]](_modules/pake/pake.html#MultitaskContext.submit)[¶](#pake.MultitaskContext.submit "Permalink to this definition")

Submit a task to pakes current threadpool.

If no thread pool exists, such as in the case of **–jobs 1**, then the submitted

function is immediately executed in the current thread.

This function has an identical call syntax to **concurrent.futures.Executor.submit**.

Example:

```

mt.submit(work\_function, arg1, arg2, keyword\_arg='arg')

```

| Returns: | `concurrent.futures.Future` |

*class* `pake.``TaskGraph`(*name*, *func*)[[source]](_modules/pake/pake.html#TaskGraph)[¶](#pake.TaskGraph "Permalink to this definition")

Bases: [`pake.graph.Graph`](#pake.graph.Graph "pake.graph.Graph")

Task graph node.

`func`[¶](#pake.TaskGraph.func "Permalink to this definition")

Task function reference.

This function will be an internal wrapper around

the one you specified and you should not call it.

There is not currently a way to get a reference

to your actual unwrapped task function from the

[`pake.Pake`](#pake.Pake "pake.Pake") object or elsewhere.

However since the `functools.wraps()` decorator is used

when wrapping your task function, metadata such as **func.\_\_doc\_\_** 

will be maintained on this function reference.

`add_edge`(*edge*)[¶](#pake.TaskGraph.add_edge "Permalink to this definition")

Add an edge to the graph.

| Parameters: | **edge** – The edge to add (another [`pake.graph.Graph`](#pake.graph.Graph "pake.graph.Graph") object) |

`edges`[¶](#pake.TaskGraph.edges "Permalink to this definition")

Retrieve a set of edges from this graph node.

| Returns: | A set() of adjacent nodes. |

`name`[¶](#pake.TaskGraph.name "Permalink to this definition")

The task name.

| Returns: | The task name, as a string. |

`remove_edge`(*edge*)[¶](#pake.TaskGraph.remove_edge "Permalink to this definition")

Remove an edge from the graph by reference.

| Parameters: | **edge** – Reference to a [`pake.graph.Graph`](#pake.graph.Graph "pake.graph.Graph") object. |

`topological_sort`()[¶](#pake.TaskGraph.topological_sort "Permalink to this definition")

Return a generator object that runs topological sort as it is iterated over.

Nodes that have been visited will not be revisited, making infinite recursion impossible.

| Returns: | A generator that produces [`pake.graph.Graph`](#pake.graph.Graph "pake.graph.Graph") nodes. |

`pake.``pattern`(*file\_pattern*)[[source]](_modules/pake/pake.html#pattern)[¶](#pake.pattern "Permalink to this definition")

Produce a substitution pattern that can be used in place of an output file.

The **%** character represents the file name, while **{dir}** and **{ext}** represent the directory of

the input file, and the input file extension.

Example:

```

@pk.task(i=pake.glob('src/\*.c'), o=pake.pattern('obj/%.o'))

def build\_c(ctx):

    for i, o in ctx.outdated\_pairs:

        ctx.call('gcc', '-c', i, '-o', o)

        

@pk.task(i=[pake.glob('src\_a/\*.c'), pake.glob('src\_b/\*.c')], o=pake.pattern('{dir}/%.o'))

def build\_c(ctx):

    for i, o in ctx.outdated\_pairs:

        ctx.call('gcc', '-c', i, '-o', o)

```

[`pake.pattern()`](#pake.pattern "pake.pattern") returns function similar to this:

```

def output\_generator(inputs):

    # inputs is always a flat list, and a copy

    # inputs is safe to mutate

    for inp in inputs:

        dir = os.path.dirname(inp)

        name, ext = os.path.splitext(os.path.basename(inp))

        yield file\_pattern.replace('{dir}', dir).replace('%', name).replace('{ext}', ext)

```

`pake.``glob`(*expression*)[[source]](_modules/pake/pake.html#glob)[¶](#pake.glob "Permalink to this definition")

Deferred file input glob, the glob is not executed until the task executes.

This input generator handles recursive directory globs by default, denoted by a double asterisk.

It will return directory names as well if your glob expression matches them.

The syntax used is the same as the built in `glob.glob()` from pythons `glob` module.

Example:

```

@pk.task(build\_c, i=pake.glob('obj/\*.o'), o='main')

def build\_exe(ctx):

   ctx.call('gcc', ctx.inputs, '-o', ctx.outputs)

@pk.task(build\_c, i=[pake.glob('obj\_a/\*.o'), pake.glob('obj\_b/\*.o')], o='main')

def build\_exe(ctx):

   ctx.call('gcc', ctx.inputs, '-o', ctx.outputs)

```

Recursive Directory Search Example:

```

# Find everything under 'src' that is a .c file, including

# in sub directories of 'src' and all the way to the bottom of

# the directory tree.

# pake.pattern is used to put the object file for each .c file

# next to it in the same directory.

@pk.task(i=pake.glob('src/\*\*/\*.c'), o=pake.pattern('{dir}/%.o'))

def build\_c(ctx):

    for i, o in ctx.outdated\_pairs:

        ctx.call('gcc', '-c', i, '-o', o)

```

[`pake.glob()`](#pake.glob "pake.glob") returns a function similar to this:

```

def input\_generator():

    return glob.iglob(expression, recursive=True)

```

| Returns: | A callable function object, which returns a

generator over the file glob results as strings. |

*class* `pake.``FileHelper`(*printer=None*)[[source]](_modules/pake/filehelper.html#FileHelper)[¶](#pake.FileHelper "Permalink to this definition")

Bases: `object`

A helper class for dealing with common file operations inside and outside of pake tasks. Instantiating this class

with the **printer** parameter set to a [`pake.TaskContext`](#pake.TaskContext "pake.TaskContext") instance will cause it to print information about

file system operations it performs to the tasks output queue. Each function can be silenced by setting the **silent**

parameter of the function to **True**.

`copy`(*src*, *dest*, *copy\_metadata=False*, *follow\_symlinks=True*, *silent=False*)[[source]](_modules/pake/filehelper.html#FileHelper.copy)[¶](#pake.FileHelper.copy "Permalink to this definition")

Copy a file to a destination.

See `shutil.copy()` and `shutil.copy2()` (when **copy\_metadata** is True)

| Parameters: | * **src** – The file.

* **dest** – The destination path.

* **copy\_metadata** – If True, file metadata like creation time will be copied to the new file.

* **follow\_symlinks** – Whether or not to follow symlinks while copying.

* **silent** – If True, Don’t print information to the tasks output.

 |

`copytree`(*self*, *src*, *dst*, *symlinks=False*, *ignore=None*, *copy\_function=shutil.copy2*, *ignore\_dangling\_symlinks=False*, *silent=False*)[[source]](_modules/pake/filehelper.html#FileHelper.copytree)[¶](#pake.FileHelper.copytree "Permalink to this definition")

Recursively copy a directory tree, See `shutil.copytree()`.

The destination directory must not already exist.

If exception(s) occur, an Error is raised with a list of reasons.

If the optional symlinks flag is true, symbolic links in the

source tree result in symbolic links in the destination tree; if

it is false, the contents of the files pointed to by symbolic

links are copied. If the file pointed by the symlink doesn’t

exist, an exception will be added in the list of errors raised in

an Error exception at the end of the copy process.

You can set the optional ignore\_dangling\_symlinks flag to true if you

want to silence this exception. Notice that this has no effect on

platforms that don’t support `os.symlink()`.

The optional ignore argument is a callable. If given, it

is called with the src parameter, which is the directory

being visited by `shutil.copytree()`, and names which is the list of

src contents, as returned by `os.listdir()`:

callable(src, names) -> ignored\_names

Since `shutil.copytree()` is called recursively, the callable will be

called once for each directory that is copied. It returns a

list of names relative to the src directory that should

not be copied.

The optional copy\_function argument is a callable that will be used

to copy each file. It will be called with the source path and the

destination path as arguments. By default, `shutil.copy2()` is used, but any

function that supports the same signature (like `shutil.copy()`) can be used.

| Raises: | **shutil.Error** – If exception(s) occur, an Error is raised with a list of reasons. |

| Parameters: | * **src** – The source directory tree.

* **dst** – The destination path.

* **symlinks** – If True, try to copy symlinks.

* **ignore** – Callable, used specifying files to ignore in a specific directory as copytree

walks the source directory tree. `callable(src, names) -> ignored\_names`

* **copy\_function** – The copy function, if not specified `shutil.copy2()` is used.

* **ignore\_dangling\_symlinks** – If True, don’t throw an exception when the file pointed to

by a symlink does not exist.

* **silent** – If True, Don’t print info the the tasks output.

 |

`glob_remove`(*glob\_pattern*, *silent=False*)[[source]](_modules/pake/filehelper.html#FileHelper.glob_remove)[¶](#pake.FileHelper.glob_remove "Permalink to this definition")

Remove files using a glob pattern, this makes use of pythons built in glob module.

This function handles recursive directory globing patterns by default.

Files are removed using `os.remove()`.

| Parameters: | * **glob\_pattern** – The glob pattern to use to search for files to remove.

* **silent** – If True, don’t print information to the tasks output.

 |

| Raises: | **OSError** – Raised if a file is in use (On Windows), or if there is another problem deleting one of the files. |

`glob_remove_dirs`(*glob\_pattern*, *silent=False*)[[source]](_modules/pake/filehelper.html#FileHelper.glob_remove_dirs)[¶](#pake.FileHelper.glob_remove_dirs "Permalink to this definition")

Remove directories using a glob pattern, this makes use of pythons built in glob module.

This function handles recursive directory globing patterns by default.

This uses `shutil.rmtree()` to remove directories.

This function will remove non empty directories.

| Parameters: | * **glob\_pattern** – The glob pattern to use to search for directories to remove.

* **silent** – If True, don’t print information to the tasks output.

 |

`makedirs`(*path*, *mode=511*, *silent=False*, *exist\_ok=True*)[[source]](_modules/pake/filehelper.html#FileHelper.makedirs)[¶](#pake.FileHelper.makedirs "Permalink to this definition")

Create a directory tree if it does not exist, if the directory tree exists already this function does nothing.

This uses `os.makedirs()`.

| Parameters: | * **path** – The directory path/tree.

* **mode** – The permissions umask to use for the directories.

* **silent** – If True, don’t print information to the tasks output.

* **exist\_ok** – If False, an OSError will be thrown if any directory

in the given path already exists.

 |

| Raises: | **OSError** – Raised for all directory creation errors (aside from *errno.EEXIST* if **exist\_ok** is **True**) |

`move`(*self*, *src*, *dest*, *copy\_function=shutil.copy2*, *silent=False*)[[source]](_modules/pake/filehelper.html#FileHelper.move)[¶](#pake.FileHelper.move "Permalink to this definition")

Recursively move a file or directory to another location. (See shutil.move)

This is similar to the Unix “mv” command. Return the file or directory’s

destination.

If the destination is a directory or a symlink to a directory, the source

is moved inside the directory. The destination path must not already

exist.

If the destination already exists but is not a directory, it may be

overwritten depending on `os.rename()` semantics.

If the destination is on our current filesystem, then `os.rename()` is used.

Otherwise, src is copied to the destination and then removed. Symlinks are

recreated under the new name if `os.rename()` fails because of cross

filesystem renames.

The optional copy\_function argument is a callable that will be used

to copy the source or it will be delegated to `shutil.copytree()`.

By default, `shutil.copy2()` is used, but any function that supports the same

signature (like `shutil.copy()`) can be used.

| Raises: | **shutil.Error** – If the destination already exists, or if src is moved into itself. |

| Parameters: | * **src** – The file.

* **dest** – The destination to move the file to.

* **copy\_function** – The copy function to use for copying individual files.

* **silent** – If True, don’t print information to the tasks output.

 |

`printer`[¶](#pake.FileHelper.printer "Permalink to this definition")

Return the printer object associated with this [`pake.FileHelper`](#pake.FileHelper "pake.FileHelper").

If one does not exist, return **None**.

`remove`(*path*, *silent=False*, *must\_exist=False*)[[source]](_modules/pake/filehelper.html#FileHelper.remove)[¶](#pake.FileHelper.remove "Permalink to this definition")

Remove a file from disk if it exists, otherwise do nothing, uses `os.remove()`.

| Raises: | * **FileNotFoundError** – If must\_exist is True, and the file does not exist.

* **OSError** – If the path is a directory.

 |

| Parameters: | * **path** – The path of the file to remove.

* **silent** – If True, don’t print information to the tasks output.

* **must\_exist** – If set to True, a FileNotFoundError will be raised if the file does not exist.

 |

`rmtree`(*path*, *silent=False*, *must\_exist=False*)[[source]](_modules/pake/filehelper.html#FileHelper.rmtree)[¶](#pake.FileHelper.rmtree "Permalink to this definition")

Remove a directory tree if it exist, if the directory tree does not exists this function does nothing.

This uses `shutil.rmtree()`.

This function will remove non empty directories.

| Raises: | **FileNotFoundError** – Raised if must\_exist is True and the given path does not exist. |

| Parameters: | * **path** – The directory path/tree.

* **silent** – If True, don’t print information to the tasks output.

* **must\_exist** – If True, a FileNotFoundError will be raised if the directory

does not exist

 |

`touch`(*file\_name*, *mode=438*, *exist\_ok=True*, *silent=False*)[[source]](_modules/pake/filehelper.html#FileHelper.touch)[¶](#pake.FileHelper.touch "Permalink to this definition")

Create a file at this given path. If mode is given, it is combined with the process’ umask value to determine

the file mode and access flags. If the file already exists, the function succeeds if exist\_ok is true

(and its modification time is updated to the current time), otherwise `FileExistsError` is raised.

This uses `pathlib.Path.touch()`.

| Raises: | **FileExistsError** – Raised if **exist\_ok** is **False** and the file already exists. |

| Parameters: | * **file\_name** – The file name.

* **mode** – The permissions umask.

* **exist\_ok** – whether or not it is okay for the file to exist already.

* **silent** – If True, don’t print information to the tasks output.

 |

*exception* `pake.``TaskException`(*task\_name*, *exception*)[[source]](_modules/pake/pake.html#TaskException)[¶](#pake.TaskException "Permalink to this definition")

Bases: `Exception`

Raised by [`pake.Pake.run()`](#pake.Pake.run "pake.Pake.run") if an exception is encountered running/visiting a task.

`exception`[¶](#pake.TaskException.exception "Permalink to this definition")

The exception raised.

`task_name`[¶](#pake.TaskException.task_name "Permalink to this definition")

The name of the task which the exception was raised in.

`exception_name`[¶](#pake.TaskException.exception_name "Permalink to this definition")

The fully qualified name of the exception object.

`print_traceback`(*file=None*)[[source]](_modules/pake/pake.html#TaskException.print_traceback)[¶](#pake.TaskException.print_traceback "Permalink to this definition")

Print the traceback of the exception that was raised inside the task to a file object.

| Parameters: | **file** – The file object to print to. Default value is `pake.conf.stderr` if **None** is specified. |

*exception* `pake.``TaskExitException`(*task\_name*, *exception*)[[source]](_modules/pake/pake.html#TaskExitException)[¶](#pake.TaskExitException "Permalink to this definition")

Bases: `Exception`

Raised when `SystemExit` or an exception derived from it is thrown inside a task.

This is raised from [`pake.Pake.run()`](#pake.Pake.run "pake.Pake.run") when **exit()**, [`pake.terminate()`](#pake.terminate "pake.terminate"),

or [`pake.Pake.terminate()`](#pake.Pake.terminate "pake.Pake.terminate") is called inside of a task.

`task_name`[¶](#pake.TaskExitException.task_name "Permalink to this definition")

The name of the task in which **exit** was called.

`exception`[¶](#pake.TaskExitException.exception "Permalink to this definition")

Reference to the `SystemExit` exception which caused this exception to be raised.

`print_traceback`(*file=None*)[[source]](_modules/pake/pake.html#TaskExitException.print_traceback)[¶](#pake.TaskExitException.print_traceback "Permalink to this definition")

Print the traceback of the `SystemExit` exception that was raised inside the task to a file object.

| Parameters: | **file** – The file object to print to. Default value is `pake.conf.stderr` if **None** is specified. |

`return_code`[¶](#pake.TaskExitException.return_code "Permalink to this definition")

The return code passed to **exit()** inside the task.

*exception* `pake.``TaskSubprocessException`(*cmd*, *returncode*, *output=None*, *output\_stream=None*, *message=None*)[[source]](_modules/pake/pake.html#TaskSubprocessException)[¶](#pake.TaskSubprocessException "Permalink to this definition")

Bases: [`pake.process.StreamingSubprocessException`](#pake.process.StreamingSubprocessException "pake.process.StreamingSubprocessException")

Raised by default upon encountering a non-zero return code from a subprocess spawned

by the [`pake.TaskContext`](#pake.TaskContext "pake.TaskContext") object.

This exception can be raised from [`pake.TaskContext.call()`](#pake.TaskContext.call "pake.TaskContext.call"),

[`pake.TaskContext.check\_call()`](#pake.TaskContext.check_call "pake.TaskContext.check_call"), and [`pake.TaskContext.check\_output()`](#pake.TaskContext.check_output "pake.TaskContext.check_output").

`cmd`[¶](#pake.TaskSubprocessException.cmd "Permalink to this definition")

Executed command in list form.

`returncode`[¶](#pake.TaskSubprocessException.returncode "Permalink to this definition")

Process returncode.

`message`[¶](#pake.TaskSubprocessException.message "Permalink to this definition")

Optional message from the raising function, may be **None**

`filename`[¶](#pake.TaskSubprocessException.filename "Permalink to this definition")

Filename describing the file from which the process call was initiated. (might be None)

`function_name`[¶](#pake.TaskSubprocessException.function_name "Permalink to this definition")

Function name describing the function which initiated the process call. (might be None)

`line_number`[¶](#pake.TaskSubprocessException.line_number "Permalink to this definition")

Line Number describing the line where the process call was initiated. (might be None)

`output`[¶](#pake.TaskSubprocessException.output "Permalink to this definition")

All output of the process (including **stderr**) as a bytes object

if it is available, otherwise this property is **None**.

`output_stream`[¶](#pake.TaskSubprocessException.output_stream "Permalink to this definition")

All output of the process (including **stderr**) as a file 

object at **seek(0)** if it is available, otherwise this property is **None**.

If this property is not **None** and you call [`pake.TaskSubprocessException.write\_info()`](#pake.TaskSubprocessException.write_info "pake.TaskSubprocessException.write_info"),

this property will become **None** because that method reads the stream and disposes of it.

The stream will be a text mode stream.

`write_info`(*file*)[¶](#pake.TaskSubprocessException.write_info "Permalink to this definition")

Writes information about the subprocess exception to a file like object.

This is necessary over implementing in \_\_str\_\_, because the process output might be 

drawn from another file to prevent issues with huge amounts of process output.

Calling this method will cause [`pake.TaskSubprocessException.output\_stream`](#pake.TaskSubprocessException.output_stream "pake.TaskSubprocessException.output_stream") to

become **None** if it already isn’t.

| Parameters: | **file** – The text mode file object to write the information to. |

*exception* `pake.``InputNotFoundException`(*task\_name*, *output\_name*)[[source]](_modules/pake/pake.html#InputNotFoundException)[¶](#pake.InputNotFoundException "Permalink to this definition")

Bases: `Exception`

Raised by [`pake.Pake.run()`](#pake.Pake.run "pake.Pake.run") and [`pake.Pake.dry\_run()`](#pake.Pake.dry_run "pake.Pake.dry_run") if a task with inputs

declared cannot find an input file/directory on disk.

*exception* `pake.``MissingOutputsException`(*task\_name*)[[source]](_modules/pake/pake.html#MissingOutputsException)[¶](#pake.MissingOutputsException "Permalink to this definition")

Bases: `Exception`

Raised by [`pake.Pake.run()`](#pake.Pake.run "pake.Pake.run") and [`pake.Pake.dry\_run()`](#pake.Pake.dry_run "pake.Pake.dry_run") if a task declares input files without

specifying any output files/directories.

*exception* `pake.``UndefinedTaskException`(*task\_name*)[[source]](_modules/pake/pake.html#UndefinedTaskException)[¶](#pake.UndefinedTaskException "Permalink to this definition")

Bases: `Exception`

Raised on attempted lookup/usage of an unregistered task function or task name.

`task_name`[¶](#pake.UndefinedTaskException.task_name "Permalink to this definition")

The name of the referenced task.

*exception* `pake.``RedefinedTaskException`(*task\_name*)[[source]](_modules/pake/pake.html#RedefinedTaskException)[¶](#pake.RedefinedTaskException "Permalink to this definition")

Bases: `Exception`

Raised on registering a duplicate task.

`task_name`[¶](#pake.RedefinedTaskException.task_name "Permalink to this definition")

The name of the redefined task.

*exception* `pake.``PakeUninitializedException`[[source]](_modules/pake/program.html#PakeUninitializedException)[¶](#pake.PakeUninitializedException "Permalink to this definition")

Bases: `Exception`

Thrown if a function is called which depends on [`pake.init()`](#pake.init "pake.init") being called first.

*exception* `pake.``SubpakeException`(*cmd*, *returncode*, *output=None*, *output\_stream=None*, *message=None*)[[source]](_modules/pake/subpake.html#SubpakeException)[¶](#pake.SubpakeException "Permalink to this definition")

Bases: [`pake.process.StreamingSubprocessException`](#pake.process.StreamingSubprocessException "pake.process.StreamingSubprocessException")

Raised upon encountering a non-zero return code from a subpake invocation.

This exception is raised from both [`pake.subpake()`](#pake.subpake "pake.subpake") and [`pake.TaskContext.subpake()`](#pake.TaskContext.subpake "pake.TaskContext.subpake").

`cmd`[¶](#pake.SubpakeException.cmd "Permalink to this definition")

Executed subpake command in list form.

`returncode`[¶](#pake.SubpakeException.returncode "Permalink to this definition")

Process returncode.

`message`[¶](#pake.SubpakeException.message "Permalink to this definition")

Optional message from the raising function, may be **None**

`filename`[¶](#pake.SubpakeException.filename "Permalink to this definition")

Filename describing the file from which the process call was initiated. (might be None)

`function_name`[¶](#pake.SubpakeException.function_name "Permalink to this definition")

Function name describing the function which initiated the process call. (might be None)

`line_number`[¶](#pake.SubpakeException.line_number "Permalink to this definition")

Line Number describing the line where the process call was initiated. (might be None)

`output`[¶](#pake.SubpakeException.output "Permalink to this definition")

All output of the process (including **stderr**) as a bytes object

if it is available, otherwise this property is **None**.

`output_stream`[¶](#pake.SubpakeException.output_stream "Permalink to this definition")

All output of the process (including **stderr**) as a file 

object at **seek(0)** if it is available, otherwise this property is **None**.

If this property is not **None** and you call [`pake.TaskSubprocessException.write\_info()`](#pake.TaskSubprocessException.write_info "pake.TaskSubprocessException.write_info"),

this property will become **None** because that method reads the stream and disposes of it.

The stream will be a text mode stream.

`write_info`(*file*)[¶](#pake.SubpakeException.write_info "Permalink to this definition")

Writes information about the subprocess exception to a file like object.

This is necessary over implementing in \_\_str\_\_, because the process output might be 

drawn from another file to prevent issues with huge amounts of process output.

Calling this method will cause [`pake.TaskSubprocessException.output\_stream`](#pake.TaskSubprocessException.output_stream "pake.TaskSubprocessException.output_stream") to

become **None** if it already isn’t.

| Parameters: | **file** – The text mode file object to write the information to. |

*exception* `pake.``TerminateException`(*\*args*)[[source]](_modules/pake/program.html#TerminateException)[¶](#pake.TerminateException "Permalink to this definition")

Bases: `SystemExit`

This exception is raised by [`pake.terminate()`](#pake.terminate "pake.terminate") and [`pake.Pake.terminate()`](#pake.Pake.terminate "pake.Pake.terminate"),

it derives `SystemExit` and if it is not caught pake will exit gracefully with

the return code provided to the exception.

If this exception is raised inside of a task, [`pake.Pake.run()`](#pake.Pake.run "pake.Pake.run") with raise a

[`pake.TaskExitException`](#pake.TaskExitException "pake.TaskExitException") in response.

`code`[¶](#pake.TerminateException.code "Permalink to this definition")

exception code

*exception* `pake.``AggregateException`(*exceptions*)[[source]](_modules/pake/pake.html#AggregateException)[¶](#pake.AggregateException "Permalink to this definition")

Bases: `Exception`

Thrown upon [`pake.MultitaskContext.shutdown()`](#pake.MultitaskContext.shutdown "pake.MultitaskContext.shutdown") if the context had

its [`pake.MultitaskContext.aggregate\_exceptions`](#pake.MultitaskContext.aggregate_exceptions "pake.MultitaskContext.aggregate_exceptions") setting set to **True**

and one or more submitted tasks encountered an exception.

See the **aggregate\_exceptions** parameter of [`pake.TaskContext.multitask()`](#pake.TaskContext.multitask "pake.TaskContext.multitask").

`write_info`(*file=None*)[[source]](_modules/pake/pake.html#AggregateException.write_info)[¶](#pake.AggregateException.write_info "Permalink to this definition")

Write information about all the encountered exceptions to a file like object.

If you specify the file as **None**, the default is `pake.conf.stderr`

The information written is not guaranteed to be available for writing more than once.

Exceptions derived from [`pake.process.StreamingSubprocessException`](#pake.process.StreamingSubprocessException "pake.process.StreamingSubprocessException")

have special handling in this function, as they can incrementally stream

information from a temp file and then dispose of it. They must have **write\_info**

called on them as well.

| Parameters: | **file** – A text mode file like object to write information to. |

### Submodules[¶](#submodules "Permalink to this headline")

#### Module: pake.graph[¶](#module-pake.graph "Permalink to this headline")

*class* `pake.graph.``Graph`[[source]](_modules/pake/graph.html#Graph)[¶](#pake.graph.Graph "Permalink to this definition")

Bases: `object`

Represents a node in a directed graph.

`add_edge`(*edge*)[[source]](_modules/pake/graph.html#Graph.add_edge)[¶](#pake.graph.Graph.add_edge "Permalink to this definition")

Add an edge to the graph.

| Parameters: | **edge** – The edge to add (another [`pake.graph.Graph`](#pake.graph.Graph "pake.graph.Graph") object) |

`edges`[¶](#pake.graph.Graph.edges "Permalink to this definition")

Retrieve a set of edges from this graph node.

| Returns: | A set() of adjacent nodes. |

`remove_edge`(*edge*)[[source]](_modules/pake/graph.html#Graph.remove_edge)[¶](#pake.graph.Graph.remove_edge "Permalink to this definition")

Remove an edge from the graph by reference.

| Parameters: | **edge** – Reference to a [`pake.graph.Graph`](#pake.graph.Graph "pake.graph.Graph") object. |

`topological_sort`()[[source]](_modules/pake/graph.html#Graph.topological_sort)[¶](#pake.graph.Graph.topological_sort "Permalink to this definition")

Return a generator object that runs topological sort as it is iterated over.

Nodes that have been visited will not be revisited, making infinite recursion impossible.

| Returns: | A generator that produces [`pake.graph.Graph`](#pake.graph.Graph "pake.graph.Graph") nodes. |

#### Module: pake.process[¶](#module-pake.process "Permalink to this headline")

Methods for spawning processes.

`pake.process.``DEVNULL`[¶](#pake.process.DEVNULL "Permalink to this definition")

Analog for `subprocess.DEVNULL`

`pake.process.``STDOUT`[¶](#pake.process.STDOUT "Permalink to this definition")

Analog for `subprocess.STDOUT`

`pake.process.``PIPE`[¶](#pake.process.PIPE "Permalink to this definition")

Analog for `subprocess.PIPE`

*exception* `pake.process.``ProcessException`(*message*)[[source]](_modules/pake/process.html#ProcessException)[¶](#pake.process.ProcessException "Permalink to this definition")

Bases: `Exception`

Base class for process exceptions.

*exception* `pake.process.``StreamingSubprocessException`(*cmd*, *returncode*, *output=None*, *output\_stream=None*, *message=None*)[[source]](_modules/pake/process.html#StreamingSubprocessException)[¶](#pake.process.StreamingSubprocessException "Permalink to this definition")

Bases: [`pake.process.ProcessException`](#pake.process.ProcessException "pake.process.ProcessException")

A base class for sub-process exceptions which need to be able to handle reporting huge

amounts of process output when a process fails.

This exception is used as a base class for process exceptions thrown from [`pake.subpake()`](#pake.subpake "pake.subpake"), and the

process spawning methods in the [`pake.TaskContext`](#pake.TaskContext "pake.TaskContext") object.

`cmd`[¶](#pake.process.StreamingSubprocessException.cmd "Permalink to this definition")

Executed command in list form.

`returncode`[¶](#pake.process.StreamingSubprocessException.returncode "Permalink to this definition")

Process returncode.

`message`[¶](#pake.process.StreamingSubprocessException.message "Permalink to this definition")

Optional message from the raising function, may be **None**

`filename`[¶](#pake.process.StreamingSubprocessException.filename "Permalink to this definition")

Filename describing the file from which the process call was initiated. (might be None)

`function_name`[¶](#pake.process.StreamingSubprocessException.function_name "Permalink to this definition")

Function name describing the function which initiated the process call. (might be None)

`line_number`[¶](#pake.process.StreamingSubprocessException.line_number "Permalink to this definition")

Line Number describing the line where the process call was initiated. (might be None)

`output`[¶](#pake.process.StreamingSubprocessException.output "Permalink to this definition")

All output of the process (including **stderr**) as a bytes object

if it is available, otherwise this property is **None**.

`output_stream`[¶](#pake.process.StreamingSubprocessException.output_stream "Permalink to this definition")

All output of the process (including **stderr**) as a file 

object at **seek(0)** if it is available, otherwise this property is **None**.

If this property is not **None** and you call [`pake.TaskSubprocessException.write\_info()`](#pake.TaskSubprocessException.write_info "pake.TaskSubprocessException.write_info"),

this property will become **None** because that method reads the stream and disposes of it.

The stream will be a text mode stream.

`write_info`(*file*)[[source]](_modules/pake/process.html#StreamingSubprocessException.write_info)[¶](#pake.process.StreamingSubprocessException.write_info "Permalink to this definition")

Writes information about the subprocess exception to a file like object.

This is necessary over implementing in \_\_str\_\_, because the process output might be 

drawn from another file to prevent issues with huge amounts of process output.

Calling this method will cause [`pake.TaskSubprocessException.output\_stream`](#pake.TaskSubprocessException.output_stream "pake.TaskSubprocessException.output_stream") to

become **None** if it already isn’t.

| Parameters: | **file** – The text mode file object to write the information to. |

*exception* `pake.process.``CalledProcessException`(*cmd*, *returncode*, *output=None*, *stderr=None*)[[source]](_modules/pake/process.html#CalledProcessException)[¶](#pake.process.CalledProcessException "Permalink to this definition")

Bases: [`pake.process.ProcessException`](#pake.process.ProcessException "pake.process.ProcessException")

Raised when [`pake.process.check\_call()`](#pake.process.check_call "pake.process.check_call") or [`pake.process.check\_output()`](#pake.process.check_output "pake.process.check_output") and the process returns a non-zero exit status.

This exception is only raised by process spawning methods in the [`pake.process`](#module-pake.process "pake.process") module.

`cmd`[¶](#pake.process.CalledProcessException.cmd "Permalink to this definition")

Executed command

`timeout`[¶](#pake.process.CalledProcessException.timeout "Permalink to this definition")

Timeout in seconds.

`output`[¶](#pake.process.CalledProcessException.output "Permalink to this definition")

Output of the child process if it was captured by [`pake.process.check\_output()`](#pake.process.check_output "pake.process.check_output"). Otherwise, None.

`stdout`[¶](#pake.process.CalledProcessException.stdout "Permalink to this definition")

Alias for output, for symmetry with stderr.

`stderr`[¶](#pake.process.CalledProcessException.stderr "Permalink to this definition")

Stderr output of the child process if it was captured by [`pake.process.check\_output()`](#pake.process.check_output "pake.process.check_output"). Otherwise, None.

`filename`[¶](#pake.process.CalledProcessException.filename "Permalink to this definition")

Filename describing the file from which the process call was initiated. (might be None)

`function_name`[¶](#pake.process.CalledProcessException.function_name "Permalink to this definition")

Function name describing the function which initiated the process call. (might be None)

`line_number`[¶](#pake.process.CalledProcessException.line_number "Permalink to this definition")

Line Number describing the line where the process call was initiated. (might be None)

`stdout`

Alias for **output**

*exception* `pake.process.``TimeoutExpired`(*cmd*, *timeout*, *output=None*, *stderr=None*)[[source]](_modules/pake/process.html#TimeoutExpired)[¶](#pake.process.TimeoutExpired "Permalink to this definition")

Bases: [`pake.process.ProcessException`](#pake.process.ProcessException "pake.process.ProcessException")

This exception is raised when the timeout expires while waiting for a child process.

This exception is only raised by process spawning methods in the [`pake.process`](#module-pake.process "pake.process") module.

`cmd`[¶](#pake.process.TimeoutExpired.cmd "Permalink to this definition")

Executed command

`timeout`[¶](#pake.process.TimeoutExpired.timeout "Permalink to this definition")

Timeout in seconds.

`output`[¶](#pake.process.TimeoutExpired.output "Permalink to this definition")

Output of the child process if it was captured by [`pake.process.check\_output()`](#pake.process.check_output "pake.process.check_output"). Otherwise, None.

`stdout`[¶](#pake.process.TimeoutExpired.stdout "Permalink to this definition")

Alias for output, for symmetry with stderr.

`stderr`[¶](#pake.process.TimeoutExpired.stderr "Permalink to this definition")

Stderr output of the child process if it was captured by [`pake.process.check\_output()`](#pake.process.check_output "pake.process.check_output"). Otherwise, None.

`filename`[¶](#pake.process.TimeoutExpired.filename "Permalink to this definition")

Filename describing the file from which the process call was initiated. (might be None)

`function_name`[¶](#pake.process.TimeoutExpired.function_name "Permalink to this definition")

Function name describing the function which initiated the process call. (might be None)

`line_number`[¶](#pake.process.TimeoutExpired.line_number "Permalink to this definition")

Line Number describing the line where the process call was initiated. (might be None)

`pake.process.``call`(*\*args*, *stdin=None*, *stdout=None*, *stderr=None*, *shell=False*, *timeout=None*, *\*\*kwargs*)[[source]](_modules/pake/process.html#call)[¶](#pake.process.call "Permalink to this definition")

Wrapper around `subprocess.call()` which allows the same **\*args** call syntax as [`pake.TaskContext.call()`](#pake.TaskContext.call "pake.TaskContext.call") and friends.

| Parameters: | * **args** – Executable and arguments.

* **stdin** – Stdin to feed to the process.

* **stdout** – File to write stdout to.

* **stderr** – File to write stderr to.

* **shell** – Execute in shell mode.

* **timeout** – Program execution timeout value in seconds.

 |

| Raises: | [`pake.process.TimeoutExpired`](#pake.process.TimeoutExpired "pake.process.TimeoutExpired") If the process does not exit before timeout is up. |

`pake.process.``check_call`(*\*args*, *stdin=None*, *stdout=None*, *stderr=None*, *shell=False*, *timeout=None*, *\*\*kwargs*)[[source]](_modules/pake/process.html#check_call)[¶](#pake.process.check_call "Permalink to this definition")

Wrapper around `subprocess.check\_call()` which allows the same **\*args** call syntax as [`pake.TaskContext.call()`](#pake.TaskContext.call "pake.TaskContext.call") and friends.

| Parameters: | * **args** – Executable and arguments.

* **stdin** – Stdin to feed to the process.

* **stdout** – File to write stdout to.

* **stderr** – File to write stderr to.

* **shell** – Execute in shell mode.

* **timeout** – Program execution timeout value in seconds.

 |

| Raises: | [`pake.process.CalledProcessException`](#pake.process.CalledProcessException "pake.process.CalledProcessException") If the process exits with a non-zero return code. |

| Raises: | [`pake.process.TimeoutExpired`](#pake.process.TimeoutExpired "pake.process.TimeoutExpired") If the process does not exit before timeout is up. |

`pake.process.``check_output`(*\*args*, *stdin=None*, *stderr=None*, *shell=False*, *timeout=None*, *\*\*kwargs*)[[source]](_modules/pake/process.html#check_output)[¶](#pake.process.check_output "Permalink to this definition")

Wrapper around `subprocess.check\_output()` which allows the same **\*args** call syntax as [`pake.TaskContext.call()`](#pake.TaskContext.call "pake.TaskContext.call") and friends.

| Parameters: | * **args** – Executable and arguments.

* **stdin** – Stdin to feed to the process.

* **stderr** – File to write stderr to.

* **shell** – Execute in shell mode.

* **timeout** – Program execution timeout value in seconds.

 |

| Raises: | [`pake.process.CalledProcessException`](#pake.process.CalledProcessException "pake.process.CalledProcessException") If the process exits with a non-zero return code. |

| Raises: | [`pake.process.TimeoutExpired`](#pake.process.TimeoutExpired "pake.process.TimeoutExpired") If the process does not exit before timeout is up. |

#### Module: pake.util[¶](#module-pake.util "Permalink to this headline")

`pake.util.``touch`(*file\_name*, *mode=438*, *exist\_ok=True*)[[source]](_modules/pake/util.html#touch)[¶](#pake.util.touch "Permalink to this definition")

Create a file at this given path. 

If mode is given, it is combined with the process’ umask value to determine the file mode and access flags.

If the file already exists, the function succeeds if **exist\_ok** is true (and its modification time is updated to the current time),

otherwise `FileExistsError` is raised.

| Parameters: | * **file\_name** – The file name.

* **mode** – The mode (octal perms mask) defaults to **0o666**.

* **exist\_ok** – Whether or not it is okay for the file to exist when touched, if not a `FileExistsError` is thrown.

 |

`pake.util.``is_iterable`(*obj*)[[source]](_modules/pake/util.html#is_iterable)[¶](#pake.util.is_iterable "Permalink to this definition")

Test if an object is iterable.

| Parameters: | **obj** – The object to test. |

| Returns: | True if the object is iterable, False otherwise. |

`pake.util.``is_iterable_not_str`(*obj*)[[source]](_modules/pake/util.html#is_iterable_not_str)[¶](#pake.util.is_iterable_not_str "Permalink to this definition")

Test if an object is iterable, and not a string.

| Parameters: | **obj** – The object to test. |

| Returns: | True if the object is an iterable non string, False otherwise. |

`pake.util.``str_is_float`(*value*)[[source]](_modules/pake/util.html#str_is_float)[¶](#pake.util.str_is_float "Permalink to this definition")

Test if a string can be parsed into a float.

| Returns: | True or False |

`pake.util.``str_is_int`(*value*)[[source]](_modules/pake/util.html#str_is_int)[¶](#pake.util.str_is_int "Permalink to this definition")

Test if a string can be parsed into an integer.

| Returns: | True or False |

`pake.util.``flatten_non_str`(*iterable*)[[source]](_modules/pake/util.html#flatten_non_str)[¶](#pake.util.flatten_non_str "Permalink to this definition")

Flatten a nested iterable without affecting strings.

Example:

```

val = list(flatten\_non\_str(['this', ['is', ['an'], 'example']]))

# val == ['this', 'is', 'an', 'example']

```

| Returns: | A generator that iterates over the flattened iterable. |

`pake.util.``handle_shell_args`(*args*)[[source]](_modules/pake/util.html#handle_shell_args)[¶](#pake.util.handle_shell_args "Permalink to this definition")

Handles parsing the **\*args** parameter of [`pake.TaskContext.call()`](#pake.TaskContext.call "pake.TaskContext.call") and [`pake.subpake()`](#pake.subpake "pake.subpake").

It allows shell arguments to be passed as a list object, variadic parameters, or a single string.

Any non-string object you pass that is not an iterable will be stringified.

| Returns: | A list of shell argument strings. |

*class* `pake.util.``CallerDetail`[[source]](_modules/pake/util.html#CallerDetail)[¶](#pake.util.CallerDetail "Permalink to this definition")

`filename`[¶](#pake.util.CallerDetail.filename "Permalink to this definition")

Source file name.

`function_name`[¶](#pake.util.CallerDetail.function_name "Permalink to this definition")

Function call name.

`line_number`[¶](#pake.util.CallerDetail.line_number "Permalink to this definition")

Line number of function call.

`pake.util.``get_pakefile_caller_detail`()[[source]](_modules/pake/util.html#get_pakefile_caller_detail)[¶](#pake.util.get_pakefile_caller_detail "Permalink to this definition")

Get the full pakefile path, called function name, and line number of the first

function call in the current call tree which exists inside of a pakefile.

This function traverses up the stack frame looking for the first occurrence of

a source file with the same path that [`pake.get\_init\_file()`](#pake.get_init_file "pake.get_init_file") returns.

If [`pake.init()`](#pake.init "pake.init") has not been called, this function returns **None**.

| Returns: | A named tuple: [`pake.util.CallerDetail`](#pake.util.CallerDetail "pake.util.CallerDetail") or **None**. |

`pake.util.``parse_define_value`(*value*)[[source]](_modules/pake/util.html#parse_define_value)[¶](#pake.util.parse_define_value "Permalink to this definition")

Used to interpret the value of a define declared on the command line with the **-D/–define** option.

**-D** excepts all forms of python literal as define values.

This function can parse strings, integers, floats, lists, tuples, dictionaries and sets.

‘True’, ‘False’ and ‘None’ values are case insensitive.

Anything that does not start with a python literal quoting character (such as **{** and **[** ) and

is not a True or False value, Integer, or Float, is considered to be a raw string.

| Raises: | `ValueError` if the **value** parameter is **None**, or

if an attempt to parse a complex literal (quoted string, list, set, tuple, or dictionary) fails. |

| Parameters: | **value** – String representing the defines value. |

| Returns: | Python literal representing the defines values. |

`pake.util.``copyfileobj_tee`(*fsrc*, *destinations*, *length=16384*, *readline=False*)[[source]](_modules/pake/util.html#copyfileobj_tee)[¶](#pake.util.copyfileobj_tee "Permalink to this definition")

copy data from file-like object **fsrc** to multiple file like objects.

| Parameters: | * **fsrc** – Source file object.

* **destinations** – List of destination file objects.

* **length** – Read chunk size, default is 16384 bytes.

* **readline** – If **True** readline will be used to read from **fsrc**, the **length**

parameter will be ignored.

 |

`pake.util.``qualified_name`(*object\_instance*)[[source]](_modules/pake/util.html#qualified_name)[¶](#pake.util.qualified_name "Permalink to this definition")

Return the fully qualified type name of an object.

| Parameters: | **object\_instance** – Object instance. |

| Returns: | Fully qualified name string. |

#### Module: pake.conf[¶](#module-pake.conf "Permalink to this headline")

Global configuration module.

`pake.conf.``stdout`[¶](#pake.conf.pake.conf.stdout "Permalink to this definition")

(set-able) Default file object used by pake library calls to print informational output, defaults to **sys.stdout**

This can be set in order to change the default informational output location for the whole library.

`pake.conf.``stderr`[¶](#pake.conf.pake.conf.stderr "Permalink to this definition")

(set-able) Default file object used by pake library calls to print error output, defaults to **sys.stderr**.

This can be set in order to change the default error output location for the whole library.

`pake.conf.``reset`()[[source]](_modules/pake/conf.html#reset)[¶](#pake.conf.reset "Permalink to this definition")

Reset all configuration to its default state.

#### Module: pake.returncodes[¶](#module-pake.returncodes "Permalink to this headline")

Pake return codes.

`pake.returncodes.``SUCCESS`[¶](#pake.returncodes.SUCCESS "Permalink to this definition")

0. Pake ran/exited successfully.

`pake.returncodes.``ERROR`[¶](#pake.returncodes.ERROR "Permalink to this definition")

1. Generic error, good for use with [`pake.terminate()`](#pake.terminate "pake.terminate") (or **exit()** inside tasks)

`pake.returncodes.``PAKEFILE_NOT_FOUND`[¶](#pake.returncodes.PAKEFILE_NOT_FOUND "Permalink to this definition")

2. Pakefile not found in directory, or specified pakefile does not exist.

`pake.returncodes.``BAD_ARGUMENTS`[¶](#pake.returncodes.BAD_ARGUMENTS "Permalink to this definition")

3. Bad combination of command line arguments, or bad arguments in general.

`pake.returncodes.``BAD_DEFINE_VALUE`[¶](#pake.returncodes.BAD_DEFINE_VALUE "Permalink to this definition")

4. Syntax error while parsing a define value from the **-D/–define** option.

`pake.returncodes.``NO_TASKS_DEFINED`[¶](#pake.returncodes.NO_TASKS_DEFINED "Permalink to this definition")

5. No tasks defined in pakefile.

`pake.returncodes.``NO_TASKS_SPECIFIED`[¶](#pake.returncodes.NO_TASKS_SPECIFIED "Permalink to this definition")

6. No tasks specified to run, no default tasks exist.

`pake.returncodes.``TASK_INPUT_NOT_FOUND`[¶](#pake.returncodes.TASK_INPUT_NOT_FOUND "Permalink to this definition")

7. One of task’s input files/directories is missing.

`pake.returncodes.``TASK_OUTPUT_MISSING`[¶](#pake.returncodes.TASK_OUTPUT_MISSING "Permalink to this definition")

8. A task declares input files/directories but no output files/directories.

`pake.returncodes.``UNDEFINED_TASK`[¶](#pake.returncodes.UNDEFINED_TASK "Permalink to this definition")

9. An undefined task was referenced.

`pake.returncodes.``TASK_SUBPROCESS_EXCEPTION`[¶](#pake.returncodes.TASK_SUBPROCESS_EXCEPTION "Permalink to this definition")

10. An unhandled [`pake.TaskSubprocessException`](#pake.TaskSubprocessException "pake.TaskSubprocessException") was raised inside a task.

`pake.returncodes.``SUBPAKE_EXCEPTION`[¶](#pake.returncodes.SUBPAKE_EXCEPTION "Permalink to this definition")

11. An exceptional condition occurred running a subpake script.

Or if a pakefile invoked with [`pake.subpake()`](#pake.subpake "pake.subpake") returns non-zero and the subpake parameter **exit\_on\_error** is set to **True**.

`pake.returncodes.``TASK_EXCEPTION`[¶](#pake.returncodes.TASK_EXCEPTION "Permalink to this definition")

12. An unhandled exception occurred inside a task.

`pake.returncodes.``AGGREGATE_EXCEPTION`[¶](#pake.returncodes.AGGREGATE_EXCEPTION "Permalink to this definition")

13. An aggregate exception was raised from a usage of [`pake.TaskContext.multitask()`](#pake.TaskContext.multitask "pake.TaskContext.multitask")

where the **aggregate\_exceptions** parameter of [`pake.TaskContext.multitask()`](#pake.TaskContext.multitask "pake.TaskContext.multitask")

was set to **True**.

`pake.returncodes.``STDIN_DEFINES_SYNTAX_ERROR`[¶](#pake.returncodes.STDIN_DEFINES_SYNTAX_ERROR "Permalink to this definition")

14. A syntax error was encountered parsing the defines dictionary passed into

**stdin** while using the **–stdin-defines** option.

Guides / Help[¶](#guides-help "Permalink to this headline")

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

### Running Pake[¶](#running-pake "Permalink to this headline")

```

cd your_pakefile_directory

# Run pake with up to 10 tasks running in parallel

pake -j 10

```

pake will look for “pakefile.py” or “pakefile” in the current directory and run it if it exists.

#### Manually specifying pakefile(s)[¶](#manually-specifying-pakefile-s "Permalink to this headline")

You can specify one or more files to run with **-f/–file**.

The switch does not have multiple arguments, but it can be used

more than once to specify multiple files.

If you specify more than one pakefile with a **–jobs** parameter greater than 1,

the specified pakefiles will still be run synchronously (one after another). The tasks

inside each pakefile will be ran in parallel however.

For example:

```

pake -f pakefile.py foo

pake -f your_pakefile_1.py -f your_pakefile_2.py foo

```

#### Executing in another directory[¶](#executing-in-another-directory "Permalink to this headline")

The **-C** or **–directory** option can be used to execute pake in an arbitrary directory.

If you do not specify a file with **-f** or **–file**, then a pakefile must exist in the given directory:

Example:

```

# Pake will find the 'pakefile.py' in 'build\_directory'

# then change directories into it and start running

pake -C build_directory my_task

```

You can also tell pake to run a pakefile (or multiple pakefiles) in a different working directory.

Example:

```

# Pake will run 'my\_pakefile.py' with a working directory of 'build\_directory'

pake -f my_pakefile.py -C build_directory my_task

# Pake will run all the given pakefiles with a working directory of 'build\_directory'

pake -f pakefile1.py -f pakefile2.py -f pakefile3.py -C build_directory my_task

```

#### Running multiple tasks[¶](#running-multiple-tasks "Permalink to this headline")

You can specify multiple tasks, but do not rely on unrelated tasks being executed in any

specific order because they won’t be. If there is a specific order you need your tasks to

execute in, the one that comes first should be declared a dependency of the one that comes

second, then the second task should be specified to run.

When running parallel builds, leaf dependencies will start executing pretty much

simultaneously, and non related tasks that have a dependency chain may execute

in parallel.

In general, direct dependencies of a task have no defined order of execution when

there is more than one of them.

`pake task unrelated\_task order\_independent\_task`

#### Specifying define values[¶](#specifying-define-values "Permalink to this headline")

The **-D/–define** option is used to specify defines on the command line that can be retrieved

with the [`pake.Pake.get\_define()`](index.html#pake.Pake.get_define "pake.Pake.get_define") method, or **\_\_getitem\_\_** indexer on the [`pake.Pake`](index.html#pake.Pake "pake.Pake")

object (which is returned by [`pake.init()`](index.html#pake.init "pake.init")).

Define values are parsed partially with the built in `ast` module, the only caveat is that the

values **True**, **False** and **None** are case insensitive.

Defines which are specified without a value, default to the value of **True**.

Basic Example:

```

pake -D IM\_TRUE=True \

     -D IM\_TRUE\_TOO=true \

     -D IM\_NONE=none \

     -D NO_VALUE \

     -D IM\_STRING="Hello" \

     -D IM\_INT=1 \

     -D IM\_FLOAT=0.5

```

Retrieval:

```

import pake

pk = pake.init()

im\_true = pk.get\_define('IM\_TRUE')

im\_true\_too = pk.get\_define('IM\_TRUE\_TOO')

im\_none = pk.get\_define('IM\_NONE')

no\_value = pk.get\_define('NO\_VALUE')

im\_string = pk.get\_define('IM\_STRING')

im\_int = pk.get\_define('IM\_INT')

im\_float = pk.get\_define('IM\_FLOAT')

print(type(im\_true)) # -> <class 'bool'>

print(im\_true) # -> True

print(type(im\_true\_too)) # -> <class 'bool'>

print(im\_true\_too) # -> True

print(type(im\_none)) # -> <class 'NoneType'>

print(im\_none) # -> None

print(type(no\_value)) # -> <class 'bool'>

print(no\_value) # -> True

print(type(im\_string)) # -> <class 'str'>

print(im\_string) # -> Hello

print(type(im\_int)) # -> <class 'int'>

print(im\_int) # -> 1

print(type(im\_float)) # -> <class 'float'>

print(im\_float) # -> 0.5

pk.terminate(0)

```

You can pass complex python literals such as lists, sets, tuples, dictionaries, etc.. as a define value.

pake will recognize and fully deserialize them into the correct type.

Complex Types Example:

```

pake -D IM\_A\_DICT="{'im': 'dict'}" \

     -D IM\_A\_SET="{'im', 'set'}" \

     -D IM\_A\_LIST="['im', 'list']" \

     -D IM\_A\_TUPLE="('im', 'tuple')"

```

Retrieval:

```

import pake

pk = pake.init()

im\_a\_dict = pk.get\_define('IM\_A\_DICT')

im\_a\_set = pk.get\_define('IM\_A\_SET')

im\_a\_list = pk.get\_define('IM\_A\_LIST')

im\_a\_tuple = pk.get\_define('IM\_A\_TUPLE')

print(type(im\_a\_dict)) # -> <class 'dict'>

print(im\_a\_dict) # -> {'im': 'dict'}

print(type(im\_a\_set)) # -> <class 'set'>

print(im\_a\_set) # -> {'im', 'set'}

print(type(im\_a\_list)) # -> <class 'list'>

print(im\_a\_list) # -> ['im': 'list']

print(type(im\_a\_tuple)) # -> <class 'tuple'>

print(im\_a\_tuple) # -> ('im': 'tuple')

pk.terminate(0)

```

#### Reading defines from STDIN[¶](#reading-defines-from-stdin "Permalink to this headline")

The **–stdin-defines** option allows you to pipe defines into pake in the form of a python dictionary.

Any defines that are set this way can be overwritten by defines set on the command line using **-D/–define**

The dictionary that you pipe in is parsed into a python literal using the built in `ast` module,

so you can use complex types such as lists, sets, tuples, dictionaries ect.. as the value for your defines.

Pake reads the defines from **stdin** on the first call to [`pake.init()`](index.html#pake.init "pake.init") and caches them in memory.

Later calls to **init** will read the specified defines back from cache and apply them to a newly created

[`pake.Pake`](index.html#pake.Pake "pake.Pake") instance.

Calls to [`pake.de\_init()`](index.html#pake.de_init "pake.de_init") will not clear cached defines read from **stdin**.

Example Pakefile:

```

import pake

pk = pake.init()

a = pk['MY\_DEFINE']

b = pk['MY\_DEFINE\_2']

print(a)

print(b)

pk.terminate(0)

```

Example Commands:

```

# Pipe in two defines, MY\_DEFINE=True and MY\_DEFINE\_2=42

echo "{'MY\_DEFINE': True, 'MY\_DEFINE\_2': 42}" | pake --stdin-defines

# Prints:

True

42

# Overwrite the value of MY\_DEFINE\_2 that was piped in, using the -D/--define option

# it will have a value of False instead of 42

echo "{'MY\_DEFINE': True, 'MY\_DEFINE\_2': 42}" | pake --stdin-defines -D MY\_DEFINE\_2=False

# Prints:

True

False

```

#### Environmental variables[¶](#environmental-variables "Permalink to this headline")

Pake currently recognizes only one environmental variable named `PAKE\_SYNC\_OUTPUT`.

This variable corresponds to the command line option **–sync-output**.

Using the **–sync-output** option will override the environmental variable however.

Pake will use the value from the command line option instead of the value in the environment.

When this environmental variable and **–sync-output** are not defined/specified,

the default value pake uses is **–sync-output True**.

[`pake.init()`](index.html#pake.init "pake.init") has an argument named **sync\_output** that can also be used to

permanently override both the **–sync-output** switch and the `PAKE\_SYNC\_OUTPUT`

environmental variable from inside of a pakefile.

The **–sync-output** option controls whether pake tries to synchronize task output

by queueing it when running with more than one job.

**–sync-output False** causes [`pake.TaskContext.io\_lock`](index.html#pake.TaskContext.io_lock "pake.TaskContext.io_lock") to yield a lock

object which actually does nothing when it is acquired, and it also forces pake

to write all run output to [`pake.Pake.stdout`](index.html#pake.Pake.stdout "pake.Pake.stdout") instead of task output

queues, even when running tasks concurrently.

The output synchronization setting is inherited by all [`pake.subpake()`](index.html#pake.subpake "pake.subpake")

and `pake.Pake.subpake()` invocations.

You can stop this inheritance by manually passing a different value for **–sync-output**

as a shell argument when using one of the **subpake** functions. The new value will

be inherited by the pakefile you invoked with **subpake** and all of its children.

#### Command line options[¶](#command-line-options "Permalink to this headline")

```

usage: pake [-h] [-v] [-D DEFINE] [--stdin-defines] [-j JOBS] [-n]

                [-C DIRECTORY] [-t] [-ti] [--sync-output {True, False, 1, 0}]

                [-f FILE]

                [tasks [tasks ...]]

    positional arguments:

      tasks                 Build tasks.

    optional arguments:

      -h, --help            show this help message and exit

      -v, --version         show program's version number and exit

      -D DEFINE, --define DEFINE

                            Add defined value.

      --stdin-defines       Read defines from a Python Dictionary piped into

                            stdin. Defines read with this option can be

                            overwritten by defines specified on the command line

                            with -D/--define.

      -j JOBS, --jobs JOBS  Max number of parallel jobs. Using this option enables

                            unrelated tasks to run in parallel with a max of N

                            tasks running at a time.

      -n, --dry-run         Use to preform a dry run, lists all tasks that will be

                            executed in the next actual invocation.

      -C DIRECTORY, --directory DIRECTORY

                            Change directory before executing.

      -t, --show-tasks      List all task names.

      -ti, --show-task-info

                            List all tasks along side their doc string. Only tasks

                            with doc strings present will be shown.

      --sync-output {True, False, 1, 0}

                            Tell pake whether it should synchronize task output

                            when running with multiple jobs. Console output can

                            get scrambled under the right circumstances with this

                            turned off, but pake will run slightly faster. This

                            option will override any value in the PAKE_SYNC_OUTPUT

                            environmental variable, and is inherited by subpake

                            invocations unless the argument is re-passed with a

                            different value or overridden in pake.init.

      -f FILE, --file FILE  Pakefile path(s). This switch can be used more than

                            once, all specified pakefiles will be executed in

                            order with the current directory as the working

                            directory (unless -C is specified).

```

#### Return codes[¶](#return-codes "Permalink to this headline")

See the [`pake.returncodes`](index.html#module-pake.returncodes "pake.returncodes") module, pake’s return codes are defined

as constants and each is described in detail in the module documentation.

### Writing Basic Tasks[¶](#writing-basic-tasks "Permalink to this headline")

Additional information about change detection is available in the form of examples in

the documentation for the [`pake.Pake.task()`](index.html#pake.Pake.task "pake.Pake.task") function decorator.

Pake is capable of handling change detection against both files and directories, and the two can be used

as inputs or outputs interchangeably and in combination.

**Note:**

> 

> Each registered task receives a [`pake.TaskContext`](index.html#pake.TaskContext "pake.TaskContext") instance as a single argument when run.

> In this example the argument is named **ctx**, but it can be named however you like.

> It is not an error to leave this argument undefined, but you will most likely be using it.

Example:

```

import pake

# Tasks are registered the the pake.Pake object

# returned by pake's initialization call, using the task decorator.

pk = pake.init()

# Try to grab a command line define.

# In particular the value of -D CC=..

# CC will default to 'gcc' in this case if

# it was not specified.

CC = pk.get\_define('CC', 'gcc')

# you can also use the syntax: pk["CC"] to

# attempt to get the defines value, if it is not

# defined then it will return None.

# ===

# If you just have a single input/output, there is no

# need to pass a list to the tasks inputs/outputs

@pk.task(i='foo/foo.c', o='foo/foo.o')

def foo(ctx):

    # Execute a program (gcc) and print its stdout/stderr to the tasks output.

    # ctx.call can be passed a command line as variadic arguments, an iterable, or

    # as a string. It will automatically flatten out non string iterables in your variadic

    # arguments or iterable object, so you can pass an iterable such as ctx.inputs

    # as part of your full command line invocation instead of trying to create the command

    # line by concatenating lists or using the indexer on ctx.inputs/ctx.outputs

    ctx.call(CC, '-c', ctx.inputs, '-o', ctx.outputs)

# Pake can handle file change detection with multiple inputs

# and outputs. If the amount of inputs is different from

# the amount of outputs, the task is considered to be out

# of date if any input file is newer than any output file.

# When the amount of inputs is equal to the amount of outputs,

# pake will compare each input to its corresponding output

# and collect out of date input/outputs into ctx.outdated\_inputs

# and ctx.outdated\_outputs respectively. ctx.outdated\_pairs

# can be used to get a generator over (input, output) pairs,

# it is shorthand for zip(ctx.outdated\_inputs, ctx.outdated\_outputs)

@pk.task(i=pake.glob('bar/\*.c'), o=pake.pattern('bar/%.o'))

def bar(ctx):

    # zip together the outdated inputs and outputs, since they

    # correspond to each other, this iterates of a sequence of python

    # tuple objects in the form (input, output)

    for i, o in ctx.outdated\_pairs:

        ctx.call(CC, '-c', i, '-o', o)

# This task depends on the 'foo' and 'bar' tasks, as

# specified with the decorators leading parameters.

# It outputs 'bin/baz' by taking the input 'main.c'

# and linking it to the object files produced in the other tasks.

@pk.task(foo, bar, o='bin/baz', i='main.c')

def baz(ctx):

    """Use this to build baz"""

    # Documentation strings can be viewed by running 'pake -ti' in

    # the directory the pakefile exists in, it will list all documented

    # tasks with their python doc strings.

    # The pake.FileHelper class can be used to preform basic file

    # system operations while printing information about the operations

    # it has completed to the tasks output.

    file\_helper = pake.FileHelper(ctx)

    # Create a bin directory, this won't complain if it exists already

    file\_helper.makedirs('bin')

    # ctx.dependency\_outputs contains a list of all outputs that this

    # tasks immediate dependencies produce

    ctx.call(CC, '-o', ctx.outputs, ctx.inputs, ctx.dependency\_outputs)

@pk.task

def clean(ctx):

    """Clean binaries"""

    file\_helper = pake.FileHelper(ctx)

    # Clean up using the FileHelper object.

    # Remove the bin directory, this wont complain if 'bin'

    # does not exist.

    file\_helper.rmtree('bin')

    # Glob remove object files from the foo and bar directories

    file\_helper.glob\_remove('foo/\*.o')

    file\_helper.glob\_remove('bar/\*.o')

# Run pake; The default task that will be executed when

# none are specified on the command line will be 'baz' in

# this case.

# The tasks parameter is optional, but if it is not specified

# here, you will be required to specify a task or tasks on the

# command line.

pake.run(pk, tasks=baz)

```

Output from command `pake`:

```

===== Executing task: "bar"

gcc -c bar/bar.c -o bar/bar.o

===== Executing task: "foo"

gcc -c foo/foo.c -o foo/foo.o

===== Executing task: "baz"

Created Directory(s): "bin"

gcc -o bin/baz main.c foo/foo.o bar/bar.o

```

Output from command `pake clean`:

```

===== Executing task: "clean"

Removed Directory(s): "bin"

Glob Removed Files: "foo/\*.o"

Glob Removed Files: "bar/\*.o"

```

### Input/Output Name Generators & Globbing[¶](#input-output-name-generators-globbing "Permalink to this headline")

Pake can accept callables as task inputs, this is how [`pake.glob()`](index.html#pake.glob "pake.glob") and [`pake.pattern()`](index.html#pake.pattern "pake.pattern") are

implemented under the hood. They both take the pattern you give them and return a new function, which

generates an iterable of input/output file names.

Input and output generators will work with both the [`pake.Pake.task()`](index.html#pake.Pake.task "pake.Pake.task") function

decorator, as well as the [`pake.Pake.add\_task()`](index.html#pake.Pake.add_task "pake.Pake.add_task") method.

The evaluation of input/output generators is deferred until the task runs.

The reasoning behind this is that input generators like [`pake.glob()`](index.html#pake.glob "pake.glob") can have access

to artifacts created by a tasks dependencies when evaluation happens just before the task runs.

Because all the dependencies of the task will have been built by that point.

The outputs of input/output generators are passed through pake’s change detection algorithm

once the values have been retrieved from them, to determine if the task should run or not.

[`pake.glob()`](index.html#pake.glob "pake.glob") and [`pake.pattern()`](index.html#pake.pattern "pake.pattern") are implemented like this:

```

def glob(pattern):

    def input\_generator():

        # Input generators can return generators or lists.

        # As long as whatever the input generator returns

        # is an iterable object that produces file/directory

        # names as strings, it will work.

        # You can also use 'yield' syntax in your input

        # generator function, since the result is an iterable

        return glob.iglob(expression, recursive=True)

    return input\_generator

# pake.pattern generates a callable that you can

# pass as a pake output, into the "i" parameter

# of the task decorator, or even to the "inputs"

# parameter of pk.add\_task

def pattern(file\_pattern):

    def output\_generator(inputs):

        # output generators receive the inputs

        # provided to the task, even ones that

        # were generated by an input generator

        # inputs is always a flat list, and a copy

        # inputs is safe to mutate if you want

        # As with input generators, you can return

        # any type of iterable that produces file/directory

        # names as strings and it will work.

        for inp in inputs:

            dir = os.path.dirname(inp)

            name, ext = os.path.splitext(os.path.basename(inp))

            yield file\_pattern.replace('{dir}', dir).replace('%', name).replace('{ext}', ext)

    return output\_generator

```

[`pake.glob()`](index.html#pake.glob "pake.glob") and [`pake.pattern()`](index.html#pake.pattern "pake.pattern") are used like this:

```

import pake

pk = pake.init()

@pk.task(i=pake.glob('src/\*.c'), o=pake.pattern('bin/%.o'))

def build\_c(ctx):

    # Your going to have an equal number of

    # inputs and outputs in this task, because

    # the output names are being generated from

    # the input names.

    for i, o in ctx.outdated\_pairs:

        ctx.call('gcc', '-c', i, '-o', o)

pake.run(pk, tasks=build\_c)

```

#### Multiple input generators at once[¶](#multiple-input-generators-at-once "Permalink to this headline")

You can place input generators into a list or any other iterable such as a tuple,

pake will combine the values that they generate into one flat list. You can also

use input generator callables along side plain old file or directory references.

Multiple output generators are not allowed however, you may only ever use

one output generator callable at a time, and you cannot use output generators

along side regular file/directory names.

Output generators process all of the tasks input file/directory names, and

are expected to return all of the tasks outputs.

Multiple Input Generator Example:

```

import pake

pk = pake.init()

# This task collects .c files from two directories

# ('src\_one' and 'src\_two'), and compiles them all

# together with 'main.c' (which exists in the current directory).

# This task produces an executable file called 'main'

@pk.task(i=[pake.glob('src\_one/\*.c'), pake.glob('src\_two/\*.c'), 'main.c'], o='main')

def build\_c(ctx):

    ctx.call('gcc', ctx.inputs, '-o', ctx.outputs)

pake.run(pk, tasks=build\_c)

```

Example with an output generator:

```

import pake

pk = pake.init()

# This task collects .c files from two directories

# ('src\_one' and 'src\_two'), and compiles object files

# that are created in each source directory along side

# the source file.

@pk.task(i=[pake.glob('src\_one/\*.c'), pake.glob('src\_two/\*.c')], o=pake.pattern('{dir}/%.o'))

def build\_c(ctx):

    # Your going to have an equal number of

    # inputs and outputs in this task, because

    # the output names are being generated from

    # the input names.

    for i, o in ctx.outdated\_pairs:

        ctx.call('gcc', '-c', i, '-o', o)

pake.run(pk, tasks=build\_c)

```

### Change Detection Against Directories[¶](#change-detection-against-directories "Permalink to this headline")

Change detection in pake works against directories in the same way it works against files.

Files can be compared against directories (and vice versa) when providing inputs and

outputs to a task, directories can also be compared against each other if needed.

Basically, a directory name can be used in place of a file name anywhere in

a tasks input(s) and output(s) parameters.

Example:

```

import pake

import glob

import pathlib

pk = pake.init()

# Whenever the modification time of 'my\_directory' or

# 'my\_directory\_2' is more recent than the file 'my\_big.png',

# this task will run.

@pk.task(i=['my\_directory', 'my\_directory\_2'], o='my\_big.png')

def concatenate\_pngs(ctx):

   png\_files = []

   for d in ctx.inputs:

       # Need to collect the files in the directories yourself

       png\_files += pathlib.Path(d).glob('\*.png')

   # Concatenate with ImageMagick's convert command

   ctx.call('convert', png\_files, '-append', ctx.outputs)

pake.run(pk, tasks=concatenate\_pngs)

```

### Exiting Pakefiles Gracefully[¶](#exiting-pakefiles-gracefully "Permalink to this headline")

[`pake.terminate()`](index.html#pake.terminate "pake.terminate") can be used to gracefully exit a pakefile from anywhere.

You can also use [`pake.Pake.terminate()`](index.html#pake.Pake.terminate "pake.Pake.terminate") on the pake context returned by [`pake.init()`](index.html#pake.init "pake.init").

[`pake.Pake.terminate()`](index.html#pake.Pake.terminate "pake.Pake.terminate") is just a shortcut for calling [`pake.terminate()`](index.html#pake.terminate "pake.terminate") with the first argument filled out.

These methods are for exiting pake with a given return code after it is initialized, they ensure

the proper ‘leaving directory / exit subpake` messages are sent to pake’s output if needed upon exit, and

help keep logged output consistent.

You should use these functions instead of **exit** when handling error conditions

that occur outside of pake tasks before [`pake.run()`](index.html#pake.run "pake.run") is called.

It is optional to use [`pake.terminate()`](index.html#pake.terminate "pake.terminate") inside tasks, **exit** will always

work inside tasks but [`pake.terminate()`](index.html#pake.terminate "pake.terminate") may provide additional functionality

in the future.

Example Use Case:

```

import os

import pake

from pake import returncodes

pk = pake.init()

# Say you need to wimp out of a build for some reason

# But not inside of a task. pake.terminate will make sure the

# 'leaving directory/exiting subpake' message is printed

# if it needs to be.

if os.name == 'nt':

   pk.print('You really thought you could '

            'build my software on windows? nope!')

   pake.terminate(pk, returncodes.ERROR)

   # or

   # pk.terminate(returncodes.ERROR)

# Define some tasks...

@pk.task

def build(ctx):

    # You can use pake.terminate() inside of a task as well as exit()

    # pake.terminate() may offer more functionality than a raw exit()

    # in the future, however exit() will always work too.

    something\_bad\_happened = True

    if something\_bad\_happened:

        pake.terminate(pk, returncodes.ERROR)

        # Or:

        # pk.terminate(returncodes.ERROR)

pake.run(pk, tasks=build)

# If you were to use pk.run, a TaskExitException would be thrown

# the inner exception (err.exception) would be set to

# pake.TerminateException

# try:

# pk.run(tasks=test)

# except pake.TaskExitException as err:

# print('\n' + str(err) + '\n')

#

# # print to pake.conf.stderr by default

# # file parameter can be used to change that

# err.print\_traceback()

```

#### Calls To exit() inside tasks[¶](#calls-to-exit-inside-tasks "Permalink to this headline")

You can also exit pake with a specific return code when inside a task by simply calling **exit**.

**exit** inside of a task is considered a global exit, even when a task is on another thread due to

pake’s **–jobs** parameter being greater than 1. The return code passed to **exit** inside the task

will become the return code for command line call to pake.

**exit** will always work inside of a task and cause a graceful exit, however [`pake.terminate()`](index.html#pake.terminate "pake.terminate")

may offer more functionality than **exit** sometime in the future.

If you exit with [`pake.returncodes.SUCCESS`](index.html#pake.returncodes.SUCCESS "pake.returncodes.SUCCESS"), no stack trace for the exit call will be printed.

Pake handles calls to **exit** in the same manner as it handles exceptions, although this condition is

instead signified by a [`pake.TaskExitException`](index.html#pake.TaskExitException "pake.TaskExitException") from [`pake.Pake.run()`](index.html#pake.Pake.run "pake.Pake.run") and the message

sent to pake’s output is slightly different.

The behavior when running parallel pake is the same as when a normal exception is thrown.

Example:

```

import pake

from pake import returncodes

pk = pake.init()

@pk.task

def test(ctx):

    ctx.print('hello world')

    # We could also use anything other than 0 to signify an error.

    # returncodes.SUCCESS and returncodes.ERROR will always be 0 and 1.

    exit(returncodes.ERROR)

pake.run(pk, tasks=test)

# If you were to use pk.run, a TaskExitException would be thrown

# try:

# pk.run(tasks=test)

# except pake.TaskExitException as err:

# print('\n' + str(err) + '\n')

#

# # print to pake.conf.stderr by default

# # file parameter can be used to change that

# err.print\_traceback()

```

Yields Output:

```

===== Executing Task: "test"

hello world

Exit exception "SystemExit" with return-code(1) was raised in task "test".

Traceback (most recent call last):

  File "{PAKE\_INSTALL\_PATH}/pake/pake.py", line 1316, in func_wrapper

    return func(*args, **kwargs)

  File "{FULL\_PAKEFILE\_DIR\_PATH}/pakefile.py", line 12, in test

    exit(returncodes.ERROR)

  File "{PYTHON\_INSTALL\_PATH}/lib/\_sitebuiltins.py", line 26, in __call__

    raise SystemExit(code)

SystemExit: 1

```

#### Stack traces from exit/terminate in tasks[¶](#stack-traces-from-exit-terminate-in-tasks "Permalink to this headline")

Calls to **exit()**, [`pake.terminate()`](index.html#pake.terminate "pake.terminate"), or [`pake.Pake.terminate()`](index.html#pake.Pake.terminate "pake.Pake.terminate") with non-zero return codes

will result in a stack trace being printed with information about the location of the exit or terminate call.

This is not the case if you call **exit()** or pake’s terminate functions with a return code of zero,

there will be no stack trace or any information printed if the return code indicates success.

Example **exit(1)** stack trace:

```

import pake

from pake import returncodes

pk = pake.init()

@pk.task

def build(ctx):

    exit(returncodes.ERROR)

pake.run(pk, tasks=build)

```

Yields Output:

```

===== Executing Task: "build"

Exit exception "SystemExit" with return-code(1) was raised in task "build".

Traceback (most recent call last):

  File "{PAKE\_INSTALL\_PATH}/pake/pake.py", line 1504, in func_wrapper

    return func(*args, **kwargs)

  File "{FULL\_PAKEFILE\_DIR\_PATH}/pakefile.py", line 9, in build

    exit(returncodes.ERROR)

  File "{PYTHON\_INSTALL\_PATH}/lib/\_sitebuiltins.py", line 26, in __call__

    raise SystemExit(code)

SystemExit: 1

```

Example **terminate(1)** stack trace:

```

import pake

from pake import returncodes

pk = pake.init()

@pk.task

def build(ctx):

    pk.terminate(returncodes.ERROR)

pake.run(pk, tasks=build)

```

Yields Output:

```

===== Executing Task: "build"

Exit exception "pake.program.TerminateException" with return-code(1) was raised in task "build".

Traceback (most recent call last):

  File "{PAKE\_INSTALL\_PATH}/pake/pake.py", line 1504, in func_wrapper

    return func(*args, **kwargs)

  File "{FULL\_PAKEFILE\_DIR\_PATH}/pakefile.py", line 9, in build

    pk.terminate(returncodes.ERROR)

  File "{PAKE\_INSTALL\_PATH}/pake/pake.py", line 1027, in terminate

    pake.terminate(self, return\_code=return_code)

  File "{PAKE\_INSTALL\_PATH}/pake/program.py", line 614, in terminate

    m_exit(return_code)

  File "{PAKE\_INSTALL\_PATH}/pake/program.py", line 605, in m_exit

    raise TerminateException(code)

pake.program.TerminateException: 1

```

### Adding Tasks Programmatically[¶](#adding-tasks-programmatically "Permalink to this headline")

Pake tasks may be programmatically added using the [`pake.Pake.add\_task()`](index.html#pake.Pake.add_task "pake.Pake.add_task") method of the pake instance.

When adding tasks programmatically, you may specify a callable class instance or a function as your task entry point.

Basic C to Object Compilation Task Example:

```

import pake

pk = pake.init()

def compile\_c(ctx):

   for i, o in ctx.outdated\_pairs:

       ctx.call(['gcc', '-c', i, '-o', o])

# The task name may differ from the function name.

pk.add\_task('compile\_c\_to\_objects', compile\_c,

           inputs=pake.glob('src/\*.c'),

           outputs=pake.pattern('obj/%.o'))

pake.run(pk, tasks='compile\_c\_to\_objects')

# Or:

# pake.run(pk, tasks=compile\_c)

```

Multiple Dependencies:

```

import pake

pk = pake.init()

@pk.task

def task\_a():

    pass

@pk.task

def task\_b():

    pass

def do\_both():

    pass

# The dependencies parameter will accept a single task reference

# as well as a list of task references

pk.add\_task('do\_both', do\_both, dependencies=[task\_a, 'task\_b'])

pake.run(pk, tasks=do\_both)

```

Callable Class Example:

```

import pake

pk = pake.init()

class MessagePrinter:

   """Task documentation goes here."""

   def \_\_init\_\_(self, message):

       self.\_message = message

   def \_\_call\_\_(self, ctx):

       ctx.print(self.\_message)

pk.add\_task('task\_a', MessagePrinter('Hello World!'))

instance\_a = MessagePrinter('hello world again')

# Can refer to the dependency by name, since we did not save a reference.

pk.add\_task('task\_b', instance\_a, dependencies='task\_a')

instance\_b = MessagePrinter('Goodbye!')

# Can also refer to the dependency by instance.

pk.add\_task('task\_c', instance\_b, dependencies=instance\_a)

pake.run(pk, tasks='task\_c')

# Or:

# pake.run(pk, tasks=instance\_b)

```

### Exceptions Inside Tasks[¶](#exceptions-inside-tasks "Permalink to this headline")

Pake handles most exceptions occuring inside a task by wrapping them in a [`pake.TaskException`](index.html#pake.TaskException "pake.TaskException")

and throwing them from [`pake.Pake.run()`](index.html#pake.Pake.run "pake.Pake.run").

[`pake.run()`](index.html#pake.run "pake.run") handles all of the exceptions from [`pake.Pake.run()`](index.html#pake.Pake.run "pake.Pake.run") and prints the exception

information to `pake.conf.stderr` in a way that is useful to the user/developer.

Example:

```

import pake

pk = pake.init()

@pk.task

def test(ctx):

    ctx.print('hello world')

    raise Exception('Some Exception')

pake.run(pk, tasks=test)

# If you were to use pk.run, a TaskException would be thrown

# try:

# pk.run(tasks=test)

# except pake.TaskException as err:

# print('\n'+str(err)+'\n')

#

# # print to pake.conf.stderr by default

# # file parameter can be used to change that

# err.print\_traceback()

```

Yields Output:

```

===== Executing Task: "test"

hello world

Exception "Exception" was raised within task "test".

Traceback (most recent call last):

  File "{PAKE\_INSTALL\_PATH}/pake/pake.py", line 1316, in func_wrapper

    return func(*args, **kwargs)

  File "{FULL\_PAKEFILE\_DIR\_PATH}/pakefile.py", line 8, in test

    raise Exception('Some Exception')

Exception: Some Exception

```

When an exception is thrown inside a task, the fully qualified exception name and the task it

occurred in will be mentioned at the very end of pake’s output. That information is followed

by a stack trace for the raised exception.

When running with multiple jobs, pake will stop as soon as possible. Independent tasks that were

running in the background when the exception occurred will finish, and then the information for the

encountered exception will be printed at the very end of pake’s output.

#### pake.TaskSubprocessException[¶](#pake-tasksubprocessexception "Permalink to this headline")

Special error reporting is implemented for [`pake.TaskSubprocessException`](index.html#pake.TaskSubprocessException "pake.TaskSubprocessException"), which is

raised from [`pake.TaskContext.call`](index.html#pake.TaskContext.call "pake.TaskContext.call"), [`pake.TaskContext.check\_call`](index.html#pake.TaskContext.check_call "pake.TaskContext.check_call"), and

[`pake.TaskContext.check\_output`](index.html#pake.TaskContext.check_output "pake.TaskContext.check_output").

When a process called through one of these process spawning methods returns with a non-zero return code,

a [`pake.TaskSubprocessException`](index.html#pake.TaskSubprocessException "pake.TaskSubprocessException") is raised by default. That will always be true unless you have

supplied **ignore\_errors=True** as an argument to these functions.

This exception derives from [`pake.process.StreamingSubprocessException`](index.html#pake.process.StreamingSubprocessException "pake.process.StreamingSubprocessException"), an exception

base class which incrementally reads process output that has been buffered to disk when reporting

error information. Buffering the output to disk and reading it back incrementally helps keep huge

amounts of process output from crashing pake.

The reported exception information will contain the full path to your pakefile, the name of the process

spawning function, and the line number where it was called. All of this will be at the very top of the

error message.

All output from the failed command will be mentioned at the bottom in a block surrounded by brackets,

which is labeled with **“Command Output: “**

Example:

```

import pake

pk = pake.init()

@pk.task

def test(ctx):

    # pake.TaskSubprocessException is raised because

    # which cannot find the given command and returns non-zero

    # silent is specified, which means the process will not

    # send any output to the task IO queue, but the command

    # will still be printed

    ctx.call('which', "i-dont-exist", silent=True)

pake.run(pk, tasks=test)

```

Yields Output:

```

===== Executing Task: "test"

which i-dont-exist

pake.pake.TaskSubprocessException(

        filename="{FULL\_PAKEFILE\_DIR\_PATH}/pakefile.py",

        function\_name="call",

        line\_number=9

)

Message: A subprocess spawned by a task exited with a non-zero return code.

The following command exited with return code: 1

which i-dont-exist

Command Output: {

which: no i-dont-exist in ({EVERY_DIRECTORY_IN_YOUR_ENV_PATH_VAR})

}

```

#### pake.SubpakeException[¶](#pake-subpakeexception "Permalink to this headline")

[`pake.SubpakeException`](index.html#pake.SubpakeException "pake.SubpakeException") is derived from [`pake.process.StreamingSubprocessException`](index.html#pake.process.StreamingSubprocessException "pake.process.StreamingSubprocessException")

just like [`pake.TaskSubprocessException`](index.html#pake.TaskSubprocessException "pake.TaskSubprocessException"), and produces similar error information when raised

inside a task.

Example: `subfolder/pakefile.py`

```

import pake

pk = pake.init()

@pk.task

def sub\_test(ctx):

    raise Exception('Test Exception')

pake.run(pk, tasks=sub\_test)

```

Example: `pakefile.py`

```

import pake

pk = pake.init()

@pk.task

def test(ctx):

    # pake.SubpakeException is raised because

    # 'subfolder/pakefile.py' raises an exception inside a task

    # and returns with a non-zero exit code.

    # Silent prevents the pakefiles output from being printed

    # to the task IO queue, keeping the output short for this example

    ctx.subpake('subfolder/pakefile.py', silent=True)

pake.run(pk, tasks=test)

```

Yields Output:

```

===== Executing Task: "test"

pake.subpake.SubpakeException(

        filename="{REST\_OF\_FULL\_PATH}/pakefile.py",

        function\_name="subpake",

        line\_number=13

)

Message: A pakefile invoked by pake.subpake exited with a non-zero return code.

The following command exited with return code: 13

{PYTHON_INSTALL_DIR}/python3 subfolder/pakefile.py --_subpake_depth 1 --stdin-defines --directory {REST_OF_FULL_PATH}/subfolder

Command Output: {

*** enter subpake[1]:

pake[1]: Entering Directory "{REST\_OF\_FULL\_PATH}/subfolder"

===== Executing Task: "sub\_test"

Exception "Exception" was called within task "sub\_test".

Traceback (most recent call last):

  File "{PAKE\_INSTALL\_DIRECTORY}/pake/pake.py", line 1323, in func_wrapper

    return func(*args, **kwargs)

  File "subfolder/pakefile.py", line 7, in sub_test

Exception: Test Exception

pake[1]: Exiting Directory "{REST\_OF\_FULL\_PATH}/subfolder"

*** exit subpake[1]:

}

```

### Concurrency Inside Tasks[¶](#concurrency-inside-tasks "Permalink to this headline")

Work can be submitted to the threadpool pake is running its tasks on to achieve a

predictable level of concurrency for sub tasks that is limited by the **–jobs** command line argument,

or the **jobs** parameter of [`pake.run()`](index.html#pake.run "pake.run") and [`pake.Pake.run()`](index.html#pake.Pake.run "pake.Pake.run").

This is done using the [`pake.MultitaskContext`](index.html#pake.MultitaskContext "pake.MultitaskContext") returned by [`pake.TaskContext.multitask()`](index.html#pake.TaskContext.multitask "pake.TaskContext.multitask").

[`pake.MultitaskContext`](index.html#pake.MultitaskContext "pake.MultitaskContext") implements an **Executor** with an identical interface to

`concurrent.futures.ThreadPoolExecutor` from the built-in python module `concurrent.futures`.

Submitting work to a [`pake.MultitaskContext`](index.html#pake.MultitaskContext "pake.MultitaskContext") causes your work to be added to the

threadpool that pake is running on when the **–jobs** parameter is greater than **1**.

When the **–jobs** parameter is **1** (the default value), [`pake.MultitaskContext`](index.html#pake.MultitaskContext "pake.MultitaskContext")

degrades to synchronous behavior.

Example:

```

import pake

# functools.partial is used for binding argument values to functions

from functools import partial

pk = pake.init()

@pk.task(i=pake.glob('src/\*.c'), o=pake.pattern('obj/%.o'))

def build\_c(ctx)

   file\_helper = pake.FileHelper(ctx)

   # Make 'obj' directory if it does not exist.

   # This does not complain if it is already there.

   file\_helper.makedirs('obj')

   # Start multitasking

   with ctx.multitask() as mt:

       for i, o in ctx.outdated\_pairs:

           # Read the section 'Output synchronization with ctx.call & ctx.subpake'

           # near the bottom of this page for an explanation of 'sync\_call'

           # below, and how output synchronization is achieved for

           # ctx.call and ctx.subpake

           sync\_call = partial(ctx.call,

                               collect\_output=pk.max\_jobs > 1)

           # Submit a work function with arguments to the threadpool

           mt.submit(sync\_call, ['gcc', '-c', i, '-o', o])

@pk.task(build\_c, i=pake.glob('obj/\*.o'), o='main')

def build(ctx):

   # Utilizing the automatic non string iterable

   # flattening here to pass ctx.inputs and ctx.outputs

   ctx.call('gcc', ctx.inputs, '-o', ctx.outputs)

pake.run(pk, tasks=build)

```

#### Output synchronization with ctx.print & ctx.io.write[¶](#output-synchronization-with-ctx-print-ctx-io-write "Permalink to this headline")

If you are using [`pake.TaskContext.multitask()`](index.html#pake.TaskContext.multitask "pake.TaskContext.multitask") to add concurrency to

the inside of a task, you are in charge of synchronizing output to the

task IO queue.

Pake will synchronize writing the whole task IO queue when the task finishes

if **–sync-output False** is not specified on the command line, but it will not

be able to synchronize the output from sub tasks you submit to its threadpool by

yourself without help.

When performing multiple writes to [`pake.TaskContext.io()`](index.html#pake.TaskContext.io "pake.TaskContext.io") from inside of a task

submitted to [`pake.MultitaskContext()`](index.html#pake.MultitaskContext "pake.MultitaskContext"), you need to acquire a lock on

[`pake.TaskContext.io\_lock`](index.html#pake.TaskContext.io_lock "pake.TaskContext.io_lock") if you want to sure all your writes show

up in the order you made them.

If **–sync-output False** is specified on the command line or [`pake.Pake.sync\_output`](index.html#pake.Pake.sync_output "pake.Pake.sync_output")

is set to **False** manually in the pakefile, then using [`pake.TaskContext.io\_lock`](index.html#pake.TaskContext.io_lock "pake.TaskContext.io_lock")

in a **with** statement does not actually acquire any lock.

If you know that the function or subprocess you are calling is only ever going to write

**once** to the task IO queue (such as the functions in [`pake.FileHelper`](index.html#pake.FileHelper "pake.FileHelper")),

then there is no need to synchronize the output. The single write may come out

of order with respect to other sub tasks, but the message as a whole will be

intact/in-order.

Example:

```

import pake

import random

import time

pk = pake.init()

def my\_sub\_task(ctx):

    data = [

        'Hello ',

        'World, ',

        'I ',

        'Come ',

        'On ',

        'One ',

        'Line\n']

    # ctx.io.write and ctx.print

    # need to be guarded for guaranteed

    # write order, or they might get

    # scrambled in with other IO pake is doing

    with ctx.io\_lock:

        # Lock, so all these writes come in

        # a defined order when jobs > 1

        for i in data:

           # Add a random short delay in seconds

           # to make things interesting

           time.sleep(random.uniform(0, 0.3))

           ctx.io.write(i)

    # This could get scrambled in the output for

    # the task, because your other sub tasks might

    # be interjecting and printing/writing stuff in

    # between these calls to ctx.print when jobs > 1

    data = ['These', 'Are', 'Somewhere', 'Very', 'Weird']

    for i in data:

           # Add a random short delay in seconds

           # to make things interesting

        time.sleep(random.uniform(0, 0.3))

        ctx.print(i)

@pk.task

def my\_task(ctx):

    # Run the sub task 3 times in parallel,

    # passing it the task context

    with ctx.multitask() as mt:

        for i in range(0, 3):

            mt.submit(my\_sub\_task, ctx)

pake.run(pk, tasks=my\_task)

```

Example Output (Will vary of course):

`pake -j 10`

```

===== Executing Task: "my\_task"

Hello World, I Come On One Line

Hello World, I Come On One Line

Hello World, I Come On One Line

These

These

Are

Are

These

Somewhere

Very

Are

Somewhere

Somewhere

Weird

Very

Very

Weird

Weird

```

#### Output synchronization with ctx.call & ctx.subpake[¶](#output-synchronization-with-ctx-call-ctx-subpake "Permalink to this headline")

[`pake.TaskContext.subpake()`](index.html#pake.TaskContext.subpake "pake.TaskContext.subpake"), and `pake.call()` both have an argument

named **collect\_output** which will do all the work required to synchronize output

from sub-pakefiles/processes in a memory efficient manner.

> 

> *Note:*

> 

> 

> [`pake.subpake()`](index.html#pake.subpake "pake.subpake") also has this argument, but you need to pass a lockable context manager object to

> **collect\_output\_lock** in order to properly synchronize its output to the **stdout** parameter.

> [`pake.TaskContext.subpake()`](index.html#pake.TaskContext.subpake "pake.TaskContext.subpake") does all of this for you and a few extra things to make sure

> everything works right, so use it for multitasking inside tasks instead. It passes in the

> [`pake.TaskContext.io\_lock`](index.html#pake.TaskContext.io_lock "pake.TaskContext.io_lock") object as a lock, just FYI.

> 

> 

> 

When the **collect\_output** is **True** and the **silent** parameter of these functions is **False**,

they will buffer all process output to a temporary file while the process is doing work.

When the process finishes, theses functions will acquire a lock on [`pake.TaskContext.io\_lock`](index.html#pake.TaskContext.io_lock "pake.TaskContext.io_lock")

and write all their output to the task’s IO queue incrementally. This way the sub-pakefile/process output

will not get scrambled in with output from other sub tasks that are running concurrently.

Reading process output incrementally from a temporary file after a process

completes will occur much faster than it takes for the actual process to finish.

This means that other processes which may have output can do work and write concurrently,

and pake only needs to lock the task IO queue when it has to relay the output from a

completed process (which is faster than locking while the process is writing).

When pake relays sub-pakefile/process output and **collect\_output** is **True**,

the output will be read/written in chunks to prevent possible memory issues with

processes that produce a lot of output.

The **collect\_output** parameter can be bound to a certain value with `functools.partial()`,

which works well with [`pake.MultitaskContext.map()`](index.html#pake.MultitaskContext.map "pake.MultitaskContext.map") and the other methods of the

multitasking context.

Example:

```

import pake

# functools.partial is used for binding argument values to functions

from functools import partial

pk = pake.init()

@pk.task(i=pake.glob('src/\*.c'), o=pake.pattern('obj/%.o'))

def compile\_c(ctx):

    file\_helper = pake.FileHelper(ctx)

    # Make 'obj' directory if it does not exist.

    # This does not complain if it is already there.

    file\_helper.makedirs('obj')

    # Generate a command for every invocation of GCC that is needed

    compiler\_commands = (['gcc', '-c', i, '-o', o] for i, o in ctx.outdated\_pairs)

    # ----

    # Only use collect\_output when the number of jobs is greater than 1.

    # Task context functions with collect\_output parameters such as

    # ctx.call and ctx.subpake will not degrade back to non-locking

    # behavior on their own when the job count is only 1 and collect\_output=True.

    # This is so you can use this feature with a thread or a threadpool you have

    # created yourself if you want to, without pake messing it up automagically.

    # You should turn collect\_output off when not running pake in parallel,

    # or when you are not using ctx.call or ctx.subpake from another thread

    # that you have manually created. It will still work if you don't, but it

    # will lock IO and pause the main thread until all process output is collected,

    # even when it does not need be doing that.

    sync\_call = partial(ctx.call,

                        collect\_output=pk.max\_jobs > 1)

    # ^^^ You can bind any other arguments to ctx.call you might need this way too.

    with ctx.multitask() as mt:

        # Apply sync\_call to every command

        # in the compiler\_commands list with map,

        # and force execution of the returned generator

        # by passing it to a list constructor

        # This will execute GCC in parallel on the main task

        # threadpool if pake's --jobs argument is > 1

        # sync\_call will keep GCC's output from becoming

        # scrambled in with other stuff if it happens to

        # print warning information or something

        list(mt.map(sync\_call, compiler\_args))

pake.run(pk, tasks=compile\_c)

```

#### Sub task exceptions[¶](#sub-task-exceptions "Permalink to this headline")

If an exception occurs inside one of the sub tasks submitted to [`pake.MultitaskContext.submit()`](index.html#pake.MultitaskContext.submit "pake.MultitaskContext.submit")

or [`pake.MultitaskContext.map()`](index.html#pake.MultitaskContext.map "pake.MultitaskContext.map"), it will be re-raised in the foreground thread of your pake task

at the end of your **with** statement.

The pake task *(your registered task)* will then take over handling of the exception if you do not catch it.

It will be wrapped in a [`pake.TaskException`](index.html#pake.TaskException "pake.TaskException") which is raised from [`pake.Pake.run()`](index.html#pake.Pake.run "pake.Pake.run") and

handled by [`pake.run()`](index.html#pake.run "pake.run").

By default, if more than one task completes with an exception, the one that was submitted first

will be the one to have its exception re-raised.

You can set the **aggregate\_exceptions** parameter of [`pake.TaskContext.multitask()`](index.html#pake.TaskContext.multitask "pake.TaskContext.multitask")

to **True**, and it will return an executor context that will collect any raised exceptions

and add them all to a [`pake.AggregateException`](index.html#pake.AggregateException "pake.AggregateException"). The aggregate exception will then

be raised at the end of your **with** statement.

Example:

```

import pake

pk = pake.init()

class MyException(Exception):

    pass

def my\_sub\_task():

    raise MyException('Hello World!')

@pk.task

def my\_task(ctx):

    with ctx.multitask(aggregate\_exceptions=True) as mt:

        # You can also do this, instead of using the parameter

        mt.aggregate\_exceptions = True

        for i in range(0, 3):

            mt.submit(my\_sub\_task)

# Force this example to run with 10 jobs

# regardless of what the command line says

pake.run(pk, tasks=my\_task, jobs=10)

```

Output:

```

===== Executing Task: "my\_task"

Exception "pake.pake.AggregateException" was raised within task "my\_task".

Traceback (most recent call last):

  File "{PAKE\_INSTALL\_DIR}/pake/pake.py", line 1937, in func_wrapper

    return func(*args, **kwargs)

  File "{PAKEFILE\_DIR}/pakefile.py", line 19, in my_task

    mt.submit(my_sub_task)

  File "{PAKE\_INSTALL\_DIR}/pake/pake.py", line 1228, in __exit__

    self.shutdown()

  File "{PAKE\_INSTALL\_DIR}/pake/pake.py", line 1225, in shutdown

    raise AggregateException(exceptions)

pake.pake.AggregateException: [MyException('Hello World!',), MyException('Hello World!',), MyException('Hello World!',)]

All Aggregated Exceptions:

Exception Number 1:

===================

Traceback (most recent call last):

  File "{PYTHON\_INSTALL\_DIR}/lib/concurrent/futures/thread.py", line 55, in run

    result = self.fn(*self.args, **self.kwargs)

  File "{PAKEFILE\_DIR}/pakefile.py", line 9, in my_sub_task

    raise MyException('Hello World!')

MyException: Hello World!

Exception Number 2:

===================

Traceback (most recent call last):

  File "{PYTHON\_INSTALL\_DIR}/lib/concurrent/futures/thread.py", line 55, in run

    result = self.fn(*self.args, **self.kwargs)

  File "{PAKEFILE\_DIR}/pakefile.py", line 9, in my_sub_task

    raise MyException('Hello World!')

MyException: Hello World!

Exception Number 3:

===================

Traceback (most recent call last):

  File "{PYTHON\_INSTALL\_DIR}/lib/concurrent/futures/thread.py", line 55, in run

    result = self.fn(*self.args, **self.kwargs)

  File "{PAKEFILE\_DIR}/pakefile.py", line 9, in my_sub_task

    raise MyException('Hello World!')

MyException: Hello World!

```

Aggregate exceptions will be wrapped in a [`pake.TaskException`](index.html#pake.TaskException "pake.TaskException") and thrown from

[`pake.Pake.run()`](index.html#pake.Pake.run "pake.Pake.run") just like any other exception. [`pake.run()`](index.html#pake.run "pake.run") intercepts

the task exception and makes sure it gets printed in a way that is readable if it contains

an instance of [`pake.AggregateException`](index.html#pake.AggregateException "pake.AggregateException").

If you are not using a **with** statement, the exception will propagate out of

[`pake.MultitaskContext.shutdown()`](index.html#pake.MultitaskContext.shutdown "pake.MultitaskContext.shutdown") when you call it manually, unless you

pass **wait=False**, in which case no exceptions will be re-raised.

### Manipulating Files / Dirs With pake.FileHelper[¶](#manipulating-files-dirs-with-pake-filehelper "Permalink to this headline")

[`pake.FileHelper`](index.html#pake.FileHelper "pake.FileHelper") contains several useful filesystem manipulation

methods that are common in software builds. Operations include creating full

directory trees, glob removal of files and directories, file touch etc..

The [`pake.FileHelper`](index.html#pake.FileHelper "pake.FileHelper") class takes a single optional argument named **printer**.

The passed object should implement a **print(\*args)** function.

If you pass it a [`pake.TaskContext`](index.html#pake.TaskContext "pake.TaskContext") instance from your tasks single argument, it will

print information about file system operations to the tasks IO queue as they are being performed.

Each method can turn off this printing by using a **silent** option argument that is common

to all class methods.

If you construct [`pake.FileHelper`](index.html#pake.FileHelper "pake.FileHelper") without an argument, all operations will occur

silently.

#### File / Folder creation methods[¶](#file-folder-creation-methods "Permalink to this headline")

```

@pk.task

def my\_build(ctx):

    fh = pake.FileHelper(ctx)

    # Create a directory or an entire directory tree

    fh.makedirs('dist/bin')

    # Touch a file

    fh.touch('somefile.txt')

```

Output:

```

===== Executing Task: "my\_build"

Created Directory(s): "dist/bin"

Touched File: "somefile.txt"

```

#### Copy / Move methods[¶](#copy-move-methods "Permalink to this headline")

```

@pk.task

def my\_build(ctx):

fh = pake.FileHelper(ctx)

# Recursively copy and entire directory tree.

# In this case, 'bin' will be copied into 'dist'

# as a subfolder.

fh.copytree('bin', 'dist/bin')

# Recursively move an entire directory tree

# and its contents. In this case, 'lib' will

# be moved into 'dist' as a subfolder.

fh.move('lib', 'dist/lib')

# Copy a file to a directory without

# renaming it.

fh.copy('LICENCE.txt', 'dist')

# Copy with rename

fh.copy('LICENCE.txt', 'dist/licence.txt')

# Move a file to a directory without

# renaming it.

fh.move('README.txt', 'dist')

# Move with rename

fh.move('README.rtf', 'dist/readme.rtf')

```

Output:

```

===== Executing Task: "my\_build"

Copied Tree: "bin" -> "dist/bin"

Moved Tree: "lib" -> "dist/lib"

Copied File: "LICENCE.txt" -> "dist"

Copied File: "LICENCE.txt" -> "dist/licence.txt"

Moved File: "README.txt" -> "dist"

Moved File: "README.rtf" -> "dist/readme.rtf"

```

#### Removal / Clean related methods[¶](#removal-clean-related-methods "Permalink to this headline")

```

@pk.task

def my\_clean(ctx):

   fh = pake.FileHelper(ctx)

   # Glob delete all files under the 'obj' directory

   fh.glob\_remove('obj/\*.o')

   # Delete all sub directories of 'stuff'

   fh.glob\_remove\_dirs('stuff/\*')

   # Remove a directory tree, does nothing if 'build\_dir'

   # does not exist. Unless the must\_exist argument is

   # set to True.

   fh.rmtree('build\_dir')

   # Remove a file, does nothing if 'main.exe' does not

   # exist. Unless the must\_exist argument is set to True

   fh.remove('main.exe')

```

Output:

```

===== Executing Task: "my\_clean"

Glob Removed Files: "obj/\*.o"

Glob Removed Directories: "stuff/\*"

Removed Directory(s): "build\_dir"

Removed File: "main.exe"

```

### Running Commands / Sub Processes[¶](#running-commands-sub-processes "Permalink to this headline")

#### TaskContext.call[¶](#taskcontext-call "Permalink to this headline")

The [`pake.TaskContext`](index.html#pake.TaskContext "pake.TaskContext") object passed into each task contains

methods for calling sub-processes in a way that produces user friendly

error messages and halts the execution of pake if an error is reported

by the given process.

[`pake.TaskContext.call()`](index.html#pake.TaskContext.call "pake.TaskContext.call") can be used to run a program and direct

all of its output (stdout and stderr) to the tasks IO queue.

It will raise a [`pake.TaskSubprocessException`](index.html#pake.TaskSubprocessException "pake.TaskSubprocessException") on non-zero return

codes by default unless you specify **ignore\_errors=True**.

If you specify for **call** to ignore errors, it will always return the

process’s return code regardless of whether it was non-zero or not.

It can be used to test return codes like [`pake.TaskContext.check\_call()`](index.html#pake.TaskContext.check_call "pake.TaskContext.check_call"),

but it is preferable to use the later method for that purpose since [`pake.TaskContext.call()`](index.html#pake.TaskContext.call "pake.TaskContext.call")

prints to the task IO queue by default. (unless you specify **silent=True** and **print\_cmd=False**).

[`pake.TaskContext.call()`](index.html#pake.TaskContext.call "pake.TaskContext.call") is designed primarily for handling

large amounts of process output and reporting it back when an error occurs

without crashing pake, which is accomplished by duplicating the process output

to a temporary file on disk and later reading it back incrementally when needed.

Examples:

```

# 'call' can have its arguments passed in several different ways

@pk.task(o='somefile.txt')

def my\_task(ctx):

    # Command line passed as a list..

    ctx.call(['echo', 'Hello!'])

    # Iterables such as the outputs property of the context

    # will be flattened. String objects are not considered

    # for flattening which allows this sort of syntax

    ctx.call(['touch', ctx.outputs]) # We know there is only one output

    # The above will also work when using varargs

    ctx.call('touch', ctx.outputs)

    # Command line passed as a string

    ctx.call('echo "goodbye!"')

    # Try some command and ignore any errors (non-zero return codes)

    # Otherwise, 'call' raises a 'pake.TaskSubprocessException' on non-zero

    # return codes.

    ctx.call(['do\_something\_bad'], ignore\_errors=True)

# A realistic example for compiling objects from C

@pk.task(i=pake.glob('src/\*.c'), o=pake.pattern('obj/%.o'))

def compile\_c(ctx):

    for i, o in ctx.outdated\_pairs:

        ctx.call('gcc', '-c', i, '-o', o)

# And with multitasking, the simple way

@pk.task(i=pake.glob('src/\*.c'), o=pake.pattern('obj/%.o'))

def compile\_c(ctx):

    with ctx.multitask() as mt:

        for i, o in ctx.outdated\_pairs:

            mt.submit(ctx.call, ['gcc', '-c', i, '-o', o])

# With multitasking, the fancy way

@pk.task(i=pake.glob('src/\*.c'), o=pake.pattern('obj/%.o'))

def compile\_c(ctx):

    with ctx.multitask() as mt:

        # Force enumeration over the returned generator by constructing a temporary list..

        # the 'ctx.map' function yields 'Future' instances

        list(ctx.map(ctx.call, (['gcc', '-c', i, '-o', o] for i, o in ctx.outdated\_pairs)))

```

#### TaskContext.check\_output[¶](#taskcontext-check-output "Permalink to this headline")

[`pake.TaskContext.check\_output()`](index.html#pake.TaskContext.check_output "pake.TaskContext.check_output") can be used to read all the output

from a command into a bytes object. The args parameter of **check\_output**

and in general all functions dealing with calling system commands allow for

identical syntax, including nested lists and such.

The reasoning or using this over the built in `subprocess.check\_output()`

is that if an error occurs in the subprocess, pake will be able to print more comprehensible

error information to the task output.

[`pake.TaskContext.check\_output()`](index.html#pake.TaskContext.check_output "pake.TaskContext.check_output") differs from `subprocess.check\_output()`

in that you cannot specify an **stderr** parameter, and an **ignore\_errors**

option is added which can prevent the method from raising an exception on non

zero return codes from the process. All of the process’s **stderr** is directed

to its **stdout**.

**ignore\_errors** allows you to directly return the output of a command even if it errors

without having to handle an exception to get the output.

[`pake.TaskContext.check\_output()`](index.html#pake.TaskContext.check_output "pake.TaskContext.check_output") returns a **bytes** object, which means you need

to call **decode** on it if you want the output as a string.

Examples:

```

# 'which' is a unix command that returns the full path of a command's binary.

# The exit code is non-zero if the command given does not exist. So

# it will be easy enough to use for this example.

@pk.task

def my\_task(ctx):

    # Print the full path of the default C compiler on linux

    ctx.print(ctx.check\_output('which', 'cc').decode())

    # Check if some command exists

    if ctx.check\_output(['which', 'some\_command'],

                        ignore\_errors=True).decode().strip() != '':

        ctx.print('some\_command exists')

    # Using an exception handler

    try:

        path = ctx.check\_output('which', 'gcc').decode()

        ctx.print('gcc exists!, path:', path)

    except pake.TaskSubprocessException:

        pass

```

#### TaskContext.check\_call[¶](#taskcontext-check-call "Permalink to this headline")

[`pake.TaskContext.check\_call()`](index.html#pake.TaskContext.check_call "pake.TaskContext.check_call") has an identical signature to [`pake.TaskContext.check\_output()`](index.html#pake.TaskContext.check_output "pake.TaskContext.check_output"),

except it returns the return code of the called process.

The **ignore\_errors** argument allows you to return the value of non-zero return codes without

having to handle an exception such as with `subprocess.check\_call()` from pythons built

in subprocess module.

In addition, if an exception is thrown, pake will be able to print comprehensible error info

about the location of the exception to the task IO queue while avoiding a huge stack trace.

The same is true for the other functions dealing with processes in the task context.

Examples:

```

# using the 'which' command here again for this example...

@pk.task

def my\_task(ctx):

    # Check if some command exists, a better way on linux at least

    if ctx.check\_call(['which', 'some\_command'],

                       ignore\_errors=True) == 0:

        ctx.print('some\_command exists')

    # Using an exception handler

    try:

        ctx.check\_call('which', 'gcc')

        ctx.print('gcc exists!')

    except pake.TaskSubprocessException:

        pass

```

#### pake.process module methods[¶](#pake-process-module-methods "Permalink to this headline")

The [`pake.process`](index.html#module-pake.process "pake.process") module provides thin wrappers around the built in python `subprocess` module methods.

Primarily: `subprocess.call()`, `subprocess.check\_call()` and `subprocess.check\_output()`.

The corresponding wrappers are: [`pake.process.call()`](index.html#pake.process.call "pake.process.call"), [`pake.process.check\_call()`](index.html#pake.process.check_call "pake.process.check_call") and [`pake.process.check\_output()`](index.html#pake.process.check_output "pake.process.check_output").

The wrappers exist mostly to allow calling sub-processes with a similar syntax to `pake.Pake.call()` and friends.

IE. They can be called with variadic arguments, and will also flatten any non string iterables passed to the **\*args** parameter.

Example:

```

import sys

from pake import process

def run\_python\_silent(\*args):

    # sys.executable and \*args go into the variadic argument, the

    # \*args iterable is flattened out for you

    # Returns the return code

    return process.call(sys.executable, args,

                        stdout=process.DEVNULL,

                        stderr=process.DEVNULL)

```

They also raise exceptions similar to those from the `subprocess` module, however the exceptions

behave nicer if they occur inside of a task.

See: [`pake.process.TimeoutExpired`](index.html#pake.process.TimeoutExpired "pake.process.TimeoutExpired") and [`pake.process.CalledProcessException`](index.html#pake.process.CalledProcessException "pake.process.CalledProcessException").

Which are analogs for `subprocess.TimeoutExpired` and `subprocess.CalledProcessException`.

### Running Sub Pakefiles[¶](#running-sub-pakefiles "Permalink to this headline")

Pake is able to run itself through the use of [`pake.TaskContext.subpake()`](index.html#pake.TaskContext.subpake "pake.TaskContext.subpake")

and [`pake.subpake()`](index.html#pake.subpake "pake.subpake").

[`pake.subpake()`](index.html#pake.subpake "pake.subpake") is meant to be used outside of tasks, and can even be

called before pake is initialized.

[`pake.TaskContext.subpake()`](index.html#pake.TaskContext.subpake "pake.TaskContext.subpake") is preferred for use inside of tasks because

it handles writing to the task’s output queue for you, without having to specify

extra parameters to [`pake.subpake()`](index.html#pake.subpake "pake.subpake") to get it working correctly.

A [`pake.TaskContext`](index.html#pake.TaskContext "pake.TaskContext") instance is passed into the single argument of each task function,

which you can in turn call **subpake** from.

Defines can be exported to pakefiles ran with the **subpake** functions using [`pake.export()`](index.html#pake.export "pake.export").

[`pake.subpake()`](index.html#pake.subpake "pake.subpake") and [`pake.TaskContext.subpake()`](index.html#pake.TaskContext.subpake "pake.TaskContext.subpake") use the **–stdin-defines** option of

pake to pass exported define values into the new process instance, which means you can overwrite your

exported define values with **-D/–define** in the subpake command arguments if you need to.

Export / Subpake Example:

```

import pake

pk = pake.init()

# Try to get the CC define from the command line,

# default to 'gcc'.

CC = pk.get\_define('CC', 'gcc')

# Export the CC variable's value to all invocations

# of pake.subpake or ctx.subpake as a define that can be

# retrieved with pk.get\_define()

pake.export('CC', CC)

# You can also export lists, dictionaries sets and tuples,

# as long as they only contain literal values.

# Literal values being: strings, integers, floats; and

# other lists, dicts, sets and tuples. Collections must only

# contain literals, or objects that repr() into a parsable literal.

pake.export('CC\_FLAGS', ['-Wextra', '-Wall'])

# Nesting works with composite literals,

# as long as everything is a pure literal or something

# that str()'s into a literal.

pake.export('STUFF',

            ['you',

             ['might',

              ('be',

               ['a',

                {'bad' :

                     ['person', ['if', {'you', 'do'}, ('this',) ]]

                 }])]])

# This export will be overrode in the next call

pake.export('OVERRIDE\_ME', False)

# Execute outside of a task, by default the stdout/stderr

# of the subscript goes to this scripts stdout. The file

# object to which stdout gets written to can be specified

# with pake.subpake(..., stdout=(file))

# This command also demonstrates that you can override

# your exports using the -D/--define option

pake.subpake('sometasks/pakefile.py', 'dotasks', '-D', 'OVERRIDE\_ME=True')

# This task does not depend on anything or have any inputs/outputs

# it will basically only run if you explicitly specify it as a default

# task in pake.run, or specify it on the command line

@pk.task

def my\_phony\_task(ctx):

    # Arguments are passed in a variadic parameter...

    # Specify that the "foo" task is to be ran.

    # The scripts output is written to this tasks output queue

    ctx.subpake('library/pakefile.py', 'foo')

# Run this pake script, with a default task of 'my\_phony\_task'

pake.run(pk, tasks=my\_phony\_task)

```

Output from the example above:

```

*** enter subpake[1]:

pake[1]: Entering Directory "(REST OF PATH...)/paketest/sometasks"

===== Executing Task: "dotasks"

Do Tasks

pake[1]: Exiting Directory "(REST OF PATH...)/paketest/sometasks"

*** exit subpake[1]:

===== Executing Task: "my\_phony\_task"

*** enter subpake[1]:

pake[1]: Entering Directory "(REST OF PATH...)/paketest/library"

===== Executing Task: "foo"

Foo!

pake[1]: Exiting Directory "(REST OF PATH...)/paketest/library"

*** exit subpake[1]:

```

Module Index[¶](#module-index "Permalink to this headline")

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

* [Module Index](py-modindex.html)

