Welcome to parasweep’s documentation!¶
parasweep¶
parasweep is a free and open-source Python utility for facilitating parallel parameter sweeps with computational models. Instead of requiring parameters to be passed by command-line, which can be error-prone and time-consuming, parasweep leverages the model’s existing configuration files using a template system, requiring minimal code changes. After the sweep values are specified, a parallel job is dispatched for each parameter set, with support for common high-performance computing job schedulers. Post-processing is facilitated by providing a mapping between the parameter sets and the simulations.
The following paper gives a description as well as a simple example to get started: https://arxiv.org/pdf/1905.03448.pdf. Please cite it if you find parasweep useful for your project!
- Free software: MIT license
- Documentation: http://www.parasweep.io
- Code: https://github.com/eviatarbach/parasweep
Dependencies¶
- Python 3.6+
- xarray
- numpy
- scipy
- Mako (optional)
- drmaa-python (optional)
Credits¶
Developed by Eviatar Bach <eviatarbach@protonmail.com>. Special thanks to Daniel Philipps (danielphili) for a bug fix and feature suggestion.
This package was created with Cookiecutter and the audreyr/cookiecutter-pypackage project template.
Installation¶
Stable release¶
To install parasweep, run this command in your terminal:
$ pip install parasweep
This is the preferred method to install parasweep, as it will always install the most recent stable release.
If you don’t have pip installed, this Python installation guide can guide you through the process.
From sources¶
The sources for parasweep can be downloaded from the GitHub repo.
You can either clone the public repository:
$ git clone git://github.com/eviatarbach/parasweep
Or download the tarball:
$ curl -OL https://github.com/eviatarbach/parasweep/tarball/master
Once you have a copy of the source, you can install it with:
$ python setup.py install
Examples¶
As a toy “simulation”, in these examples we make use of the standard Unix
command cat
, which concatenates the files given to it as arguments and
prints the results.
Sweeps¶
CartesianSweep¶
In a Cartesian sweep, all the combinations of all the parameters are used (every member in the Cartesian product of the sets of parameter values).
template.txt:
Hello {x}, {y}, {z}
Command:
>>> from parasweep import run_sweep, CartesianSweep
>>> mapping = run_sweep(command='cat {sim_id}.txt',
... configs=['{sim_id}.txt'],
... templates=['template.txt'],
... sweep=CartesianSweep({'x': [1, 2],
... 'y': [3, 4, 5],
... 'z': [6, 7]}),
... verbose=False, sweep_id='test')
Hello 1, 3, 6
Hello 1, 3, 7
Hello 1, 4, 6
Hello 1, 4, 7
Hello 1, 5, 6
Hello 1, 5, 7
Hello 2, 3, 6
Hello 2, 3, 7
Hello 2, 4, 6
Hello 2, 4, 7
Hello 2, 5, 6
Hello 2, 5, 7
Note
Although the commands may execute in the order shown above, this is
not guaranteed since the simulations are dispatched in parallel. To run
serially, the option serial=True
can be set.
An xarray DataArray
will be returned between the parameters and the
simulation IDs, which facilitates postprocessing:
>>> mapping
<xarray.DataArray 'sim_id' (x: 2, y: 3, z: 2)>
array([[['test_00', 'test_01'],
['test_02', 'test_03'],
['test_04', 'test_05']],
[['test_06', 'test_07'],
['test_08', 'test_09'],
['test_10', 'test_11']]], dtype='<U7')
Coordinates:
* x (x) int64 1 2
* y (y) int64 3 4 5
* z (z) int64 6 7
In this case, it is three-dimensional, since three parameters are being swept over.
FilteredCartesianSweep¶
There is also a filtered Cartesian sweep, allowing for a Cartesian sweep
where only elements meeting satisfying some condition on the parameters
are used. For example, suppose we want to sweep over x
, y
, and z
but only include those parameter sets where x > y
:
template.txt:
Hello {x}, {y}, {z}
Command:
>>> from parasweep import run_sweep, FilteredCartesianSweep
>>> sweep = FilteredCartesianSweep({'x': [1, 2, 3], 'y': [1, 2, 3],
... 'z': [4, 5]},
... filter_func=lambda x, y, **kwargs: x > y)
>>> mapping = run_sweep(command='cat {sim_id}.txt',
... configs=['{sim_id}.txt'],
... templates=['template.txt'], sweep=sweep,
... verbose=False, sweep_id='test')
Hello 2, 1, 4
Hello 2, 1, 5
Hello 3, 1, 4
Hello 3, 1, 5
Hello 3, 2, 4
Hello 3, 2, 5
Note
Parameters that are not used in the filtering function, z
in this
case, can be ignored in filter_func
by using the **kwargs
argument.
In this case, the parameter mapping is a dictionary like the following:
>>> mapping
{'test_0': {'x': 2, 'y': 1, 'z': 4},
'test_1': {'x': 2, 'y': 1, 'z': 5},
'test_2': {'x': 3, 'y': 1, 'z': 4},
'test_3': {'x': 3, 'y': 1, 'z': 5},
'test_4': {'x': 3, 'y': 2, 'z': 4},
'test_5': {'x': 3, 'y': 2, 'z': 5}}
SetSweep¶
Instead of a Cartesian sweep, specific parameter sets can be used with
SetSweep
:
template.txt:
Hello {x}, {y}, {z}
Command:
>>> from parasweep import run_sweep, SetSweep
>>> mapping = run_sweep(command='cat {sim_id}.txt',
... configs=['{sim_id}.txt'],
... templates=['template.txt'],
... sweep=SetSweep([{'x': 2, 'y': 8, 'z': 5},
... {'x': 1, 'y': -4, 'z': 9}]),
... verbose=False, sweep_id='test')
Hello 2, 8, 5
Hello 1, -4, 9
Here, as with FilteredCartesianSweep
, the parameter mapping is a
dictionary:
>>> mapping
{'test_0': {'x': 2, 'y': 8, 'z': 5}, 'test_1': {'x': 1, 'y': -4, 'z': 9}}
RandomSweep¶
There is also a random sweep, where parameters are drawn from independent random distributions.
template.txt:
Hello {x}, {y}
Command:
>>> import scipy.stats
>>> from parasweep import run_sweep, RandomSweep
>>> mapping = run_sweep(command='cat {sim_id}.txt',
... configs=['{sim_id}.txt'],
... templates=['template.txt'],
... sweep=RandomSweep({'x': scipy.stats.norm(),
... 'y': scipy.stats.uniform()},
... length=3),
... verbose=False, sweep_id='test')
Hello 0.9533238364874957, 0.8197338171659898
Hello -1.966220661588362, 0.3213785864763252
Hello -0.057572896338656816, 0.17615488655036005
Here, x
is drawn from a standard normal distribution and y
is uniform
between 0 and 1.
The parameter mapping is again a dictionary:
>>> mapping
{'test_0': {'x': 0.9533238364874957, 'y': 0.8197338171659898},
'test_1': {'x': -1.966220661588362, 'y': 0.3213785864763252},
'test_2': {'x': -0.057572896338656816, 'y': 0.17615488655036005}}
Multiple configuration files¶
Multiple configuration files and their corresponding templates can be used:
template1.txt:
Hello {x},
template2.txt:
hello again {y}
Command:
>>> from parasweep import run_sweep, CartesianSweep
>>> mapping = run_sweep(command='cat {sim_id}_1.txt {sim_id}_2.txt',
... configs=['{sim_id}_1.txt', '{sim_id}_2.txt'],
... templates=['template1.txt', 'template2.txt'],
... sweep=CartesianSweep({'x': [1, 2, 3],
... 'y': [4]}),
... verbose=False)
Hello 1,
hello again 4
Hello 2,
hello again 4
Hello 3,
hello again 4
Sweep IDs¶
Sweep IDs are used to name the mapping structure if it is saved to disk, and also in assigning simulation IDs in some cases. If it is not provided explicitly it is generated based on the current time.
template.txt:
Hello {x},
Command:
>>> import os
>>> from parasweep import run_sweep, CartesianSweep
>>> mapping = run_sweep(command='cat {sim_id}.txt',
... configs=['{sim_id}.txt'],
... templates=['template.txt'],
... sweep=CartesianSweep({'x': [1, 2, 3]}),
... verbose=False, sweep_id='test_sweep')
Hello 1
Hello 2
Hello 3
>>> os.path.exists('sim_ids_test_sweep.nc')
True
Dispatchers¶
Number of processes¶
By default, the maximum number of processes run simultaneously with
SubprocessDispatcher
is equal to the number of processors on the machine.
We can choose a custom number, however.
Command:
>>> from parasweep import run_sweep, CartesianSweep
>>> from parasweep.dispatchers import SubprocessDispatcher
>>> dispatcher = SubprocessDispatcher(max_procs=2)
This dispatcher should then be passed to run_sweep
as the dispatcher
argument.
DRMAA¶
Instead of dispatching simulations with Python’s subprocess
module, we can
use the Distributed Resource Management Application API (DRMAA) to interface
with a number of high-performance computing systems. The following example
assumes that DRMAA and an interface to a job scheduler are installed.
template.txt:
Hello {x}
Command:
>>> from parasweep import run_sweep, CartesianSweep
>>> from parasweep.dispatchers import DRMAADispatcher
We can specify a JobTemplate
which specifies job options for DRMAA. Here,
we set errors to output to err_test.txt
.
>>> from drmaa import JobTemplate
>>> jt = JobTemplate(errorPath=':err_test.txt')
Note
Some options specific to each job scheduler, called the native
specification, may have to be set using the
job_template.nativeSpecification
attribute, the options for which can be
found in the job scheduler’s DRMAA interface (e.g., slurm-drmaa for Slurm
and pbs-drmaa for PBS).
We set the command to print the contents of the configuration file to
stderr
(this syntax may only work on bash):
>>> mapping = run_sweep(command='>&2 cat {sim_id}.txt',
... configs=['{sim_id}.txt'],
... templates=['template.txt'],
... sweep=CartesianSweep({'x': [1]}),
... verbose=False, dispatcher=DRMAADispatcher(jt))
>>> with open('err_test.txt', 'r') as err_file:
... print(err_file.read())
Hello 1
Template engines¶
Formatting¶
The following is an example of the basic formatting that can be done with the Python formatting templates:
template.txt:
Hello {x:.2f}
Command:
>>> from parasweep import run_sweep, CartesianSweep
>>> mapping = run_sweep(command='cat {sim_id}.txt',
... configs=['{sim_id}.txt'],
... templates=['template.txt'],
... sweep=CartesianSweep({'x': [1/3, 2/3, 3/3]}),
... verbose=False)
Hello 0.33
Hello 0.67
Hello 1.00
Mako templates¶
Mako templates provide functionality that is not available with Python formatting templates, being able to insert code within the template:
template.txt:
Hello ${x*10}
Command:
>>> from parasweep import run_sweep, CartesianSweep
>>> from parasweep.templates import MakoTemplate
>>> mapping = run_sweep(command='cat {sim_id}.txt',
... configs=['{sim_id}.txt'],
... templates=['template.txt'],
... sweep=CartesianSweep({'x': [1, 2, 3]}),
... verbose=False, template_engine=MakoTemplate())
Hello 10
Hello 20
Hello 30
Naming¶
HashNamer¶
In the case where many parameter sweeps are run on the same model, it may be
helpful to use HashNamer
to avoid collision of the output files.
template.txt:
Hello {x}
Command:
>>> from parasweep import run_sweep, CartesianSweep
>>> from parasweep.namers import HashNamer
>>> mapping = run_sweep(command='echo {sim_id}',
... configs=['{sim_id}.txt'],
... templates=['template.txt'],
... sweep=CartesianSweep({'x': [1, 2, 3]}),
... namer=HashNamer(), verbose=False)
16bcb7a1
7e3245fa
1780e76b
Note
The hash for each parameter set is generated based on the parameter
set itself as well as the sweep ID. Thus if the sweep IDs are different,
hashes will vary between sweeps even if the parameters sets are identical.
If sweep_id
is not provided as an argument to run_sweep
it will be
generated based on the current time.
parasweep.sweep module¶
Main sweep functionality.
-
parasweep.sweep.
run_sweep
(command, configs, templates, sweep, namer=<parasweep.namers.SequentialNamer object>, dispatcher=<parasweep.dispatchers.SubprocessDispatcher object>, template_engine=<parasweep.templates.PythonFormatTemplate object>, sweep_id=None, excluded_sim_ids=[], serial=False, wait=True, cleanup=False, verbose=True, overwrite=True, save_mapping=True)[source]¶ Run parameter sweeps.
Parameters: - command (str) – The command to run. Must include
{sim_id}
indicating where the simulation ID is to be inserted. - configs (list) – List of paths indicating where the configuration files should be saved
after substitution of the parameters into the templates. Each must
include
{sim_id}
indicating where the simulation ID is to be inserted. Must be in the same order astemplates
. - templates (list) – List of paths of templates to substitute parameters into. Must be in
the same order as
configs
. - sweep (sweepers.Sweep instance) – A
parasweep.sweepers.Sweep
object that specifies the type of sweep. By default, it is a Cartesian sweep. - namer (namers.Namer instance, optional) – A
parasweep.namers.Namer
object that specifies how to assign simulation IDs. By default, assigns simulation IDs sequentially. - dispatcher (dispatchers.Dispatcher instance, optional) – A
parasweep.dispatchers.Dispatcher
object that specifies how to run the jobs. By default, uses Python’ssubprocess
module. - template_engine (templates.TemplateEngine instance, optional) – A
parasweep.templates.TemplateEngine
object that specifies the template engine to use. By default, uses Python format strings. - sweep_id (str, optional) – A name for the sweep. By default, the name is generated automatically from the date and time.
- excluded_sim_ids (list, optional) – A list of simulation IDs to exclude from the sweep.
- serial (bool, optional) – Whether to run simulations serially, i.e., to wait for each simulation to complete before executing the next one. Enabling this turns off parallelism. False by default.
- wait (bool, optional) – Whether to wait for all simulations to complete before returning. True by default.
- cleanup (bool, optional) – Whether to delete configuration files after all the simulations are
done. This will cause the command to wait on all processes before
returning (as with the
wait
argument). False by default. - verbose (bool, optional) – Whether to print some information about each simulation as it is launched. True by default.
- overwrite (bool, optional) – Whether to overwrite existing files when creating configuration files.
If False, a
FileExistsError
will be raised when a configuration filename coincides with an existing one in the same directory. True by default. - save_mapping (bool, optional) – Whether to save a mapping between the parameters to the simulation
IDs. The type of mapping will depend on the type of sweep (set with
the
sweep
argument). The filename will be of the formsim_ids_{sweep_id}
, with an extension depending on the mapping type. True by default.
Examples
Many examples are provided in Examples.
- command (str) – The command to run. Must include
parasweep package¶
Submodules¶
parasweep.dispatchers module¶
Dispatchers for running parallel jobs.
-
class
parasweep.dispatchers.
Dispatcher
[source]¶ Bases:
abc.ABC
Abstract base class for dispatchers.
Subclasses should implement the
initialize_session
,dispatch
, andwait_all
methods.
-
class
parasweep.dispatchers.
SubprocessDispatcher
(max_procs=None)[source]¶ Bases:
parasweep.dispatchers.Dispatcher
Dispatcher using subprocesses.
Parameters: max_procs (int, optional) – The maximum number of processes to run simultaneously. By default, uses the number of processors on the machine (this is a good choice for CPU-bound work).
-
class
parasweep.dispatchers.
DRMAADispatcher
(job_template=None)[source]¶ Bases:
parasweep.dispatchers.Dispatcher
Dispatcher for DRMAA.
Parameters: job_template (drmaa.JobTemplate instance, optional) – A job template containing settings for running the jobs with the job scheduler. Documentation for the different options is available in the Python drmaa package. Some options specific to each job scheduler, called the native specification, may have to be set using the job_template.nativeSpecification
attribute, the options for which can be found in the job scheduler’s DRMAA interface (e.g., slurm-drmaa for Slurm and pbs-drmaa for PBS).Examples
>>> import drmaa >>> jt = drmaa.JobTemplate(hardWallclockTimeLimit=60) >>> dispatcher = DRMAADispatcher(jt)
-
session
= None¶
-
parasweep.namers module¶
Namers for generating simulation IDs.
-
class
parasweep.namers.
Namer
[source]¶ Bases:
abc.ABC
Abstract class for assigning simulation IDs to simulation.
Only the
next
method has to be implemented.
-
class
parasweep.namers.
SequentialNamer
(zfill=None, start_at=0)[source]¶ Bases:
parasweep.namers.Namer
Name simulations with consecutive numbers and leading zeros.
Parameters: - zfill (None or int, optional) – If provided, sets the width to which the name string is to be padded with zeros.
- start_at (int, optional) – Sets the integer to start at in the sequential naming.
Examples
>>> counter = SequentialNamer() >>> counter.start(length=11) >>> counter.generate_id({'key1': 'value1'}, '') '00' >>> counter.generate_id({'key2': 'value2'}, '') '01' >>> counter.start(length=2) >>> counter.generate_id({'key1': 'value1'}, 'sweep_id') 'sweep_id_0'
-
class
parasweep.namers.
HashNamer
(hash_length=8)[source]¶ Bases:
parasweep.namers.Namer
Name simulations using hashing.
Parameters: hash_length (int, optional) – How many hexadecimal numbers to truncate the hash to. 6 by default. Examples
>>> namer = HashNamer() >>> namer.generate_id({'key1': 'value1'}, '') '31fc462e' >>> namer.generate_id({'key2': 'value2'}, '') '9970c8f5'
-
class
parasweep.namers.
SetNamer
(names)[source]¶ Bases:
parasweep.namers.Namer
Name simulations consecutively with a provided iterable.
Parameters: names (Iterable[str]) – The sequence of names to assign to consecutive simulations. Examples
>>> namer = SetNamer(['name1', 'name2']) >>> namer.generate_id({'key1': 'value1'}, '') 'name1' >>> namer.generate_id({'key2': 'value2'}, '') 'name2'
parasweep.sweepers module¶
-
class
parasweep.sweepers.
Sweep
(*args, **kwargs)[source]¶ Bases:
abc.ABC
Abstract class for parameter sweep types.
Sweeps must define an initialization using
__init__
, the sweep length using__len__
, an iteration usingelements
, and a type of mapping usingmapping
.-
elements
()[source]¶ Return the elements of the sweep.
May be lazily evaluated, depending on the type of sweep.
-
mapping
(sim_ids, sweep_id, save=True)[source]¶ Return a mapping between the simulation IDs and the parameter sets.
The mapping may be from simulation IDs to parameter sets or vice-versa, depending on what is convenient for the type of sweep.
Parameters: - sim_ids (list) – The simulation IDs that were assigned to each parameter set, in the
same order as returned by
elements
. - sweep_id (str) – The sweep ID
- save (bool) – Whether to save the mapping to disk. The filename should be of the
form
sim_ids_{sweep_id}
, with an extension depending on the mapping type. True by default.
- sim_ids (list) – The simulation IDs that were assigned to each parameter set, in the
same order as returned by
-
-
class
parasweep.sweepers.
CartesianSweep
(sweep_params)[source]¶ Bases:
parasweep.sweepers.Sweep
A Cartesian product parameter sweep.
Parameters: sweep_params (dict) – A dictionary containing the parameter names as keys and lists of values to sweep over as values. -
elements
()[source]¶ Return the elements of the sweep.
May be lazily evaluated, depending on the type of sweep.
-
mapping
(sim_ids, sweep_id, save=True)[source]¶ Return a labelled array which maps parameters to simulation IDs.
See
parasweep.sweepers.Sweep.mapping()
for argument information. Returns a multidimensional labelled array (using xarray) which maps the parameters to the simulation IDs. The array coordinates correspond to each sweep parameter, while the values contain the simulation IDs. Ifsave=True
, this array will be saved as a netCDF file with the namesim_ids_{sweep_id}.nc
.
-
-
class
parasweep.sweepers.
FilteredCartesianSweep
(sweep_params, filter_func)[source]¶ Bases:
parasweep.sweepers.Sweep
A parameter sweep which uses specified parameter sets.
Parameters: - sweep_params (dict) – A dictionary containing the parameter names as keys and lists of values to sweep over as values.
- filter_func (function) – A boolean function of parameter values; only parameter sets that
return true will be included in the sweep. The arguments of the
function should be named after the corresponding parameters. If not all
the parameters in the sweep are used in the filtering, the
**kwargs
argument should be defined, or else an error will be raised.
-
elements
()[source]¶ Return the elements of the sweep.
May be lazily evaluated, depending on the type of sweep.
-
mapping
(sim_ids, sweep_id, save=True)[source]¶ Return a dictionary which maps simulation IDs to parameter sets.
See
parasweep.sweepers.Sweep.mapping()
for argument information. Ifsave=True
, this dictionary will be saved as a JSON file with the namesim_ids_{sweep_id}.json
.
-
class
parasweep.sweepers.
SetSweep
(param_sets)[source]¶ Bases:
parasweep.sweepers.Sweep
A Cartesian product parameter sweep with filtering.
Parameters: param_sets (list) – A list containing the parameter sets to use in the sweep as dictionaries. -
elements
()[source]¶ Return the elements of the sweep.
May be lazily evaluated, depending on the type of sweep.
-
mapping
(sim_ids, sweep_id, save=True)[source]¶ Return a dictionary which maps simulation IDs to parameter sets.
See
parasweep.sweepers.Sweep.mapping()
for argument information. Ifsave=True
, this dictionary will be saved as a JSON file with the namesim_ids_{sweep_id}.json
.
-
-
class
parasweep.sweepers.
RandomSweep
(sweep_params, length, random_state=None)[source]¶ Bases:
parasweep.sweepers.Sweep
A random parameter sweep.
Each parameter is treated as an independent random variable with a given distribution.
Parameters: - sweep_params (dict) – A dictionary containing the parameter names as keys and SciPy random
variables (i.e., instances of subclasses of
_RandomVariable
, or ofscipy.stats._distn_infrastructure.rv_generic
) as values. - length (int) – The number of sets of random parameters to draw
- random_state (numpy.random.RandomState instance, optional) – If provided, will use the given random state in generating random numbers. By default, it uses the global random state.
-
elements
()[source]¶ Return the elements of the sweep.
May be lazily evaluated, depending on the type of sweep.
-
mapping
(sim_ids, sweep_id, save=True)[source]¶ Return a dictionary which maps simulation IDs to parameter sets.
See
parasweep.sweepers.Sweep.mapping()
for argument information. Ifsave=True
, this dictionary will be saved as a JSON file with the namesim_ids_{sweep_id}.json
.
- sweep_params (dict) – A dictionary containing the parameter names as keys and SciPy random
variables (i.e., instances of subclasses of
parasweep.templates module¶
Template engines for generating configuration files.
-
class
parasweep.templates.
TemplateEngine
[source]¶ Bases:
abc.ABC
Abstract base class for template engines.
Subclasses should implement the
load
andrender
methods. Make sure to implement errors for providing parameters not present in the template, and for using parameters in the template that are not provided.
-
class
parasweep.templates.
PythonFormatTemplate
[source]¶ Bases:
parasweep.templates.TemplateEngine
Template engine using Python’s string formatting.
-
class
parasweep.templates.
MakoTemplate
[source]¶ Bases:
parasweep.templates.TemplateEngine
Template engine using Mako.
Module contents¶
Top-level package for parasweep.
Contributing¶
Contributions are welcome, and they are greatly appreciated! Every little bit helps, and credit will always be given.
You can contribute in many ways:
Types of Contributions¶
Report Bugs¶
Report bugs at https://github.com/eviatarbach/parasweep/issues.
If you are reporting a bug, please include:
- Your operating system name and version.
- Any details about your local setup that might be helpful in troubleshooting.
- Detailed steps to reproduce the bug.
Fix Bugs¶
Look through the GitHub issues for bugs. Anything tagged with “bug” and “help wanted” is open to whoever wants to implement it.
Implement Features¶
Look through the GitHub issues for features. Anything tagged with “enhancement” and “help wanted” is open to whoever wants to implement it.
Write Documentation¶
parasweep could always use more documentation, whether as part of the official parasweep docs, in docstrings, or even on the web in blog posts, articles, and such.
Submit Feedback¶
The best way to send feedback is to file an issue at https://github.com/eviatarbach/parasweep/issues.
If you are proposing a feature:
- Explain in detail how it would work.
- Keep the scope as narrow as possible, to make it easier to implement.
- Remember that this is a volunteer-driven project, and that contributions are welcome :)
Get Started!¶
Ready to contribute? Here’s how to set up parasweep for local development.
Fork the parasweep repo on GitHub.
Clone your fork locally:
$ git clone git@github.com:your_name_here/parasweep.git
Install your local copy into a virtualenv. Assuming you have virtualenvwrapper installed, this is how you set up your fork for local development:
$ mkvirtualenv parasweep $ cd parasweep/ $ python setup.py develop
Create a branch for local development:
$ git checkout -b name-of-your-bugfix-or-feature
Now you can make your changes locally.
When you’re done making changes, check that your changes pass flake8 and the tests:
$ flake8 parasweep tests $ python setup.py test or py.test
To get flake8, just pip install it into your virtualenv.
Commit your changes and push your branch to GitHub:
$ git add . $ git commit -m "Your detailed description of your changes." $ git push origin name-of-your-bugfix-or-feature
Submit a pull request through the GitHub website.
Pull Request Guidelines¶
Before you submit a pull request, check that it meets these guidelines:
- The pull request should include tests.
- If the pull request adds functionality, the docs should be updated. Put your new functionality into a function with a docstring, and add the feature to the list in README.rst.
- The pull request should work for Python 3.
History¶
2021.01 (2021-01-06)¶
- Changing wait option to be True by default
- Minor fixes to Lorenz example
2020.10 (2020-10-27)¶
- Adding option to exclude simulation IDs
- Allowing empty sweep ID
2020.09 (2020-09-02)¶
- Incorporating sweep_id into SequentialNamer (thanks to danielphili)
2020.02 (2020-02-17)¶
- Fixing bug with default sweep_id on Windows (thanks to danielphili)
- Unicode support for PythonFormatTemplate
2019.02.3 (2019-02-20)¶
- Adding SetNamer naming
2019.02.2 (2019-02-18)¶
- Adding process limit for subprocess dispatching
- Adding RandomSweep sweep type
- Adding HashNamer naming
- Clarifying version dependencies
- More examples
2019.02 (2019-02-07)¶
- Separating sweep logic into a separate module
- Adding FilteredCartesianSweep sweep type
- Numerous documentation changes, including many more examples
2019.01 (2019-01-21)¶
- First release on PyPI