Codebase list python-param / d5e2e3c
New upstream snapshot. Debian Janitor 2 years ago
83 changed file(s) with 1690 addition(s) and 7578 deletion(s). Raw diff Collapse all Expand all
+0
-15
.appveyor.yml less more
0 environment:
1 matrix:
2 - TOXENV: py36
3 - TOXENV: py35
4 - TOXENV: py34
5 - TOXENV: py27
6
7 matrix:
8 fast_finish: true
9
10 build: false
11
12 install: C:\Python36\python -m pip install -U tox
13
14 test_script: C:\Python36\scripts\tox
+0
-2
.coveragerc less more
0 [report]
1 omit = param/version.py
+0
-1
.gitattributes less more
0 __init__.py export-subst
+0
-11
.gitignore less more
0 *.py[cod]
1 #*#
2 *~
3 *.egg
4 *.egg-info
5 *.swp
6 *.DS_Store
7 *.so
8 *.o
9 *.out
10 *.lock
+0
-0
.gitmodules less more
(Empty file)
+0
-158
.travis.yml less more
0 sudo: false
1
2 language: python
3
4 # quick hack to determine what tag is (improvements welcomed)
5 # release: ^v(\d+|\.)+[^a-z]\d+$
6 # dev release: ^v(\d+|\.)+[a-z]\d+$
7
8 stages:
9 - lint
10 - test
11 - name: pip_dev_package
12 if: tag =~ ^v(\d+|\.)+[a-z]\d+$
13 - name: pip_package
14 if: tag =~ ^v(\d+|\.)+[^a-z]\d+$
15 - name: conda_dev_package
16 if: tag =~ ^v(\d+|\.)+[a-z]\d+$
17 - name: conda_package
18 if: tag =~ ^v(\d+|\.)+[^a-z]\d+$
19 - name: website_dev
20 if: tag =~ ^v(\d+|\.)+[a-z]\d+$ OR tag = website_dev
21 - name: website_release
22 if: tag =~ ^v(\d+|\.)+[^a-z]\d+$ OR tag = website
23
24
25 jobs:
26 fast_finish: true
27 include:
28 - &default
29 stage: test
30 python: 3.6
31 env: TOX_ENV=py36
32 install:
33 - pip install tox
34 script:
35 - tox -e $TOX_ENV
36
37 - <<: *default
38 python: 3.7-dev
39 env: TOX_ENV=py37
40
41 - <<: *default
42 python: 3.5
43 env: TOX_ENV=py35
44
45 - <<: *default
46 python: 3.4
47 env: TOX_ENV=py34
48
49 - <<: *default
50 python: 2.7
51 env: TOX_ENV=py27
52
53 - <<: *default
54 python: pypy
55 env: TOX_ENV=pypy
56
57 # could consider running with_ipython,numpy over py36 and 27
58
59 - <<: *default
60 env: TOX_ENV=with_ipython
61
62 - <<: *default
63 env: TOX_ENV=with_numpy
64
65 - <<: *default
66 env: TOX_ENV=with_pandas
67
68 - <<: *default
69 env: TOX_ENV=coverage
70
71 - <<: *default
72 stage: lint
73 env: TOX_ENV=flakes
74
75 # TODO: the below packaging sections will be simplified with
76 # doit/pyct (and note that using after_success means no alert to
77 # failure uploading)
78
79 - &conda_default
80 env: LABELS="--label dev"
81 stage: conda_dev_package
82 install:
83 - wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh;
84 - bash miniconda.sh -b -p $HOME/miniconda
85 - export PATH="$HOME/miniconda/bin:$PATH"
86 - conda config --set always_yes yes --set changeps1 no
87 - conda update conda
88 - conda install anaconda-client conda-build
89 script:
90 - conda build conda.recipe/
91 after_success:
92 - anaconda --token $CONDA_UPLOAD_TOKEN upload --user pyviz $LABELS $(conda build --output conda.recipe)
93
94 - <<: *conda_default
95 env: LABELS="--label dev --label main"
96 stage: conda_package
97
98 - <<: *default
99 stage: pip_dev_package
100 deploy:
101 provider: pypi
102 server: https://test.pypi.org/legacy/
103 distributions: "sdist bdist_wheel"
104 on:
105 tags: true
106 user: $TESTPYPI_USER
107 password: $TESTPYPI_PWD
108
109 - <<: *default
110 stage: pip_package
111 deploy:
112 provider: pypi
113 distributions: "sdist bdist_wheel"
114 on:
115 tags: true
116 user: $PYPI_USER
117 password: $PYPI_PWD
118
119 - &website
120 <<: *default
121 addons:
122 apt:
123 packages:
124 - graphviz
125 stage: website_release
126 before_install:
127 - pip install graphviz
128 install:
129 - pip install nbsite sphinx_ioam_theme "tornado<6"
130 - pip install -e .
131 script:
132 # TODO: nbsite commands will be simplified eventually...
133 - nbsite generate-rst --org pyviz --repo param --project-name param
134 - mkdir doc/Reference_Manual && nbsite_generate_modules.py param -d ./doc/Reference_Manual -n param -e tests
135 - nbsite build --examples-assets=''
136 deploy:
137 - provider: pages
138 skip_cleanup: true
139 github_token: $GITHUB_TOKEN
140 local_dir: ./builtdocs
141 fqdn: param.pyviz.org
142 on:
143 tags: true
144 all_branches: true
145
146 - <<: *website
147 stage: website_dev
148 env: DESC="pyviz-dev.github.io/param"
149 deploy:
150 - provider: pages
151 skip_cleanup: true
152 github_token: $GITHUB_TOKEN
153 local_dir: ./builtdocs
154 repo: pyviz-dev/param
155 on:
156 tags: true
157 all_branches: true
0 Copyright (c) 2005-2018, IOAM (ioam.github.com)
0 Copyright (c) 2005-2020, HoloViz team.
11 All rights reserved.
22
33 Redistribution and use in source and binary forms, with or without
1212 documentation and/or other materials provided with the
1313 distribution.
1414
15 * Neither the name of IOAM nor the names of its contributors
16 may be used to endorse or promote products derived from this
17 software without specific prior written permission.
15 * Neither the name of the copyright holder nor the names of any
16 contributors may be used to endorse or promote products derived
17 from this software without specific prior written permission.
1818
1919 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2020 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
0 Metadata-Version: 2.1
1 Name: param
2 Version: None
3 Summary: Make your Python code clearer and more reliable by declaring Parameters.
4 Home-page: http://param.holoviz.org/
5 Author: HoloViz
6 Author-email: developers@holoviz.org
7 Maintainer: HoloViz
8 Maintainer-email: developers@holoviz.org
9 License: BSD
10 Project-URL: Documentation, https://param.holoviz.org/
11 Project-URL: Releases, https://github.com/holoviz/param/releases
12 Project-URL: Bug Tracker, https://github.com/holoviz/param/issues
13 Project-URL: Source Code, https://github.com/holoviz/param
14 Project-URL: Panel Examples, https://panel.holoviz.org/user_guide/Param.html
15 Description: <img src="https://raw.githubusercontent.com/holoviz/param/master/doc/_static/logo_horizontal.png" width=250>
16
17 | | |
18 | --- | --- |
19 | Build Status | [![Linux/MacOS/Windows Build Status](https://github.com/holoviz/param/workflows/pytest/badge.svg)](https://github.com/holoviz/param/actions/workflows/test.yml)
20 | Coverage | [![coveralls](https://coveralls.io/repos/github/holoviz/param/badge.svg?branch=master)](https://coveralls.io/github/holoviz/param?branch=master) |
21 | Latest dev release | [![Github tag](https://img.shields.io/github/v/tag/holoviz/param.svg?label=tag&colorB=11ccbb)](https://github.com/holoviz/param/tags) [![dev-site](https://img.shields.io/website-up-down-green-red/https/pyviz-dev.github.io/param.svg?label=dev%20website)](https://pyviz-dev.github.io/param/) |
22 | Latest release | [![Github release](https://img.shields.io/github/release/holoviz/param.svg?label=tag&colorB=11ccbb)](https://github.com/holoviz/param/releases) [![PyPI version](https://img.shields.io/pypi/v/param.svg?colorB=cc77dd)](https://pypi.python.org/pypi/param) [![param version](https://img.shields.io/conda/v/pyviz/param.svg?colorB=4488ff&style=flat)](https://anaconda.org/pyviz/param) [![conda-forge version](https://img.shields.io/conda/v/conda-forge/param.svg?label=conda%7Cconda-forge&colorB=4488ff)](https://anaconda.org/conda-forge/param) [![defaults version](https://img.shields.io/conda/v/anaconda/param.svg?label=conda%7Cdefaults&style=flat&colorB=4488ff)](https://anaconda.org/anaconda/param) |
23 | Docs | [![gh-pages](https://img.shields.io/github/last-commit/holoviz/param/gh-pages.svg)](https://github.com/holoviz/param/tree/gh-pages) [![site](https://img.shields.io/website-up-down-green-red/https/param.holoviz.org.svg)](https://param.holoviz.org) |
24 | Support | [![Discourse](https://img.shields.io/discourse/status?server=https%3A%2F%2Fdiscourse.holoviz.org)](https://discourse.holoviz.org/) |
25
26 Param is a library providing Parameters: Python attributes extended to have features such as type and range checking, dynamically generated values, documentation strings, default values, etc., each of which is inherited from parent classes if not specified in a subclass.
27
28 Param contains only two required Python files, with no external dependencies, and is provided freely for both non-commercial and commercial use under a BSD license, so that it can easily be included as part of other projects.
29
30 Please see [param's website](https://param.holoviz.org) for official releases, installation instructions, documentation, and examples.
31
32 Platform: Windows
33 Platform: Mac OS X
34 Platform: Linux
35 Classifier: License :: OSI Approved :: BSD License
36 Classifier: Development Status :: 5 - Production/Stable
37 Classifier: Programming Language :: Python :: 2
38 Classifier: Programming Language :: Python :: 2.7
39 Classifier: Programming Language :: Python :: 3
40 Classifier: Programming Language :: Python :: 3.4
41 Classifier: Programming Language :: Python :: 3.5
42 Classifier: Programming Language :: Python :: 3.6
43 Classifier: Programming Language :: Python :: 3.7
44 Classifier: Programming Language :: Python :: 3.8
45 Classifier: Operating System :: OS Independent
46 Classifier: Intended Audience :: Science/Research
47 Classifier: Intended Audience :: Developers
48 Classifier: Natural Language :: English
49 Classifier: Topic :: Scientific/Engineering
50 Classifier: Topic :: Software Development :: Libraries
51 Provides: param
52 Provides: numbergen
53 Requires-Python: >=2.7
54 Description-Content-Type: text/markdown
55 Provides-Extra: all
56 Provides-Extra: doc
57 Provides-Extra: tests
0 <img src="https://raw.githubusercontent.com/holoviz/param/master/doc/_static/logo_horizontal.png" width=250>
1
2 | | |
3 | --- | --- |
4 | Build Status | [![Linux/MacOS/Windows Build Status](https://github.com/holoviz/param/workflows/pytest/badge.svg)](https://github.com/holoviz/param/actions/workflows/test.yml)
5 | Coverage | [![coveralls](https://coveralls.io/repos/github/holoviz/param/badge.svg?branch=master)](https://coveralls.io/github/holoviz/param?branch=master) |
6 | Latest dev release | [![Github tag](https://img.shields.io/github/v/tag/holoviz/param.svg?label=tag&colorB=11ccbb)](https://github.com/holoviz/param/tags) [![dev-site](https://img.shields.io/website-up-down-green-red/https/pyviz-dev.github.io/param.svg?label=dev%20website)](https://pyviz-dev.github.io/param/) |
7 | Latest release | [![Github release](https://img.shields.io/github/release/holoviz/param.svg?label=tag&colorB=11ccbb)](https://github.com/holoviz/param/releases) [![PyPI version](https://img.shields.io/pypi/v/param.svg?colorB=cc77dd)](https://pypi.python.org/pypi/param) [![param version](https://img.shields.io/conda/v/pyviz/param.svg?colorB=4488ff&style=flat)](https://anaconda.org/pyviz/param) [![conda-forge version](https://img.shields.io/conda/v/conda-forge/param.svg?label=conda%7Cconda-forge&colorB=4488ff)](https://anaconda.org/conda-forge/param) [![defaults version](https://img.shields.io/conda/v/anaconda/param.svg?label=conda%7Cdefaults&style=flat&colorB=4488ff)](https://anaconda.org/anaconda/param) |
8 | Docs | [![gh-pages](https://img.shields.io/github/last-commit/holoviz/param/gh-pages.svg)](https://github.com/holoviz/param/tree/gh-pages) [![site](https://img.shields.io/website-up-down-green-red/https/param.holoviz.org.svg)](https://param.holoviz.org) |
9 | Support | [![Discourse](https://img.shields.io/discourse/status?server=https%3A%2F%2Fdiscourse.holoviz.org)](https://discourse.holoviz.org/) |
10
11 Param is a library providing Parameters: Python attributes extended to have features such as type and range checking, dynamically generated values, documentation strings, default values, etc., each of which is inherited from parent classes if not specified in a subclass.
12
13 Param contains only two required Python files, with no external dependencies, and is provided freely for both non-commercial and commercial use under a BSD license, so that it can easily be included as part of other projects.
14
15 Please see [param's website](https://param.holoviz.org) for official releases, installation instructions, documentation, and examples.
+0
-35
README.rst less more
0 |LinuxTests|_ |WinTests|_ |Coverage|_ |PyPIVersion|_ |PyVersion|_ |License|_
1
2 Param
3 =====
4
5 Param is a library providing Parameters: Python attributes extended to
6 have features such as type and range checking, dynamically generated
7 values, documentation strings, default values, etc., each of which is
8 inherited from parent classes if not specified in a subclass.
9
10 Param contains only two required Python files, with no external
11 dependencies, and is provided freely for both non-commercial and
12 commercial use under a BSD license, so that it can easily be included
13 as part of other projects.
14
15 Please see `param's website <http://param.pyviz.org>`_ for
16 official releases, installation instructions, documentation, and examples.
17
18 .. |LinuxTests| image:: https://travis-ci.org/pyviz/param.svg?branch=master
19 .. _LinuxTests: https://travis-ci.org/pyviz/param
20
21 .. |WinTests| image:: https://ci.appveyor.com/api/projects/status/1p5aom8o0tfgok1r?svg=true
22 .. _WinTests: https://ci.appveyor.com/project/pyviz/param/branch/master
23
24 .. |Coverage| image:: https://img.shields.io/coveralls/pyviz/param.svg
25 .. _Coverage: https://coveralls.io/r/pyviz/param?branch=master
26
27 .. |PyPIVersion| image:: http://img.shields.io/pypi/v/param.svg
28 .. _PyPIVersion: https://pypi.python.org/pypi/param
29
30 .. |PyVersion| image:: https://img.shields.io/pypi/pyversions/param.svg
31 .. _PyVersion: https://pypi.python.org/pypi/param
32
33 .. |License| image:: https://img.shields.io/pypi/l/param.svg
34 .. _License: https://pypi.python.org/pypi/param
+0
-40
conda.recipe/meta.yaml less more
0 {% set sdata = load_setup_py_data() %}
1
2 package:
3 name: param
4 version: {{ sdata['version'] }}
5
6 source:
7 path: ..
8
9 build:
10 noarch: python
11 script: python setup.py install --single-version-externally-managed --record=record.txt
12
13 requirements:
14 build:
15 - python
16 - setuptools
17 run:
18 - python {{ sdata['python_requires'] }}
19
20 test:
21 requires:
22 {% for dep in sdata['extras_require']['tests'] %}
23 - {{ dep }}
24 {% endfor %}
25 source_files:
26 # for nose config
27 - setup.cfg
28 - tests
29 imports:
30 - param
31 - numbergen
32 commands:
33 # https://github.com/ioam/param/issues/219
34 - nosetests tests
35
36 about:
37 home: {{ sdata['url'] }}
38 summary: {{ sdata['description'] }}
39 license: {{ sdata['license'] }}
0 python-param (1.11.2a1+git20210817.1.cde53c5-1) UNRELEASED; urgency=low
1
2 * New upstream snapshot.
3
4 -- Debian Janitor <janitor@jelmer.uk> Wed, 18 Aug 2021 20:29:30 -0000
5
06 python-param (1.9.3-2) unstable; urgency=medium
17
28 * Source only upload for migration to testing
doc/_static/favicon.ico less more
Binary diff not shown
doc/_static/logo.png less more
Binary diff not shown
+0
-39
doc/conf.py less more
0 # -*- coding: utf-8 -*-
1
2 from nbsite.shared_conf import *
3
4 project = u'Param'
5 authors = u'PyViz authors'
6 copyright = u'\u00a9 2005-2018, ' + authors
7 description = 'Declarative Python programming using Parameters.'
8
9 import param
10 version = release = param.__version__
11
12 html_static_path += ['_static']
13 html_theme = 'sphinx_ioam_theme'
14 html_theme_options = {
15 'logo':'logo.png',
16 'favicon':'favicon.ico',
17 # 'css':'site.css'
18 }
19
20 _NAV = (
21 ('API', 'Reference_Manual/param'),
22 ('About', 'About'),
23 )
24
25 html_context.update({
26 'PROJECT': project,
27 'DESCRIPTION': description,
28 'AUTHOR': authors,
29 # canonical URL (for search engines); can ignore for local builds
30 'WEBSITE_SERVER': 'https://param.pyviz.org',
31 'VERSION': version,
32 'NAV': _NAV,
33 'LINKS': _NAV,
34 'SOCIAL': (
35 ('Gitter', '//gitter.im/pyviz/pyviz'),
36 ('Github', '//github.com/ioam/param'),
37 )
38 })
+0
-125
doc/historical_release_notes.rst less more
0 ************************
1 Historical release notes
2 ************************
3
4 Note: current release notes are on `GitHub
5 <https://github.com/ioam/param/releases>`_.
6
7 Notable additions, or changes that may require users to alter code,
8 are listed below.
9
10
11 1.4.1 (2016/07)
12 _______________
13
14 * Selector parameters now respect order of options supplied
15 * Allowed softbounds to be accessed like an attribute
16
17 A full list of changes since the previous release is available
18 `on GitHub <https://github.com/ioam/param/compare/v1.4.0...v1.4.1>`_.
19
20
21 1.4.0 (2016/07)
22 _______________
23
24 * Added support for new `ParamNB <https://github.com/ioam/paramnb>`_ project
25 * Added new parameter types Action, FileSelector, and ListSelector
26
27 A full list of changes since the previous release is available
28 `on GitHub <https://github.com/ioam/param/compare/v1.3.2...v1.4.0>`_.
29
30
31 1.3.2 (2015/04)
32 _______________
33
34 * Added Unicode support for param.String.
35 * Minor bugfixes.
36
37 A full list of changes since the previous release is available
38 `on GitHub <https://github.com/ioam/param/compare/v1.3.1...v1.3.2>`_.
39
40
41 1.3.1 (2015/03)
42 _______________
43
44 * Minor bugfix release to restore pre-1.3.0 script_repr behavior
45 (accidentally changed in 1.3.0) and to fix issues with logging.
46 * Param's logging interface now matches that of Python's logging
47 module, making it simpler to use logging (see Python's logging
48 module for details). Note therefore that Param's logging methods (a)
49 no longer call functions that are passed as arguments (instead,
50 Python's logging module does lazy string merges), and (b) no longer
51 automatically combine strings passed as arguments (instead, Python's
52 logging module supports string formatting).
53 * Improved set_param() method, now allowing multiple parameters to be
54 set easily via keyword arguments (as on initialization).
55
56 A full list of changes since the previous release is available
57 `on GitHub <https://github.com/ioam/param/compare/v1.3.0...v1.3.1>`_.
58
59
60 1.3.0 (2015/03)
61 _______________
62
63 * Added 'allow_None' support to all Parameters. Any subclass of
64 Parameter that checks types and/or values should be modified to add
65 appropriate handling of allow_None.
66 * Improved pretty printing (script_repr) of Parameterized instances,
67 and made available via the pprint method. The script_repr name will
68 be removed in a future release.
69 * Added (reproducible) time-dependent random streams
70 (numbergen.TimeAwareRandomState).
71 * Added label and unit parameters to param.Time class.
72 * Improved optional IPython extension.
73
74 A full list of changes since the previous release is available
75 `on GitHub <https://github.com/ioam/param/compare/v1.2.1...v1.3.0>`_.
76
77
78 1.2.1 (2014/06)
79 _______________
80
81 * Minor bugfix release to fix issues with version when param is
82 installed in a foreign git repository
83 * Made version module optional
84 * Improved ClassSelector and ParamOverrides
85
86 A full list of changes since the previous release is available
87 `on GitHub <https://github.com/ioam/param/compare/v1.2.0...v1.2.1>`_.
88
89
90 1.2.0 (2014/06)
91 _______________
92
93 * Added support for Python 3 (thanks to Marco Elver).
94 * Dropped support for Python 2.5.
95 * Added version module.
96 * Added optional numbergen package.
97
98 A full list of changes since the previous release is available
99 `on GitHub <https://github.com/ioam/param/compare/v1.1.0...v1.2.0>`_.
100
101
102 1.1.0 (2014/05)
103 _______________
104
105 * Switched to Python's own logging module.
106 * Improved support for time when using Dynamic parameters.
107 * Optional extension for IPython users.
108
109 A full list of changes since the previous release is available
110 `on GitHub <https://github.com/ioam/param/compare/v1.0.0...v1.1.0>`_.
111
112
113 1.0.0 (2012/07)
114 _______________
115
116 * First standalone release.
117
118
119 Pre-1.0 (2003)
120 ______________
121
122 * Param was originally developed as part of `Topographica
123 <http://ioam.github.io/topographica/>`_, and has been in heavy
124 usage as part of that project since 2003.
+0
-20
doc/index.rst less more
0 ..
1 Originally generated by nbsite (0.4.4a13+gdbf7de7-dirty):
2 nbsite generate-rst --org ioam --project param --repo param --examples-path examples --doc-path doc
3 Will not subsequently be overwritten by nbsite, so can be edited.
4
5 *****
6 Param
7 *****
8
9 .. notebook:: param ../examples/index.ipynb
10 :offset: 0
11
12 .. toctree::
13 :titlesonly:
14 :maxdepth: 2
15
16 Introduction <self>
17 API <Reference_Manual/param>
18 About <About>
19
+0
-19
examples/About.ipynb less more
0 {
1 "cells": [
2 {
3 "cell_type": "markdown",
4 "metadata": {},
5 "source": [
6 "Param is part of [PyViz](http://pyviz.org), a collaborative project to produce a coherent solution to a wide range of Python visualization problems."
7 ]
8 }
9 ],
10 "metadata": {
11 "language_info": {
12 "name": "python",
13 "pygments_lexer": "ipython3"
14 }
15 },
16 "nbformat": 4,
17 "nbformat_minor": 2
18 }
+0
-300
examples/index.ipynb less more
0 {
1 "cells": [
2 {
3 "cell_type": "markdown",
4 "metadata": {},
5 "source": [
6 "Param is a library providing Parameters: Python attributes extended to\n",
7 "have features such as type and range checking, dynamically generated\n",
8 "values, documentation strings, default values, etc., each of which is\n",
9 "inherited from parent classes if not specified in a subclass. Param\n",
10 "lets you program declaratively in Python, by just stating facts about\n",
11 "each of your parameters, and then using them throughout your code.\n",
12 "With Parameters, error checking will be automatic, which eliminates\n",
13 "huge amounts of boilerplate code that would otherwise be required to\n",
14 "verify or test user-supplied values.\n",
15 "\n",
16 "Param-based programs tend to contain much less code than other Python\n",
17 "programs, instead just having easily readable and maintainable\n",
18 "manifests of Parameters for each object or function. This way your\n",
19 "remaining code can be much simpler and clearer, while users can also\n",
20 "easily see how to use it properly."
21 ]
22 },
23 {
24 "cell_type": "markdown",
25 "metadata": {},
26 "source": [
27 "# What is a Parameter?\n",
28 "\n",
29 "A Parameter is a special type of Python attribute extended to have features such as type and range checking, dynamically generated values, documentation strings, default values, etc., each of which is inherited from parent classes if not specified in a subclass.\n",
30 "\n",
31 "```python\n",
32 ">>> import param,random\n",
33 ">>> class A(param.Parameterized):\n",
34 "... a = param.Number(0.5,bounds=(0,1),doc=\"Probability that...\")\n",
35 "... b = param.Boolean(False,doc=\"Enable feature...\")\n",
36 "\n",
37 ">>> class B(A):\n",
38 "... b = param.Boolean(True)\n",
39 "\n",
40 ">>> x = B(a=lambda: random.uniform(0,1))\n",
41 "\n",
42 ">>> x.a\n",
43 "0.37053399325641945\n",
44 "\n",
45 ">>> x.a\n",
46 "0.64907392300071842\n",
47 "```\n",
48 "\n",
49 "## Parameters provide optional range and type checking\n",
50 "\n",
51 "```python\n",
52 ">>> x.a=5\n",
53 "[...]\n",
54 "ValueError: Parameter 'a' must be at most 1\n",
55 "\n",
56 ">>> x.a=\"0.5\"\n",
57 "[...]\n",
58 "ValueError: Parameter 'a' only takes numeric values\n",
59 "```\n",
60 "\n",
61 "## Parameters have docstrings\n",
62 "\n",
63 "```python\n",
64 ">>> help(x)\n",
65 "[...]\n",
66 "class B(A)\n",
67 "[...]\n",
68 " Data descriptors defined here:\n",
69 " b\n",
70 " Enable feature...\n",
71 "[...]\n",
72 " Data descriptors inherited from A:\n",
73 " a\n",
74 " Probability that...\n",
75 "```\n",
76 "\n",
77 "## Param is lightweight\n",
78 "\n",
79 "Param consists of two required BSD-licensed Python files, with no\n",
80 "dependencies outside of the standard library, and so it can easily be\n",
81 "included as part of larger projects without adding external dependencies.\n",
82 "\n",
83 "\n",
84 "## Parameters make GUI programming simpler\n",
85 "\n",
86 "Parameters make it simple to generate GUIs by separating your semantic\n",
87 "information (what is this parameter? what type can it have? does it\n",
88 "have bounds?) from anything to do with a particular GUI library. To\n",
89 "use Parameters in a particular GUI toolkit, you just need to write a\n",
90 "simple set of interfaces that indicate how a given Parameter type\n",
91 "should be displayed, and what widgets to generate for it. Currently,\n",
92 "interfaces are provided for use in Jupyter Notebooks ([ParamNB]\n",
93 "(https://github.com/ioam/paramnb)) \n",
94 "or in Tk ([ParamTk](http://ioam.github.com/paramtk)), both of which\n",
95 "make it simple to provide a property sheet that automatically\n",
96 "generates a set of widgets for viewing and editing an object's\n",
97 "Parameters.\n",
98 "\n",
99 "\n",
100 "## Optional dynamic parameter values using `numbergen`\n",
101 "\n",
102 "Providing random or other types of varying values for parameters can\n",
103 "be tricky, because unnamed (\"lambda\") functions as used above cannot\n",
104 "easily be pickled, causing problems for people who wish to store\n",
105 "Parameterized objects containing random state. To avoid users having\n",
106 "to write a separate function for each random value, Param includes an\n",
107 "optional set of value-generating objects that are easily configured\n",
108 "and support pickling. These objects are available if you import the\n",
109 "optional `numbergen` module. If you wish to use numbergen, the above\n",
110 "example can be rewritten as:\n",
111 "\n",
112 "```python\n",
113 ">>> import param,numbergen\n",
114 ">>> class A(param.Parameterized):\n",
115 "... a = param.Number(0.5,bounds=(0,1),doc=\"Probability that...\")\n",
116 "... b = param.Boolean(False,doc=\"Enable feature...\")\n",
117 "\n",
118 ">>> class B(A):\n",
119 "... b = param.Boolean(True)\n",
120 "\n",
121 ">>> x = B(a=numbergen.UniformRandom())\n",
122 "``` \n",
123 "\n",
124 "Numbergen objects support the usual arithmetic operations like `+`, `-`,\n",
125 "`*`, `/`, `//`, `%`, `**`, and `abs()`, and so they can be freely combined with\n",
126 "each other or with mathematical constants:\n",
127 "\n",
128 "```python\n",
129 ">>> y = B(a=2.0*numbergen.UniformRandom()/(numbergen.NormalRandom()+1.5))\n",
130 "```\n",
131 "\n",
132 "Note that unlike the lambda-function approach, all varying numbergen\n",
133 "objects respect `param.Dynamic.time_fn`, e.g. to ensure that new\n",
134 "values will be generated only when Param's time has changed. \n",
135 "Parameterized programs can define a time function to maintain a\n",
136 "logical/simulated time, such as the state of a simulator, which\n",
137 "allows all Parameter values to be kept synchronized without\n",
138 "any special coordination code.\n",
139 "\n"
140 ]
141 },
142 {
143 "cell_type": "markdown",
144 "metadata": {},
145 "source": [
146 "# Installation\n",
147 "\n",
148 "Param has no required dependencies outside of Python's standard\n",
149 "library.\n",
150 "\n",
151 "Official releases of Param are available on\n",
152 "[Anaconda](https://anaconda.org/ioam/param) and\n",
153 "[PyPI](http://pypi.python.org/pypi/param), and can be installed via\n",
154 "`conda install -c ioam param`, `pip install --user param`, or \n",
155 "`pip install param`.\n",
156 "\n",
157 "The very latest changes can be obtained via `conda install -c pyviz/label/dev\n",
158 "param` or `pip install\n",
159 "https://github.com/ioam/param/archive/master.zip`.\n",
160 "\n",
161 "For development, the [git repository](http://github.com/ioam/param)\n",
162 "can be cloned and then 'develop installed' (`pip install -e .` or\n",
163 "`python setup.py develop`). Tests can be run via [tox]\n",
164 "(https://tox.readthedocs.io/en/latest/): `tox` for all tests, or\n",
165 "e.g. `tox -e coverage` to run unit tests with coverage for the\n",
166 "currently active python. Alternatively, unit tests can be run via\n",
167 "`nosetests` (after installing [nose](http://nose.readthedocs.io/en/latest)."
168 ]
169 },
170 {
171 "cell_type": "markdown",
172 "metadata": {},
173 "source": [
174 "# Comparison to other packages\n",
175 "\n",
176 "Param was first developed in 2003, in the context of the Topographica brain simulator project, and\n",
177 "was made into a separate package in 2012. In the interim other parameter libraries were\n",
178 "developed, including [Traits](http://code.enthought.com/projects/traits) and \n",
179 "[Traitlets](https://github.com/ipython/traitlets/). These libraries have broadly similar goals,\n",
180 "but each differs in important ways:\n",
181 "\n",
182 "**Dependencies**: \n",
183 " Traits is a much more heavyweight solution, requiring \n",
184 " installation of a large suite of tools, including C code, which makes it difficult to include in \n",
185 " separate projects. In contrast, Param and Traitlets are both pure Python projects, with minimal dependencies. \n",
186 "\n",
187 "**GUI toolkits**: \n",
188 " Although any of the packages could in principle add support for any\n",
189 " GUI toolkit, the toolkits actually provided differ: Traits (via the\n",
190 " separate TraitsUI package) supports wxWidgets and QT, while Param\n",
191 " supports Tkinter (via the separate ParamTk package) and\n",
192 " browser-based IPython widgets (via the separate ParamNB package),\n",
193 " while Traitlets only supports IPython widgets.\n",
194 "\n",
195 " ```python\n",
196 " >>> from time import time\n",
197 " >>> import traitlets as tr\n",
198 " >>> class A(tr.HasTraits):\n",
199 " ... instantiation_time = tr.Float()\n",
200 " ... @tr.default('instantiation_time')\n",
201 " ... def _look_up_time(self):\n",
202 " ... return time()\n",
203 " ... \n",
204 " >>> a=A()\n",
205 " >>> a.instantiation_time\n",
206 " 1475587151.967874\n",
207 " >>> a.instantiation_time\n",
208 " 1475587151.967874\n",
209 " >>> b=A()\n",
210 " >>> b.instantiation_time\n",
211 " 1475587164.750875\n",
212 " ```\n",
213 "\n",
214 "**Dynamic values**:\n",
215 " Param, Traits, and Traitlets all allow any Python expression to be\n",
216 " supplied for initializing parameters, allowing parameter default\n",
217 " values to be computed at the time a module is first loaded. Traits\n",
218 " and Traitlets also allow a class author to add code for a given\n",
219 " parameter to compute a default value on first access. Param does\n",
220 " not provide any special support for programmatic default values,\n",
221 " instead allowing fully dynamic values for *any* numeric Parameter\n",
222 " instance:\n",
223 "\n",
224 " ```python\n",
225 " >>> from time import time\n",
226 " >>> import param\n",
227 " >>> class A(param.Parameterized):\n",
228 " ... val=param.Number(0)\n",
229 " ... \n",
230 " >>> a=A()\n",
231 " >>> a.val\n",
232 " 0\n",
233 " >>> a.val=lambda:time()\n",
234 " >>> a.val\n",
235 " 1475587455.437027\n",
236 " >>> a.val\n",
237 " 1475587456.501314\n",
238 " ```\n",
239 " \n",
240 " Note that here it is the *user* of a Parameterized class, not the\n",
241 " author of the class, that decides whether any particular value is\n",
242 " dynamic, without writing any new methods or other code. All the\n",
243 " usual type checking, etc. is done on dynamic values when they are\n",
244 " computed, and so the rest of the code does not need to know or care\n",
245 " whether the user has set a particular parameter to a dynamic value.\n",
246 " This approach provides an enormous amount of power to the user,\n",
247 " without making the code more complex.\n",
248 "\n",
249 "**On_change callbacks**\n",
250 " Traitlets and Traits allow the author of a HasTraits-derived class\n",
251 " to specify code to run when a specific parameter used in that class\n",
252 " instance is modified. Param supports similar capabilities, but not\n",
253 " at the Parameterized class level, only at the Parameter class level\n",
254 " or as part of ParamNB. I.e., a class author needs to first write a\n",
255 " new Parameter class, adding methods to implement checking on\n",
256 " changes, and then add it to a Parameterized class, or else such\n",
257 " functionality can be added as callbacks at the whole-object level,\n",
258 " using ParamNB. Each approach has advantages and disadvantages, and\n",
259 " per-parameter on_change callbacks could be added in the future if\n",
260 " there are clear use cases.\n",
261 "\n",
262 "All of these packages also overlap in functionality with Python\n",
263 "properties, which were added to the language after Traits and Param\n",
264 "were developed. Like parameters and traits, properties act like\n",
265 "attributes with possible method-like actions, and so they can all be\n",
266 "used to provide the same user-visible functionality. However,\n",
267 "implementing Param/Traits-like functionality using properties would\n",
268 "require vastly more code (multiple method definitions for *every*\n",
269 "parameter in a class), and so in practice Parameters and Traits are\n",
270 "much more practical for the use cases that they cover.\n",
271 " "
272 ]
273 },
274 {
275 "cell_type": "markdown",
276 "metadata": {},
277 "source": [
278 "# Release notes\n",
279 "\n",
280 "Recent release notes are available on [GitHub](https://github.com/ioam/param/releases).\n",
281 "\n",
282 "For older releases, see our [historical release notes](historical_release_notes.html).\n",
283 "\n",
284 "\n",
285 "# Support\n",
286 "\n",
287 "Questions and comments are welcome at https://github.com/ioam/param/issues."
288 ]
289 }
290 ],
291 "metadata": {
292 "language_info": {
293 "name": "python",
294 "pygments_lexer": "ipython3"
295 }
296 },
297 "nbformat": 4,
298 "nbformat_minor": 2
299 }
201201
202202 I32 = 4294967296 # Maximum 32 bit unsigned int (i.e. 'I') value
203203 if isinstance(val, int):
204 numer, denom = val, 1
204 numer, denom = val, 1
205205 elif isinstance(val, fractions.Fraction):
206206 numer, denom = val.numerator, val.denominator
207207 elif hasattr(val, 'numer'):
0 {"version_string": "None"}
0 from __future__ import print_function
01 """
12 Parameters are a kind of class attribute allowing special behavior,
23 including dynamically generated parameter values, documentation
2829 descendents, get_logger, instance_descriptor, basestring)
2930
3031 from .parameterized import (batch_watch, depends, output, # noqa: api import
31 discard_events, edit_constant)
32 discard_events, edit_constant, instance_descriptor)
3233 from .parameterized import logging_level # noqa: api import
3334 from .parameterized import shared_parameters # noqa: api import
3435
4041 # only two required files.
4142 try:
4243 from .version import Version
43 __version__ = str(Version(fpath=__file__, archive_commit="9123ba0", reponame="param"))
44 __version__ = str(Version(fpath=__file__, archive_commit="$Format:%h$", reponame="param"))
4445 except:
4546 __version__ = "0.0.0+unknown"
4647
220221 supplied parameters, inheriting from the specified base(s).
221222 """
222223 if not (isinstance(bases, list) or isinstance(bases, tuple)):
223 bases=[bases]
224 bases=[bases]
224225 return type(name, tuple(bases), params)
225226
226227
702703
703704 def identity_hook(obj,val): return val
704705
706 def get_soft_bounds(bounds, softbounds):
707 """
708 For each soft bound (upper and lower), if there is a defined bound
709 (not equal to None) and does not exceed the hard bound, then it is
710 returned. Otherwise it defaults to the hard bound. The hard bound
711 could still be None.
712 """
713 if bounds is None:
714 hl, hu = (None, None)
715 else:
716 hl, hu = bounds
717
718 if softbounds is None:
719 sl, su = (None, None)
720 else:
721 sl, su = softbounds
722
723 if sl is None or (hl is not None and sl<hl):
724 l = hl
725 else:
726 l = sl
727
728 if su is None or (hu is not None and su>hu):
729 u = hu
730 else:
731 u = su
732
733 return (l, u)
705734
706735
707736 class Number(Dynamic):
749778
750779 """
751780
752 __slots__ = ['bounds','_softbounds','inclusive_bounds','set_hook', 'step']
753
754 def __init__(self,default=0.0,bounds=None,softbounds=None,
781 __slots__ = ['bounds', 'softbounds', 'inclusive_bounds', 'set_hook', 'step']
782
783 def __init__(self, default=0.0, bounds=None, softbounds=None,
755784 inclusive_bounds=(True,True), step=None, **params):
756785 """
757786 Initialize this parameter object and store the bounds.
758787
759788 Non-dynamic default values are checked against the bounds.
760789 """
761 super(Number,self).__init__(default=default,**params)
790 super(Number,self).__init__(default=default, **params)
762791
763792 self.set_hook = identity_hook
764793 self.bounds = bounds
765794 self.inclusive_bounds = inclusive_bounds
766 self._softbounds = softbounds
795 self.softbounds = softbounds
767796 self.step = step
768797 self._validate(default)
769798
770
771 def __get__(self,obj,objtype):
799 def __get__(self, obj, objtype):
772800 """
773801 Same as the superclass's __get__, but if the value was
774802 dynamically generated, check the bounds.
775803 """
776 result = super(Number,self).__get__(obj,objtype)
804 result = super(Number, self).__get__(obj, objtype)
777805 # CEBALERT: results in extra lookups (_value_is_dynamic() is
778806 # also looking up 'result' - should just pass it in). Note
779807 # that this method is called often.
780 if self._value_is_dynamic(obj,objtype): self._validate(result)
808 if self._value_is_dynamic(obj, objtype):
809 self._validate(result)
781810 return result
782
783 # Allow softbounds to be used like a normal attribute, as it
784 # probably should have been already (not _softbounds)
785 @property
786 def softbounds(self): return self._softbounds
787
788 @softbounds.setter
789 def softbounds(self,value): self._softbounds = value
790
791811
792812 def set_in_bounds(self,obj,val):
793813 """
799819 bounded_val = self.crop_to_bounds(val)
800820 else:
801821 bounded_val = val
802 super(Number,self).__set__(obj,bounded_val)
803
822 super(Number, self).__set__(obj, bounded_val)
804823
805824 # CEBERRORALERT: doesn't take account of exclusive bounds; see
806825 # https://github.com/ioam/param/issues/80.
807 def crop_to_bounds(self,val):
826 def crop_to_bounds(self, val):
808827 """
809828 Return the given value cropped to be within the hard bounds
810829 for this parameter.
836855
837856 else:
838857 # non-numeric value sent in: reverts to default value
839 return self.default
858 return self.default
840859
841860 return val
842861
843
844 def _checkBounds(self, val):
845
846 if self.bounds is not None:
847 vmin,vmax = self.bounds
848 incmin,incmax = self.inclusive_bounds
849
850 # Could simplify: see https://github.com/ioam/param/issues/83
851 if vmax is not None:
852 if incmax is True:
853 if not val <= vmax:
854 raise ValueError("Parameter '%s' must be at most %s"%(self.name,vmax))
855 else:
856 if not val < vmax:
857 raise ValueError("Parameter '%s' must be less than %s"%(self.name,vmax))
858
859 if vmin is not None:
860 if incmin is True:
861 if not val >= vmin:
862 raise ValueError("Parameter '%s' must be at least %s"%(self.name,vmin))
863 else:
864 if not val > vmin:
865 raise ValueError("Parameter '%s' must be greater than %s"%(self.name,vmin))
866
867
862 def _validate_bounds(self, val, bounds, inclusive_bounds):
863 if bounds is None or (val is None and self.allow_None) or callable(val):
864 return
865 vmin, vmax = bounds
866 incmin, incmax = inclusive_bounds
867 if vmax is not None:
868 if incmax is True:
869 if not val <= vmax:
870 raise ValueError("Parameter %r must be at most %s, "
871 "not %s." % (self.name, vmax, val))
872 else:
873 if not val < vmax:
874 raise ValueError("Parameter %r must be less than %s, "
875 "not %s." % (self.name, vmax, val))
876
877 if vmin is not None:
878 if incmin is True:
879 if not val >= vmin:
880 raise ValueError("Parameter %r must be at least %s, "
881 "not %s." % (self.name, vmin, val))
882 else:
883 if not val > vmin:
884 raise ValueError("Parameter %r must be greater than %s, "
885 "not %s." % (self.name, vmin, val))
886
887 def _validate_value(self, val, allow_None):
888 if (allow_None and val is None) or callable(val):
889 return
890
891 if not _is_number(val):
892 raise ValueError("Parameter %r only takes numeric values, "
893 "not type %r." % (self.name, type(val)))
894
895 def _validate_step(self, val, step):
896 if step is not None and not _is_number(step):
897 raise ValueError("Step parameter can only be None or a "
898 "numeric value, not type %r." % type(step))
868899
869900 def _validate(self, val):
870901 """
871902 Checks that the value is numeric and that it is within the hard
872903 bounds; if not, an exception is raised.
873904 """
874 if callable(val):
875 return val
876
877 if self.allow_None and val is None:
878 return
879
880 if not _is_number(val):
881 raise ValueError("Parameter '%s' only takes numeric values"%(self.name))
882
883 if self.step is not None and not _is_number(self.step):
884 raise ValueError("Step parameter can only be None or a numeric value")
885
886 self._checkBounds(val)
887
905 self._validate_value(val, self.allow_None)
906 self._validate_step(val, self.step)
907 self._validate_bounds(val, self.bounds, self.inclusive_bounds)
888908
889909 def get_soft_bounds(self):
890 """
891 For each soft bound (upper and lower), if there is a defined bound (not equal to None)
892 then it is returned, otherwise it defaults to the hard bound. The hard bound could still be None.
893 """
894 if self.bounds is None:
895 hl,hu=(None,None)
896 else:
897 hl,hu=self.bounds
898
899 if self._softbounds is None:
900 sl,su=(None,None)
901 else:
902 sl,su=self._softbounds
903
904
905 if sl is None: l = hl
906 else: l = sl
907
908 if su is None: u = hu
909 else: u = su
910
911 return (l,u)
912
910 return get_soft_bounds(self.bounds, self.softbounds)
913911
914912 def __setstate__(self,state):
915913 if 'step' not in state:
916914 state['step'] = None
917915
918 super(Number,self).__setstate__(state)
916 super(Number, self).__setstate__(state)
919917
920918
921919
922920 class Integer(Number):
923921 """Numeric Parameter required to be an Integer"""
924922
925 def __init__(self,default=0,**params):
926 Number.__init__(self,default=default,**params)
927
928 def _validate(self, val):
929 if callable(val): return
930
931 if self.allow_None and val is None:
932 return
933
934 if not isinstance(val,int):
935 raise ValueError("Parameter '%s' must be an integer."%self.name)
936
937 if self.step is not None and not isinstance(self.step, int):
938 raise ValueError("Step parameter can only be None or an integer value")
939
940
941 self._checkBounds(val)
923 def __init__(self, default=0, **params):
924 Number.__init__(self, default=default, **params)
925
926 def _validate_value(self, val, allow_None):
927 if callable(val):
928 return
929
930 if allow_None and val is None:
931 return
932
933 if not isinstance(val, int):
934 raise ValueError("Integer parameter %r must be an integer, "
935 "not type %r." % (self.name, type(val)))
936
937 def _validate_step(self, val, step):
938 if step is not None and not isinstance(step, int):
939 raise ValueError("Step parameter can only be None or an "
940 "integer value, not type %r" % type(step))
942941
943942
944943
945944 class Magnitude(Number):
946945 """Numeric Parameter required to be in the range [0.0-1.0]."""
947946
948 def __init__(self,default=1.0,softbounds=None,**params):
949 Number.__init__(self,default=default,bounds=(0.0,1.0),softbounds=softbounds,**params)
947 def __init__(self, default=1.0, softbounds=None, **params):
948 Number.__init__(self, default=default, bounds=(0.0,1.0), softbounds=softbounds, **params)
950949
951950
952951
955954
956955 __slots__ = ['bounds']
957956
958 # CB: bounds have no effect; see https://github.com/ioam/param/issues/82
959 def __init__(self,default=False,bounds=(0,1),**params):
957 # CB: bounds have no effect; see https://github.com/holoviz/param/issues/82
958 def __init__(self, default=False, bounds=(0,1), **params):
960959 self.bounds = bounds
961 super(Boolean, self).__init__(default=default,**params)
962
963 def _validate(self, val):
964 if self.allow_None:
965 if not isinstance(val,bool) and val is not None:
966 raise ValueError("Boolean '%s' only takes a Boolean value or None."
967 %self.name)
968
969 if val is not True and val is not False and val is not None:
970 raise ValueError("Boolean '%s' must be True, False, or None."%self.name)
971 else:
972 if not isinstance(val,bool):
973 raise ValueError("Boolean '%s' only takes a Boolean value."%self.name)
974
975 if val is not True and val is not False:
976 raise ValueError("Boolean '%s' must be True or False."%self.name)
977 super(Boolean, self)._validate(val)
960 super(Boolean, self).__init__(default=default, **params)
961
962 def _validate_value(self, val, allow_None):
963 if allow_None:
964 if not isinstance(val, bool) and val is not None:
965 raise ValueError("Boolean parameter %r only takes a "
966 "Boolean value or None, not %s."
967 % (self.name, val))
968 elif not isinstance(val, bool):
969 raise ValueError("Boolean parameter %r must be True or False, "
970 "not %s." % (self.name, val))
978971
979972
980973
983976
984977 __slots__ = ['length']
985978
986 def __init__(self,default=(0,0),length=None,**params):
979 def __init__(self, default=(0,0), length=None, **params):
987980 """
988981 Initialize a tuple parameter with a fixed length (number of
989982 elements). The length is determined by the initial default
990983 value, if any, and must be supplied explicitly otherwise. The
991984 length is not allowed to change after instantiation.
992985 """
993 super(Tuple,self).__init__(default=default,**params)
986 super(Tuple,self).__init__(default=default, **params)
994987 if length is None and default is not None:
995988 self.length = len(default)
996989 elif length is None and default is None:
1000993 self.length = length
1001994 self._validate(default)
1002995
996 def _validate_value(self, val, allow_None):
997 if val is None and allow_None:
998 return
999
1000 if not isinstance(val, tuple):
1001 raise ValueError("Tuple parameter %r only takes a tuple value, "
1002 "not %r." % (self.name, type(val)))
1003
1004 def _validate_length(self, val, length):
1005 if val is None and self.allow_None:
1006 return
1007
1008 if not len(val) == length:
1009 raise ValueError("Tuple parameter %r is not of the correct "
1010 "length (%d instead of %d)." %
1011 (self.name, len(val), length))
10031012
10041013 def _validate(self, val):
1005 if val is None and self.allow_None:
1006 return
1007
1008 if not isinstance(val,tuple):
1009 raise ValueError("Tuple '%s' only takes a tuple value."%self.name)
1010
1011 if not len(val)==self.length:
1012 raise ValueError("%s: tuple is not of the correct length (%d instead of %d)." %
1013 (self.name,len(val),self.length))
1014
1014 self._validate_value(val, self.allow_None)
1015 self._validate_length(val, self.length)
1016
1017 @classmethod
1018 def serialize(cls, value):
1019 return list(value) # As JSON has no tuple representation
1020
1021 @classmethod
1022 def deserialize(cls, value):
1023 return tuple(value) # As JSON has no tuple representation
10151024
10161025
10171026 class NumericTuple(Tuple):
10181027 """A numeric tuple Parameter (e.g. (4.5,7.6,3)) with a fixed tuple length."""
10191028
1020 def _validate(self, val):
1021 super(NumericTuple, self)._validate(val)
1022 if not (self.allow_None and val is None):
1023 for n in val:
1024 if not _is_number(n):
1025 raise ValueError("%s: tuple element is not numeric: %s." %
1026 (self.name,str(n)))
1027
1029 def _validate_value(self, val, allow_None):
1030 super(NumericTuple, self)._validate_value(val, allow_None)
1031 if allow_None and val is None:
1032 return
1033 for n in val:
1034 if _is_number(n):
1035 continue
1036 raise ValueError("NumericTuple parameter %r only takes numeric "
1037 "values, not type %r." % (self.name, type(n)))
10281038
10291039
10301040 class XYCoordinates(NumericTuple):
10311041 """A NumericTuple for an X,Y coordinate."""
10321042
1033 def __init__(self,default=(0.0,0.0),**params):
1034 super(XYCoordinates,self).__init__(default=default,length=2,**params)
1035
1043 def __init__(self, default=(0.0, 0.0), **params):
1044 super(XYCoordinates,self).__init__(default=default, length=2, **params)
10361045
10371046
10381047 class Callable(Parameter):
10451054 2.4, so instantiate must be False for those values.
10461055 """
10471056
1048 def _validate(self, val):
1049 if not (self.allow_None and val is None) and (not callable(val)):
1050 raise ValueError("Callable '%s' only takes a callable object."%self.name)
1051 super(Callable, self)._validate(val)
1052
1057 def _validate_value(self, val, allow_None):
1058 if (allow_None and val is None) or callable(val):
1059 return
1060
1061 raise ValueError("Callable parameter %r only takes a callable object, "
1062 "not objects of type %r." % (self.name, type(val)))
10531063
10541064
10551065 class Action(Callable):
10671077 return False
10681078
10691079
1070
10711080 # CEBALERT: this should be a method of ClassSelector.
10721081 def concrete_descendents(parentclass):
10731082 """
10811090 """
10821091 return dict((c.__name__,c) for c in descendents(parentclass)
10831092 if not _is_abstract(c))
1084
10851093
10861094
10871095 class Composite(Parameter):
10941102 in the order specified. Likewise, setting the parameter takes a
10951103 sequence of values and sets the value of the constituent
10961104 attributes.
1097 """
1098
1099 __slots__=['attribs','objtype']
1100
1101 def __init__(self,attribs=None,**kw):
1105
1106 This Parameter type has not been tested with watchers and
1107 dependencies, and may not support them properly.
1108 """
1109
1110 __slots__ = ['attribs', 'objtype']
1111
1112 def __init__(self, attribs=None, **kw):
11021113 if attribs is None:
11031114 attribs = []
1104 super(Composite,self).__init__(default=None,**kw)
1115 super(Composite, self).__init__(default=None, **kw)
11051116 self.attribs = attribs
11061117
1107 def __get__(self,obj,objtype):
1118 def __get__(self, obj, objtype):
11081119 """
11091120 Return the values of all the attribs, as a list.
11101121 """
11111122 if obj is None:
1112 return [getattr(objtype,a) for a in self.attribs]
1123 return [getattr(objtype, a) for a in self.attribs]
11131124 else:
1114 return [getattr(obj,a) for a in self.attribs]
1125 return [getattr(obj, a) for a in self.attribs]
1126
1127 def _validate_attribs(self, val, attribs):
1128 if len(val) == len(attribs):
1129 return
1130 raise ValueError("Compound parameter %r got the wrong number "
1131 "of values (needed %d, but got %d)." %
1132 (self.name, len(attribs), len(val)))
11151133
11161134 def _validate(self, val):
1117 assert len(val) == len(self.attribs),"Compound parameter '%s' got the wrong number of values (needed %d, but got %d)." % (self.name,len(self.attribs),len(val))
1135 self._validate_attribs(val, self.attribs)
11181136
11191137 def _post_setter(self, obj, val):
11201138 if obj is None:
1121 for a,v in zip(self.attribs,val):
1122 setattr(self.objtype,a,v)
1139 for a, v in zip(self.attribs, val):
1140 setattr(self.objtype, a, v)
11231141 else:
1124 for a,v in zip(self.attribs,val):
1125 setattr(obj,a,v)
1142 for a, v in zip(self.attribs, val):
1143 setattr(obj, a, v)
11261144
11271145
11281146 class SelectorBase(Parameter):
11381156 raise NotImplementedError("get_range() must be implemented in subclasses.")
11391157
11401158
1141 class ObjectSelector(SelectorBase):
1159 class Selector(SelectorBase):
11421160 """
11431161 Parameter whose value must be one object from a list of possible objects.
1162
1163 By default, if no default is specified, picks the first object from
1164 the provided set of objects, as long as the objects are in an
1165 ordered data collection.
11441166
11451167 check_on_set restricts the value to be among the current list of
11461168 objects. By default, if objects are initially supplied,
11611183 up from the object value.
11621184 """
11631185
1164 __slots__ = ['objects','compute_default_fn','check_on_set','names']
1165
1166 # ObjectSelector is usually used to allow selection from a list of
1186 __slots__ = ['objects', 'compute_default_fn', 'check_on_set', 'names']
1187
1188 # Selector is usually used to allow selection from a list of
11671189 # existing objects, therefore instantiate is False by default.
1168 def __init__(self,default=None,objects=None,instantiate=False,
1169 compute_default_fn=None,check_on_set=None,allow_None=None,**params):
1190 def __init__(self, objects=None, default=None, instantiate=False,
1191 compute_default_fn=None, check_on_set=None,
1192 allow_None=None, empty_default=False, **params):
1193
1194 autodefault = None
1195 if objects:
1196 if is_ordered_dict(objects):
1197 autodefault = list(objects.values())[0]
1198 elif isinstance(objects, dict):
1199 main.param.warning("Parameter default value is arbitrary due to "
1200 "dictionaries prior to Python 3.6 not being "
1201 "ordered; should use an ordered dict or "
1202 "supply an explicit default value.")
1203 autodefault = list(objects.values())[0]
1204 elif isinstance(objects, list):
1205 autodefault = objects[0]
1206
1207 default = autodefault if (not empty_default and default is None) else default
1208
11701209 if objects is None:
11711210 objects = []
11721211 if isinstance(objects, collections_abc.Mapping):
11781217 self.compute_default_fn = compute_default_fn
11791218
11801219 if check_on_set is not None:
1181 self.check_on_set=check_on_set
1182 elif len(objects)==0:
1183 self.check_on_set=False
1220 self.check_on_set = check_on_set
1221 elif len(objects) == 0:
1222 self.check_on_set = False
11841223 else:
1185 self.check_on_set=True
1186
1187 super(ObjectSelector,self).__init__(default=default,instantiate=instantiate,
1188 **params)
1224 self.check_on_set = True
1225
1226 super(Selector,self).__init__(
1227 default=default, instantiate=instantiate, **params)
11891228 # Required as Parameter sets allow_None=True if default is None
11901229 self.allow_None = allow_None
11911230 if default is not None and self.check_on_set is True:
11921231 self._validate(default)
11931232
1194
11951233 # CBNOTE: if the list of objects is changed, the current value for
11961234 # this parameter in existing POs could be out of the new range.
11971235
12041242 no longer None).
12051243 """
12061244 if self.default is None and callable(self.compute_default_fn):
1207 self.default=self.compute_default_fn()
1245 self.default = self.compute_default_fn()
12081246 if self.default not in self.objects:
12091247 self.objects.append(self.default)
12101248
1211
12121249 def _validate(self, val):
12131250 """
12141251 val must be None or one of the objects in self.objects.
12181255 return
12191256
12201257 if not (val in self.objects or (self.allow_None and val is None)):
1221 # CEBALERT: can be called before __init__ has called
1222 # super's __init__, i.e. before attrib_name has been set.
1223 try:
1224 attrib_name = self.name
1225 except AttributeError:
1258 # This method can be called before __init__ has called
1259 # super's __init__, so there may not be any name set yet.
1260 if (hasattr(self, "name") and self.name):
1261 attrib_name = " " + self.name
1262 else:
12261263 attrib_name = ""
12271264
12281265 items = []
12371274 limiter = ', ...]'
12381275 break
12391276 items = '[' + ', '.join(items) + limiter
1240 raise ValueError("%s not in Parameter %s's list of possible objects, "
1241 "valid options include %s"%(val,attrib_name, items))
1277 raise ValueError("%s not in parameter%s's list of possible objects, "
1278 "valid options include %s" % (val, attrib_name, items))
12421279
12431280 def _ensure_value_is_in_objects(self,val):
12441281 """
12471284 to check each item instead.
12481285 """
12491286 if not (val in self.objects):
1250 self.objects.append(val)
1287 self.objects.append(val)
12511288
12521289 def get_range(self):
12531290 """
12581295 return named_objs(self.objects, self.names)
12591296
12601297
1261 class Selector(ObjectSelector):
1262 """
1263 A more user friendly ObjectSelector that picks the first object for
1264 the default (by default) given an ordered data collection. As the
1265 first argument is now objects, this can be passed in as a positional
1266 argument which sufficient in many common use cases.
1267 """
1268 def __init__(self,objects=None, default=None, instantiate=False,
1269 compute_default_fn=None,check_on_set=None,allow_None=None,**params):
1270
1271 if is_ordered_dict(objects):
1272 autodefault = list(objects.values())[0]
1273 elif isinstance(objects, dict):
1274 main.param.warning("Parameter default value is arbitrary due to "
1275 "dictionaries prior to Python 3.6 not being "
1276 "ordered; should use an ordered dict or "
1277 "supply an explicit default value.")
1278 autodefault = list(objects.values())[0]
1279 elif isinstance(objects, list):
1280 autodefault = objects[0]
1281 else:
1282 autodefault = None
1283
1284 default = autodefault if default is None else default
1285
1286 super(Selector,self).__init__(default=default, objects=objects,
1287 instantiate=instantiate,
1288 compute_default_fn=compute_default_fn,
1289 check_on_set=check_on_set,
1290 allow_None=allow_None, **params)
1298 class ObjectSelector(Selector):
1299 """
1300 Deprecated. Same as Selector, but with a different constructor for
1301 historical reasons.
1302 """
1303 def __init__(self, default=None, objects=None, **kwargs):
1304 super(ObjectSelector,self).__init__(objects=objects, default=default,
1305 empty_default=True, **kwargs)
1306
12911307
12921308 class ClassSelector(SelectorBase):
12931309 """
12971313 for is_instance=True.
12981314 """
12991315
1300 __slots__ = ['class_','is_instance']
1316 __slots__ = ['class_', 'is_instance']
13011317
13021318 def __init__(self,class_,default=None,instantiate=True,is_instance=True,**params):
13031319 self.class_ = class_
13051321 super(ClassSelector,self).__init__(default=default,instantiate=instantiate,**params)
13061322 self._validate(default)
13071323
1308
1309 def _validate(self,val):
1310 """val must be None, an instance of self.class_ if self.is_instance=True or a subclass of self_class if self.is_instance=False"""
1311 if isinstance(self.class_, tuple):
1312 class_name = ('(%s)' % ', '.join(cl.__name__ for cl in self.class_))
1324 def _validate(self, val):
1325 super(ClassSelector, self)._validate(val)
1326 self._validate_class_(val, self.class_, self.is_instance)
1327
1328 def _validate_class_(self, val, class_, is_instance):
1329 if (val is None and self.allow_None):
1330 return
1331 if isinstance(class_, tuple):
1332 class_name = ('(%s)' % ', '.join(cl.__name__ for cl in class_))
13131333 else:
1314 class_name = self.class_.__name__
1315 if self.is_instance:
1316 if not (isinstance(val,self.class_)) and not (val is None and self.allow_None):
1334 class_name = class_.__name__
1335 param_cls = self.__class__.__name__
1336 if is_instance:
1337 if not (isinstance(val, class_)):
13171338 raise ValueError(
1318 "Parameter '%s' value must be an instance of %s, not '%s'" %
1319 (self.name, class_name, val))
1339 "%s parameter %r value must be an instance of %s, not %r." %
1340 (param_cls, self.name, class_name, val))
13201341 else:
1321 if not (val is None and self.allow_None) and not (issubclass(val,self.class_)):
1342 if not (issubclass(val, class_)):
13221343 raise ValueError(
1323 "Parameter '%s' must be a subclass of %s, not '%s'" %
1324 (val.__name__, class_name, val.__class__.__name__))
1325
1344 "%s parameter %r must be a subclass of %s, not %r." %
1345 (param_cls, self.name, class_name, val.__name__))
13261346
13271347 def get_range(self):
13281348 """
13381358 all_classes = {}
13391359 for cls in classes:
13401360 all_classes.update(concrete_descendents(cls))
1341 d=OrderedDict((name,class_) for name,class_ in all_classes.items())
1361 d = OrderedDict((name, class_) for name,class_ in all_classes.items())
13421362 if self.allow_None:
1343 d['None']=None
1363 d['None'] = None
13441364 return d
13451365
13461366
13491369 Parameter whose value is a list of objects, usually of a specified type.
13501370
13511371 The bounds allow a minimum and/or maximum length of
1352 list to be enforced. If the class is non-None, all
1372 list to be enforced. If the item_type is non-None, all
13531373 items in the list are checked to be of that type.
1354 """
1355
1356 __slots__ = ['class_','bounds']
1357
1358 def __init__(self,default=[],class_=None,instantiate=True,
1359 bounds=(0,None),**params):
1360 self.class_ = class_
1374
1375 `class_` is accepted as an alias for `item_type`, but is
1376 deprecated due to conflict with how the `class_` slot is
1377 used in Selector classes.
1378 """
1379
1380 __slots__ = ['bounds', 'item_type', 'class_']
1381
1382 def __init__(self, default=[], class_=None, item_type=None,
1383 instantiate=True, bounds=(0, None), **params):
1384 self.item_type = item_type or class_
1385 self.class_ = self.item_type
13611386 self.bounds = bounds
1362 Parameter.__init__(self,default=default,instantiate=instantiate,
1387 Parameter.__init__(self, default=default, instantiate=instantiate,
13631388 **params)
13641389 self._validate(default)
13651390
13661391 def _validate(self, val):
13671392 """
1368 Checks that the list is of the right length and has the right contents.
1369 Otherwise, an exception is raised.
1370 """
1371 if self.allow_None and val is None:
1372 return
1373
1393 Checks that the value is numeric and that it is within the hard
1394 bounds; if not, an exception is raised.
1395 """
1396 self._validate_value(val, self.allow_None)
1397 self._validate_bounds(val, self.bounds)
1398 self._validate_item_type(val, self.item_type)
1399
1400 def _validate_bounds(self, val, bounds):
1401 "Checks that the list is of the right length and has the right contents."
1402 if bounds is None or (val is None and self.allow_None):
1403 return
1404 min_length, max_length = bounds
1405 l = len(val)
1406 if min_length is not None and max_length is not None:
1407 if not (min_length <= l <= max_length):
1408 raise ValueError("%s: list length must be between %s and %s (inclusive)"%(self.name,min_length,max_length))
1409 elif min_length is not None:
1410 if not min_length <= l:
1411 raise ValueError("%s: list length must be at least %s."
1412 % (self.name, min_length))
1413 elif max_length is not None:
1414 if not l <= max_length:
1415 raise ValueError("%s: list length must be at most %s."
1416 % (self.name, max_length))
1417
1418 def _validate_value(self, val, allow_None):
1419 if allow_None and val is None:
1420 return
13741421 if not isinstance(val, list):
1375 raise ValueError("List '%s' must be a list."%(self.name))
1376
1377 if self.bounds is not None:
1378 min_length,max_length = self.bounds
1379 l=len(val)
1380 if min_length is not None and max_length is not None:
1381 if not (min_length <= l <= max_length):
1382 raise ValueError("%s: list length must be between %s and %s (inclusive)"%(self.name,min_length,max_length))
1383 elif min_length is not None:
1384 if not min_length <= l:
1385 raise ValueError("%s: list length must be at least %s."%(self.name,min_length))
1386 elif max_length is not None:
1387 if not l <= max_length:
1388 raise ValueError("%s: list length must be at most %s."%(self.name,max_length))
1389
1390 self._check_type(val)
1391
1392 def _check_type(self,val):
1393 if self.class_ is not None:
1394 for v in val:
1395 assert isinstance(v,self.class_),repr(self.name)+": "+repr(v)+" is not an instance of " + repr(self.class_) + "."
1396
1422 raise ValueError("List parameter %r must be a list, not an object of type %s."
1423 % (self.name, type(val)))
1424
1425 def _validate_item_type(self, val, item_type):
1426 if item_type is None or (self.allow_None and val is None):
1427 return
1428 for v in val:
1429 if isinstance(v, item_type):
1430 continue
1431 raise TypeError("List parameter %r items must be instances "
1432 "of type %r, not %r." % (self.name, item_type, val))
13971433
13981434
13991435 class HookList(List):
14041440 for users to register a set of commands to be called at a
14051441 specified place in some sequence of processing steps.
14061442 """
1407 __slots__ = ['class_','bounds']
1408
1409 def _check_type(self,val):
1443 __slots__ = ['class_', 'bounds']
1444
1445 def _validate_value(self, val, allow_None):
1446 super(HookList, self)._validate_value(val, allow_None)
1447 if allow_None and val is None:
1448 return
14101449 for v in val:
1411 assert callable(v),repr(self.name)+": "+repr(v)+" is not callable."
1412
1450 if callable(v):
1451 continue
1452 raise ValueError("HookList parameter %r items must be callable, "
1453 "not %r." % (self.name, v))
14131454
14141455
14151456 class Dict(ClassSelector):
14161457 """
14171458 Parameter whose value is a dictionary.
14181459 """
1460
14191461 def __init__(self, default=None, **params):
1420 super(Dict,self).__init__(dict, default=default, **params)
1462 super(Dict, self).__init__(dict, default=default, **params)
14211463
14221464
14231465 class Array(ClassSelector):
14261468 """
14271469
14281470 def __init__(self, default=None, **params):
1429 # CEBALERT: instead use python array as default?
14301471 from numpy import ndarray
1431 super(Array,self).__init__(ndarray, allow_None=True, default=default, **params)
1472 super(Array, self).__init__(ndarray, allow_None=True, default=default, **params)
1473
1474 @classmethod
1475 def serialize(cls, value):
1476 return value.tolist()
1477
1478 @classmethod
1479 def deserialize(cls, value):
1480 from numpy import asarray
1481 return asarray(value)
14321482
14331483
14341484 class DataFrame(ClassSelector):
14491499 if a list is given, the supplied DataFrame must contain exactly the
14501500 same columns and in the same order and no other columns.
14511501 """
1452 __slots__ = ['rows','columns', 'ordered']
1502
1503 __slots__ = ['rows', 'columns', 'ordered']
14531504
14541505 def __init__(self, default=None, rows=None, columns=None, ordered=None, **params):
14551506 from pandas import DataFrame as pdDFrame
14561507 self.rows = rows
14571508 self.columns = columns
14581509 self.ordered = ordered
1459 super(DataFrame,self).__init__(pdDFrame, default=default, allow_None=True, **params)
1510 super(DataFrame,self).__init__(pdDFrame, default=default, **params)
14601511 self._validate(self.default)
1461
14621512
14631513 def _length_bounds_check(self, bounds, length, name):
14641514 message = '{name} length {length} does not match declared bounds of {bounds}'
14781528
14791529 if isinstance(self.columns, set) and self.ordered is True:
14801530 raise ValueError('Columns cannot be ordered when specified as a set')
1531
1532 if self.allow_None and val is None:
1533 return
14811534
14821535 if self.columns is None:
14831536 pass
15011554 if self.rows is not None:
15021555 self._length_bounds_check(self.rows, len(val), 'Row')
15031556
1557 @classmethod
1558 def serialize(cls, value):
1559 return value.to_dict('records')
1560
1561 @classmethod
1562 def deserialize(cls, value):
1563 from pandas import DataFrame as pdDFrame
1564 return pdDFrame(value)
1565
15041566
15051567 class Series(ClassSelector):
15061568 """
15101572 which may be a number or an integer bounds tuple to constrain the
15111573 allowable number of rows.
15121574 """
1575
15131576 __slots__ = ['rows']
1577
1578 def __init__(self, default=None, rows=None, allow_None=False, **params):
1579 from pandas import Series as pdSeries
1580 self.rows = rows
1581 super(Series,self).__init__(pdSeries, default=default, allow_None=allow_None,
1582 **params)
1583 self._validate(self.default)
15141584
15151585 def _length_bounds_check(self, bounds, length, name):
15161586 message = '{name} length {length} does not match declared bounds of {bounds}'
15251595 if failure:
15261596 raise ValueError(message.format(name=name,length=length, bounds=bounds))
15271597
1528 def __init__(self, default=None, rows=None, **params):
1529 from pandas import Series as pdSeries
1530 self.rows = rows
1531 super(Series,self).__init__(pdSeries, allow_None=True, default=default, **params)
1532 self._validate(self.default)
1533
15341598 def _validate(self, val):
15351599 super(Series, self)._validate(val)
1600
1601 if self.allow_None and val is None:
1602 return
15361603
15371604 if self.rows is not None:
15381605 self._length_bounds_check(self.rows, len(val), 'Row')
15661633 Prepended to a non-relative path, in order, until a file is
15671634 found.""")
15681635
1569 path_to_file = Boolean(default=True, pickle_default_value=False, doc="""
1570 String specifying whether the path refers to a 'File' or a 'Folder'.""")
1636 path_to_file = Boolean(default=True, pickle_default_value=False,
1637 allow_None=True, doc="""
1638 String specifying whether the path refers to a 'File' or a
1639 'Folder'. If None, the path may point to *either* a 'File' *or*
1640 a 'Folder'.""")
15711641
15721642 def __call__(self, path, **params):
15731643 p = ParamOverrides(self, params)
1574
15751644 path = os.path.normpath(path)
1645 ftype = "File" if p.path_to_file is True \
1646 else "Folder" if p.path_to_file is False else "Path"
1647
1648 if not p.search_paths:
1649 p.search_paths = [os.getcwd()]
15761650
15771651 if os.path.isabs(path):
1578 if p.path_to_file:
1579 if os.path.isfile(path):
1580 return path
1581 else:
1582 raise IOError("File '%s' not found." %path)
1583 elif not p.path_to_file:
1584 if os.path.isdir(path):
1585 return path
1586 else:
1587 raise IOError("Folder '%s' not found." %path)
1588 else:
1589 raise IOError("Type '%s' not recognised." %p.path_type)
1652 if ((p.path_to_file is None and os.path.exists(path)) or
1653 (p.path_to_file is True and os.path.isfile(path)) or
1654 (p.path_to_file is False and os.path.isdir( path))):
1655 return path
1656 raise IOError("%s '%s' not found." % (ftype,path))
15901657
15911658 else:
15921659 paths_tried = []
15931660 for prefix in p.search_paths:
15941661 try_path = os.path.join(os.path.normpath(prefix), path)
15951662
1596 if p.path_to_file:
1597 if os.path.isfile(try_path):
1598 return try_path
1599 elif not p.path_to_file:
1600 if os.path.isdir(try_path):
1601 return try_path
1602 else:
1603 raise IOError("Type '%s' not recognised." %p.path_type)
1663 if ((p.path_to_file is None and os.path.exists(try_path)) or
1664 (p.path_to_file is True and os.path.isfile(try_path)) or
1665 (p.path_to_file is False and os.path.isdir( try_path))):
1666 return try_path
16041667
16051668 paths_tried.append(try_path)
16061669
1607 raise IOError(os.path.split(path)[1] + " was not found in the following place(s): " + str(paths_tried) + ".")
1670 raise IOError(ftype + " " + os.path.split(path)[1] + " was not found in the following place(s): " + str(paths_tried) + ".")
16081671
16091672
16101673 class normalize_path(ParameterizedFunction):
16631726 super(Path,self).__init__(default,**params)
16641727
16651728 def _resolve(self, path):
1666 if self.search_paths:
1667 return resolve_path(path, search_paths=self.search_paths)
1668 else:
1669 return resolve_path(path)
1729 return resolve_path(path, path_to_file=None, search_paths=self.search_paths)
16701730
16711731 def _validate(self, val):
16721732 if val is None:
16731733 if not self.allow_None:
1674 Parameterized(name="%s.%s"%(self.owner.name,self.name)).warning('None is not allowed')
1734 Parameterized(name="%s.%s"%(self.owner.name,self.name)).param.warning('None is not allowed')
16751735 else:
16761736 try:
16771737 self._resolve(val)
16781738 except IOError as e:
1679 Parameterized(name="%s.%s"%(self.owner.name,self.name)).warning('%s',e.args[0])
1739 Parameterized(name="%s.%s"%(self.owner.name,self.name)).param.warning('%s',e.args[0])
16801740
16811741 def __get__(self, obj, objtype):
16821742 """
17141774 """
17151775
17161776 def _resolve(self, path):
1717 if self.search_paths:
1718 return resolve_path(path, path_to_file=True, search_paths=self.search_paths)
1719 else:
1720 return resolve_path(path, path_to_file=True)
1777 return resolve_path(path, path_to_file=True, search_paths=self.search_paths)
17211778
17221779
17231780 class Foldername(Path):
17381795 """
17391796
17401797 def _resolve(self, path):
1741 if self.search_paths:
1742 return resolve_path(path, path_to_file=False, search_paths=self.search_paths)
1743 else:
1744 return resolve_path(path, path_to_file=False)
1798 return resolve_path(path, path_to_file=False, search_paths=self.search_paths)
17451799
17461800
17471801
17571811
17581812
17591813
1760 class FileSelector(ObjectSelector):
1814 class FileSelector(Selector):
17611815 """
17621816 Given a path glob, allows one file to be selected from those matching.
17631817 """
17641818 __slots__ = ['path']
17651819
17661820 def __init__(self, default=None, path="", **kwargs):
1767 super(FileSelector, self).__init__(default, **kwargs)
1821 self.default = default
17681822 self.path = path
17691823 self.update()
1824 super(FileSelector, self).__init__(default=default, objects=self.objects,
1825 empty_default=True, **kwargs)
1826
1827 def _on_set(self, attribute, old, new):
1828 super(FileSelector, self)._on_set(attribute, new, old)
1829 if attribute == 'path':
1830 self.update()
17701831
17711832 def update(self):
17721833 self.objects = sorted(glob.glob(self.path))
17781839 return abbreviate_paths(self.path,super(FileSelector, self).get_range())
17791840
17801841
1781 class ListSelector(ObjectSelector):
1782 """
1783 Variant of ObjectSelector where the value can be multiple objects from
1842 class ListSelector(Selector):
1843 """
1844 Variant of Selector where the value can be multiple objects from
17841845 a list of possible objects.
17851846 """
1847
1848 def __init__(self, default=None, objects=None, **kwargs):
1849 super(ListSelector,self).__init__(
1850 objects=objects, default=default, empty_default=True, **kwargs)
17861851
17871852 def compute_default(self):
17881853 if self.default is None and callable(self.compute_default_fn):
17921857 self.objects.append(o)
17931858
17941859 def _validate(self, val):
1860 if (val is None and self.allow_None):
1861 return
17951862 for o in val:
17961863 super(ListSelector, self)._validate(o)
17971864
18041871 __slots__ = ['path']
18051872
18061873 def __init__(self, default=None, path="", **kwargs):
1807 super(MultiFileSelector, self).__init__(default, **kwargs)
1874 self.default = default
18081875 self.path = path
18091876 self.update()
1877 super(MultiFileSelector, self).__init__(default=default, objects=self.objects, **kwargs)
1878
1879 def _on_set(self, attribute, old, new):
1880 super(MultiFileSelector, self)._on_set(attribute, new, old)
1881 if attribute == 'path':
1882 self.update()
18101883
18111884 def update(self):
18121885 self.objects = sorted(glob.glob(self.path))
18261899 def __init__(self, default=None, **kwargs):
18271900 super(Date, self).__init__(default=default, **kwargs)
18281901
1829 def _validate(self, val):
1902 def _validate_value(self, val, allow_None):
18301903 """
18311904 Checks that the value is numeric and that it is within the hard
18321905 bounds; if not, an exception is raised.
18341907 if self.allow_None and val is None:
18351908 return
18361909
1837 if not isinstance(val, dt_types) and not (self.allow_None and val is None):
1838 raise ValueError("Date '%s' only takes datetime and date types."%self.name)
1839
1840 if self.step is not None and not isinstance(self.step, dt_types):
1910 if not isinstance(val, dt_types) and not (allow_None and val is None):
1911 raise ValueError("Date parameter %r only takes datetime and date types." % self.name)
1912
1913 def _validate_step(self, val, step):
1914 if step is not None and not isinstance(step, dt_types):
18411915 raise ValueError("Step parameter can only be None, a datetime or datetime type")
18421916
1843 self._checkBounds(val)
1917 @classmethod
1918 def serialize(cls, value):
1919 if not isinstance(value, (dt.datetime, dt.date)): # i.e np.datetime64
1920 value = value.astype(dt.datetime)
1921 return value.strftime("%Y-%m-%dT%H:%M:%S.%f")
1922
1923 @classmethod
1924 def deserialize(cls, value):
1925 return dt.datetime.strptime(value, "%Y-%m-%dT%H:%M:%S.%f")
18441926
18451927
18461928 class CalendarDate(Number):
18511933 def __init__(self, default=None, **kwargs):
18521934 super(CalendarDate, self).__init__(default=default, **kwargs)
18531935
1854 def _validate(self, val):
1936 def _validate_value(self, val, allow_None):
18551937 """
18561938 Checks that the value is numeric and that it is within the hard
18571939 bounds; if not, an exception is raised.
18591941 if self.allow_None and val is None:
18601942 return
18611943
1862 if not isinstance(val, dt.date) and not (self.allow_None and val is None):
1863 raise ValueError("CalendarDate '%s' only takes datetime types."%self.name)
1864
1865 if self.step is not None and not isinstance(self.step, dt.date):
1866 raise ValueError("Step parameter can only be None or a date type")
1867
1868 self._checkBounds(val)
1944 if not isinstance(val, dt.date) and not (allow_None and val is None):
1945 raise ValueError("CalendarDate parameter %r only takes datetime types." % self.name)
1946
1947 def _validate_step(self, val, step):
1948 if step is not None and not isinstance(step, dt.date):
1949 raise ValueError("Step parameter can only be None or a date type.")
1950
1951 @classmethod
1952 def serialize(cls, value):
1953 return value.strftime("%Y-%m-%d")
1954
1955 @classmethod
1956 def deserialize(cls, value):
1957 return dt.datetime.strptime(value, "%Y-%m-%d").date()
18691958
18701959
18711960 class Color(Parameter):
18721961 """
18731962 Color parameter defined as a hex RGB string with an optional #
1874 prefix.
1875 """
1876
1877 def __init__(self, default=None, allow_None=False, **kwargs):
1963 prefix or (optionally) as a CSS3 color name.
1964 """
1965
1966 # CSS3 color specification https://www.w3.org/TR/css-color-3/#svg-color
1967 _named_colors = [ 'aliceblue', 'antiquewhite', 'aqua',
1968 'aquamarine', 'azure', 'beige', 'bisque', 'black',
1969 'blanchedalmond', 'blue', 'blueviolet', 'brown', 'burlywood',
1970 'cadetblue', 'chartreuse', 'chocolate', 'coral',
1971 'cornflowerblue', 'cornsilk', 'crimson', 'cyan', 'darkblue',
1972 'darkcyan', 'darkgoldenrod', 'darkgray', 'darkgrey',
1973 'darkgreen', 'darkkhaki', 'darkmagenta', 'darkolivegreen',
1974 'darkorange', 'darkorchid', 'darkred', 'darksalmon',
1975 'darkseagreen', 'darkslateblue', 'darkslategray',
1976 'darkslategrey', 'darkturquoise', 'darkviolet', 'deeppink',
1977 'deepskyblue', 'dimgray', 'dimgrey', 'dodgerblue',
1978 'firebrick', 'floralwhite', 'forestgreen', 'fuchsia',
1979 'gainsboro', 'ghostwhite', 'gold', 'goldenrod', 'gray',
1980 'grey', 'green', 'greenyellow', 'honeydew', 'hotpink',
1981 'indianred', 'indigo', 'ivory', 'khaki', 'lavender',
1982 'lavenderblush', 'lawngreen', 'lemonchiffon', 'lightblue',
1983 'lightcoral', 'lightcyan', 'lightgoldenrodyellow',
1984 'lightgray', 'lightgrey', 'lightgreen', 'lightpink',
1985 'lightsalmon', 'lightseagreen', 'lightskyblue',
1986 'lightslategray', 'lightslategrey', 'lightsteelblue',
1987 'lightyellow', 'lime', 'limegreen', 'linen', 'magenta',
1988 'maroon', 'mediumaquamarine', 'mediumblue', 'mediumorchid',
1989 'mediumpurple', 'mediumseagreen', 'mediumslateblue',
1990 'mediumspringgreen', 'mediumturquoise', 'mediumvioletred',
1991 'midnightblue', 'mintcream', 'mistyrose', 'moccasin',
1992 'navajowhite', 'navy', 'oldlace', 'olive', 'olivedrab',
1993 'orange', 'orangered', 'orchid', 'palegoldenrod', 'palegreen',
1994 'paleturquoise', 'palevioletred', 'papayawhip', 'peachpuff',
1995 'peru', 'pink', 'plum', 'powderblue', 'purple', 'red',
1996 'rosybrown', 'royalblue', 'saddlebrown', 'salmon',
1997 'sandybrown', 'seagreen', 'seashell', 'sienna', 'silver',
1998 'skyblue', 'slateblue', 'slategray', 'slategrey', 'snow',
1999 'springgreen', 'steelblue', 'tan', 'teal', 'thistle',
2000 'tomato', 'turquoise', 'violet', 'wheat', 'white',
2001 'whitesmoke', 'yellow', 'yellowgreen']
2002
2003 __slots__ = ['allow_named']
2004
2005 def __init__(self, default=None, allow_named=True, **kwargs):
18782006 super(Color, self).__init__(default=default, **kwargs)
2007 self.allow_named = allow_named
18792008 self._validate(default)
18802009
18812010 def _validate(self, val):
1882 if (self.allow_None and val is None):
2011 self._validate_value(val, self.allow_None)
2012 self._validate_allow_named(val, self.allow_named)
2013
2014 def _validate_value(self, val, allow_None):
2015 if (allow_None and val is None):
18832016 return
18842017 if not isinstance(val, basestring):
1885 raise ValueError("Color '%s' only takes a string value."%self.name)
1886 if not re.match('^#?(([0-9a-fA-F]{2}){3}|([0-9a-fA-F]){3})$', val):
1887 raise ValueError("Color '%s' only accepts valid RGB hex codes."
1888 % self.name)
1889
2018 raise ValueError("Color parameter %r expects a string value, "
2019 "not an object of type %s." % (self.name, type(val)))
2020
2021 def _validate_allow_named(self, val, allow_named):
2022 if (val is None and self.allow_None):
2023 return
2024 is_hex = re.match('^#?(([0-9a-fA-F]{2}){3}|([0-9a-fA-F]){3})$', val)
2025 if self.allow_named:
2026 if not is_hex and val not in self._named_colors:
2027 raise ValueError("Color '%s' only takes RGB hex codes "
2028 "or named colors, received '%s'." % (self.name, val))
2029 elif not is_hex:
2030 raise ValueError("Color '%s' only accepts valid RGB hex "
2031 "codes, received '%s'." % (self.name, val))
18902032
18912033
18922034 class Range(NumericTuple):
18932035 "A numeric range with optional bounds and softbounds"
18942036
1895 __slots__ = ['bounds', 'inclusive_bounds', 'softbounds']
1896
2037 __slots__ = ['bounds', 'inclusive_bounds', 'softbounds', 'step']
18972038
18982039 def __init__(self,default=None, bounds=None, softbounds=None,
1899 inclusive_bounds=(True,True), **params):
2040 inclusive_bounds=(True,True), step=None, **params):
19002041 self.bounds = bounds
19012042 self.inclusive_bounds = inclusive_bounds
19022043 self.softbounds = softbounds
2044 self.step = step
19032045 super(Range,self).__init__(default=default,length=2,**params)
19042046
1905
19062047 def _validate(self, val):
1907 """
1908 Checks that the value is numeric and that it is within the hard
1909 bounds; if not, an exception is raised.
1910 """
1911 if self.allow_None and val is None:
1912 return
19132048 super(Range, self)._validate(val)
1914
1915 self._checkBounds(val)
2049 self._validate_bounds(val, self.bounds, self.inclusive_bounds)
2050
2051 def _validate_bounds(self, val, bounds, inclusive_bounds):
2052 if bounds is None or (val is None and self.allow_None):
2053 return
2054 vmin, vmax = bounds
2055 incmin, incmax = inclusive_bounds
2056 for bound, v in zip(['lower', 'upper'], val):
2057 too_low = (vmin is not None) and (v < vmin if incmin else v <= vmin)
2058 too_high = (vmax is not None) and (v > vmax if incmax else v >= vmax)
2059 if too_low or too_high:
2060 raise ValueError("Range parameter %r's %s bound must be in range %s."
2061 % (self.name, bound, self.rangestr()))
19162062
19172063
19182064 def get_soft_bounds(self):
1919 """
1920 For each soft bound (upper and lower), if there is a defined bound (not equal to None)
1921 then it is returned, otherwise it defaults to the hard bound. The hard bound could still be None.
1922 """
1923 if self.bounds is None:
1924 hl,hu=(None,None)
1925 else:
1926 hl,hu=self.bounds
1927
1928 if self.softbounds is None:
1929 sl,su=(None,None)
1930 else:
1931 sl,su=self.softbounds
1932
1933
1934 if sl is None: l = hl
1935 else: l = sl
1936
1937 if su is None: u = hu
1938 else: u = su
1939
1940 return (l,u)
2065 return get_soft_bounds(self.bounds, self.softbounds)
19412066
19422067
19432068 def rangestr(self):
19482073 return '%s%s, %s%s' % (incmin, vmin, vmax, incmax)
19492074
19502075
1951 def _checkBounds(self, val):
1952 if self.bounds is not None:
1953 vmin,vmax = self.bounds
1954 incmin,incmax = self.inclusive_bounds
1955 for bound, v in zip(['lower', 'upper'], val):
1956 too_low = (vmin is not None) and (v < vmin if incmin else v <= vmin)
1957 too_high = (vmax is not None) and (v > vmax if incmax else v >= vmax)
1958 if too_low or too_high:
1959 raise ValueError("Parameter '%s' %s bound must be in range %s"
1960 % (self.name, bound, self.rangestr()))
1961
1962
19632076 class DateRange(Range):
19642077 """
19652078 A datetime or date range specified as (start, end).
19662079
19672080 Bounds must be specified as datetime or date types (see param.dt_types).
19682081 """
1969 def _validate(self, val):
1970 if self.allow_None and val is None:
2082
2083 def _validate_value(self, val, allow_None):
2084 if allow_None and val is None:
19712085 return
19722086
19732087 for n in val:
1974 if not isinstance(n, dt_types):
1975 raise ValueError("DateRange '%s' only takes datetime types: %s"%(self.name,val))
2088 if isinstance(n, dt_types):
2089 continue
2090 raise ValueError("DateRange parameter %r only takes datetime "
2091 "types, not %s." % (self.name, val))
19762092
19772093 start, end = val
19782094 if not end >= start:
1979 raise ValueError("DateRange '%s': end datetime %s is before start datetime %s."%(self.name,val[1],val[0]))
1980
1981 # Calling super(DateRange, self)._check(val) would also check
1982 # values are numeric, which is redundant, so just call
1983 # _checkBounds().
1984 self._checkBounds(val)
2095 raise ValueError("DateRange parameter %r's end datetime %s "
2096 "is before start datetime %s." %
2097 (self.name,val[1],val[0]))
2098
19852099
19862100
19872101 class CalendarDateRange(Range):
19882102 """
19892103 A date range specified as (start_date, end_date).
19902104 """
1991 def _validate(self, val):
1992 if self.allow_None and val is None:
2105 def _validate_value(self, val, allow_None):
2106 if allow_None and val is None:
19932107 return
19942108
19952109 for n in val:
19962110 if not isinstance(n, dt.date):
1997 raise ValueError("CalendarDateRange '%s' only takes date types: %s"%(self.name,val))
2111 raise ValueError("CalendarDateRange parameter %r only "
2112 "takes date types, not %s." % (self.name, val))
19982113
19992114 start, end = val
20002115 if not end >= start:
2001 raise ValueError("CalendarDateRange '%s': end date %s is before start date %s."%(self.name,val[1],val[0]))
2002
2003 # Calling super(CalendarDateRange, self)._check(val) would also check
2004 # values are numeric, which is redundant, so just call
2005 # _checkBounds().
2006 self._checkBounds(val)
2116 raise ValueError("CalendarDateRange parameter %r's end date "
2117 "%s is before start date %s." %
2118 (self.name, val[1], val[0]))
2119
2120
2121 class Event(Boolean):
2122 """
2123 An Event Parameter is one whose value is intimately linked to the
2124 triggering of events for watchers to consume. Event has a Boolean
2125 value, which when set to True triggers the associated watchers (as
2126 any Parameter does) and then is automatically set back to
2127 False. Conversely, if events are triggered directly via `.trigger`,
2128 the value is transiently set to True (so that it's clear which of
2129 many parameters being watched may have changed), then restored to
2130 False when the triggering completes. An Event parameter is thus like
2131 a momentary switch or pushbutton with a transient True value that
2132 serves only to launch some other action (e.g. via a param.depends
2133 decorator), rather than encapsulating the action itself as
2134 param.Action does.
2135 """
2136
2137 # _autotrigger_value specifies the value used to set the parameter
2138 # to when the parameter is supplied to the trigger method. This
2139 # value change is then what triggers the watcher callbacks.
2140 __slots__ = ['_autotrigger_value', '_mode', '_autotrigger_reset_value']
2141
2142 def __init__(self,default=False,bounds=(0,1),**params):
2143 self._autotrigger_value = True
2144 self._autotrigger_reset_value = False
2145 self._mode = 'set-reset'
2146 # Mode can be one of 'set', 'set-reset' or 'reset'
2147
2148 # 'set' is normal Boolean parameter behavior when set with a value.
2149 # 'set-reset' temporarily sets the parameter (which triggers
2150 # watching callbacks) but immediately resets the value back to
2151 # False.
2152 # 'reset' applies the reset from True to False without
2153 # triggering watched callbacks
2154
2155 # This _mode attribute is one of the few places where a specific
2156 # parameter has a special behavior that is relied upon by the
2157 # core functionality implemented in
2158 # parameterized.py. Specifically, the set_param method
2159 # temporarily sets this attribute in order to disable resetting
2160 # back to False while triggered callbacks are executing
2161 super(Event, self).__init__(default=default,**params)
2162
2163 def _reset_event(self, obj, val):
2164 val = False
2165 if obj is None:
2166 self.default = val
2167 else:
2168 obj.__dict__[self._internal_name] = val
2169 self._post_setter(obj, val)
2170
2171 @instance_descriptor
2172 def __set__(self, obj, val):
2173 if self._mode in ['set-reset', 'set']:
2174 super(Event, self).__set__(obj, val)
2175 if self._mode in ['set-reset', 'reset']:
2176 self._reset_event(obj, val)
2177
2178
2179 from contextlib import contextmanager
2180 @contextmanager
2181 def exceptions_summarized():
2182 """Useful utility for writing docs that need to show expected errors.
2183 Shows exception only, concisely, without a traceback.
2184 """
2185 try:
2186 yield
2187 except Exception:
2188 import sys
2189 etype, value, tb = sys.exc_info()
2190 print("{}: {}".format(etype.__name__,value), file=sys.stderr)
1919 __author__ = "Jean-Luc Stevens"
2020
2121 import re
22 import sys
23 import itertools
2224 import textwrap
2325 import param
2426
8587
8688 (params, val_dict, changed) = info
8789 contents = []
88 displayed_params = {}
89 for name, p in params.items():
90 displayed_params = []
91 for name in self.sort_by_precedence(params):
9092 if only_changed and not (name in changed):
9193 continue
92 displayed_params[name] = p
93
94 right_shift = max(len(name) for name in displayed_params.keys())+2
95
96 for i, name in enumerate(sorted(displayed_params)):
97 p = displayed_params[name]
94 displayed_params.append((name, params[name]))
95
96 right_shift = max(len(name) for name, _ in displayed_params)+2
97
98 for i, (name, p) in enumerate(displayed_params):
9899 heading = "%s: " % name
99100 unindented = textwrap.dedent("< No docstring available >" if p.doc is None else p.doc)
100101
123124 return "\n".join(contents)
124125
125126
127 def sort_by_precedence(self, parameters):
128 """
129 Sort the provided dictionary of parameters by their precedence value.
130 In Python 3, preserves the original ordering for parameters with the
131 same precedence; for Python 2 sorts them lexicographically by name,
132 unless explicit precedences are provided.
133 """
134 params = [(p, pobj) for p, pobj in parameters.items()]
135 key_fn = lambda x: x[1].precedence if x[1].precedence is not None else 1e-8
136 sorted_params = sorted(params, key=key_fn)
137 groups = itertools.groupby(sorted_params, key=key_fn)
138 # Params preserve definition order in Python 3.6+
139 dict_ordered = (
140 (sys.version_info.major == 3 and sys.version_info.minor >= 6) or
141 (sys.version_info.major > 3) or
142 all(p.precedence is not None for p in parameters.values())
143 )
144 ordered_groups = [list(grp) if dict_ordered else sorted(grp) for (_, grp) in groups]
145 ordered_params = [el[0] for group in ordered_groups for el in group
146 if (el[0] != 'name' or el[0] in parameters)]
147 return ordered_params
148
149
126150 def _build_table(self, info, order, max_col_len=40, only_changed=False):
127151 """
128152 Collect the information about parameters needed to build a
129153 properly formatted table and then tabulate it.
130154 """
131155
132 info_dict, bounds_dict = {}, {}
156 info_list, bounds_dict = [], {}
133157 (params, val_dict, changed) = info
134158 col_widths = dict((k,0) for k in order)
135159
136 for name, p in params.items():
160 ordering = self.sort_by_precedence(params)
161 for name in ordering:
162 p = params[name]
137163 if only_changed and not (name in changed):
138164 continue
139165
142168 allow_None = ' AN' if hasattr(p, 'allow_None') and p.allow_None else ''
143169
144170 mode = '%s %s%s' % (constant, readonly, allow_None)
145 info_dict[name] = {'name': name, 'type':p.__class__.__name__,
146 'mode':mode}
171
172 value = repr(val_dict[name])
173 if len(value) > (max_col_len - 3):
174 value = value[:max_col_len-3] + '...'
175
176 p_dict = {'name': name, 'type': p.__class__.__name__,
177 'mode': mode, 'value': value}
147178
148179 if hasattr(p, 'bounds'):
149180 lbound, ubound = (None,None) if p.bounds is None else p.bounds
161192
162193 if (lbound, ubound) != (None,None):
163194 bounds_dict[name] = (mark_lbound, mark_ubound)
164 info_dict[name]['bounds'] = '(%s, %s)' % (lbound, ubound)
165
166 value = repr(val_dict[name])
167 if len(value) > (max_col_len - 3):
168 value = value[:max_col_len-3] + '...'
169 info_dict[name]['value'] = value
170
171 for col in info_dict[name]:
172 max_width = max([col_widths[col], len(info_dict[name][col])])
195 p_dict['bounds'] = '(%s, %s)' % (lbound, ubound)
196
197 for col in p_dict:
198 max_width = max([col_widths[col], len(p_dict[col])])
173199 col_widths[col] = max_width
174200
175 return self._tabulate(info_dict, col_widths, changed, order, bounds_dict)
176
177
178 def _tabulate(self, info_dict, col_widths, changed, order, bounds_dict):
201 info_list.append((name, p_dict))
202
203 return self._tabulate(info_list, col_widths, changed, order, bounds_dict)
204
205
206 def _tabulate(self, info_list, col_widths, changed, order, bounds_dict):
179207 """
180208 Returns the supplied information as a table suitable for
181209 printing or paging.
182210
183 info_dict: Dictionary of the parameters name, type and mode.
211 info_list: List of the parameters name, type and mode.
184212 col_widths: Dictionary of column widths in characters
185213 changed: List of parameters modified from their defaults.
186214 order: The order of the table columns
188216 """
189217
190218 contents, tail = [], []
191 column_set = set(k for row in info_dict.values() for k in row)
219 column_set = set(k for _, row in info_list for k in row)
192220 columns = [col for col in order if col in column_set]
193221
194222 title_row = []
201229 contents.append(blue % ''.join(title_row)+"\n")
202230
203231 # Format the table rows
204 for row in sorted(info_dict):
232 for row, info in info_list:
205233 row_list = []
206 info = info_dict[row]
207234 for i,col in enumerate(columns):
208235 width = col_widths[col]+2
209236 val = info[col] if (col in info) else ''
257284 heading_text = "%s\n%s\n" % (title, heading_line)
258285
259286 param_info = self.get_param_info(param_obj, include_super=True)
260
261287 if not param_info[0]:
262288 return "%s\n%s" % ((green % heading_text), "Object has no parameters.")
263289
265291 only_changed=False)
266292
267293 docstrings = self.param_docstrings(param_info, max_col_len=100, only_changed=False)
268
269294 dflt_msg = "Parameters changed from their default values are marked in red."
270295 top_heading = (green % heading_text)
271296 top_heading += "\n%s" % (red % dflt_msg)
278303 return "%s\n\n%s\n\n%s\n\n%s" % (top_heading, table, docstring_heading, docstrings)
279304
280305
281 message = """Welcome to the param IPython extension! (http://ioam.github.io/param/)"""
306 message = """Welcome to the param IPython extension! (https://param.holoviz.org/)"""
282307 message += '\nAvailable magics: %params'
283308
284309 _loaded = False
1010 import numbers
1111 import operator
1212
13 from collections import namedtuple, OrderedDict
13 # Allow this file to be used standalone if desired, albeit without JSON serialization
14 try:
15 from . import serializer
16 except ImportError:
17 serializer = None
18
19
20 from collections import defaultdict, namedtuple, OrderedDict
21 from functools import partial, wraps, reduce
1422 from operator import itemgetter,attrgetter
1523 from types import FunctionType
16 from functools import partial, wraps, reduce
1724
1825 import logging
1926 from contextlib import contextmanager
132139 """
133140 batch_watch = parameterized.param._BATCH_WATCH
134141 parameterized.param._BATCH_WATCH = True
135 watchers, events = parameterized.param._watchers, parameterized.param._events
142 watchers, events = (list(parameterized.param._watchers),
143 list(parameterized.param._events))
136144 try:
137145 yield
138146 except:
141149 parameterized.param._BATCH_WATCH = batch_watch
142150 parameterized.param._watchers = watchers
143151 parameterized.param._events = events
152
153
154 # External components can register an async executor which will run
155 # async functions
156 async_executor = None
144157
145158
146159 def classlist(class_):
285298 return cls
286299
287300
301 def iscoroutinefunction(function):
302 """
303 Whether the function is an asynchronous coroutine function.
304 """
305 if not hasattr(inspect, 'iscoroutinefunction'):
306 return False
307 return inspect.iscoroutinefunction(function)
308
309
288310 def instance_descriptor(f):
289311 # If parameter has an instance Parameter delegate setting
290312 def _f(self, obj, val):
294316 return
295317 return f(self, obj, val)
296318 return _f
319
320
321 def get_method_owner(method):
322 """
323 Gets the instance that owns the supplied method
324 """
325 if not inspect.ismethod(method):
326 return None
327 if isinstance(method, partial):
328 method = method.func
329 return method.__self__ if sys.version_info.major >= 3 else method.im_self
297330
298331
299332 @accept_arguments
345378 'or function is not supported when referencing '
346379 'parameters by name.')
347380
348 if not string_specs and watch:
349 def cb(event):
381 if not string_specs and watch: # string_specs case handled elsewhere (later), in Parameterized.__init__
382 def cb(*events):
350383 args = (getattr(dep.owner, dep.name) for dep in dependencies)
351384 dep_kwargs = {n: getattr(dep.owner, dep.name) for n, dep in kw.items()}
352385 return func(*args, **dep_kwargs)
353386
387 grouped = defaultdict(list)
354388 for dep in deps:
355 dep.owner.param.watch(cb, dep.name)
389 grouped[id(dep.owner)].append(dep)
390 for group in grouped.values():
391 group[0].owner.param.watch(cb, [dep.name for dep in group])
356392
357393 _dinfo = getattr(func, '_dinfo', {})
358394 _dinfo.update({'dependencies': dependencies,
471507 return params
472508
473509
474 def _m_caller(self,n):
475 return lambda event: getattr(self,n)()
510 def _m_caller(self, n):
511 function = getattr(self, n)
512 if iscoroutinefunction(function):
513 import asyncio
514 @asyncio.coroutine
515 def caller(*events):
516 yield function()
517 else:
518 def caller(*events):
519 return function()
520 caller._watcher_name = n
521 return caller
476522
477523
478524 PInfo = namedtuple("PInfo","inst cls name pobj what")
659705 # attributes. Using __slots__ requires special support for
660706 # operations to copy and restore Parameters (e.g. for Python
661707 # persistent storage pickling); see __getstate__ and __setstate__.
662 __slots__ = ['name','_internal_name','default','doc',
663 'precedence','instantiate','constant','readonly',
664 'pickle_default_value','allow_None', 'per_instance',
708 __slots__ = ['name', '_internal_name', 'default', 'doc',
709 'precedence', 'instantiate', 'constant', 'readonly',
710 'pickle_default_value', 'allow_None', 'per_instance',
665711 'watchers', 'owner', '_label']
666712
667713 # Note: When initially created, a Parameter does not know which
670716 # class is created, owner, name, and _internal_name are
671717 # set.
672718
673 def __init__(self,default=None,doc=None,label=None,precedence=None, # pylint: disable-msg=R0913
674 instantiate=False,constant=False,readonly=False,
719 _serializers = {'json': serializer.JSONSerialization}
720
721 def __init__(self,default=None, doc=None, label=None, precedence=None, # pylint: disable-msg=R0913
722 instantiate=False, constant=False, readonly=False,
675723 pickle_default_value=True, allow_None=False,
676724 per_instance=True):
677 """
678 Initialize a new Parameter object: store the supplied attributes.
679
680 default: the owning class's value for the attribute
681 represented by this Parameter.
682
683 precedence is a value, usually in the range 0.0 to 1.0, that
684 allows the order of Parameters in a class to be defined (for
685 e.g. in GUI menus). A negative precedence indicates a
686 parameter that should be hidden in e.g. GUI menus.
687
688 default, doc, and precedence default to None. This is to allow
725
726 """Initialize a new Parameter object and store the supplied attributes:
727
728 default: the owning class's value for the attribute represented
729 by this Parameter, which can be overridden in an instance.
730
731 doc: docstring explaining what this parameter represents.
732
733 label: optional text label to be used when this Parameter is
734 shown in a listing. If no label is supplied, the attribute name
735 for this parameter in the owning Parameterized object is used.
736
737 precedence: a numeric value, usually in the range 0.0 to 1.0,
738 which allows the order of Parameters in a class to be defined in
739 a listing or e.g. in GUI menus. A negative precedence indicates
740 a parameter that should be hidden in such listings.
741
742 instantiate: controls whether the value of this Parameter will
743 be deepcopied when a Parameterized object is instantiated (if
744 True), or if the single default value will be shared by all
745 Parameterized instances (if False). For an immutable Parameter
746 value, it is best to leave instantiate at the default of
747 False, so that a user can choose to change the value at the
748 Parameterized instance level (affecting only that instance) or
749 at the Parameterized class or superclass level (affecting all
750 existing and future instances of that class or superclass). For
751 a mutable Parameter value, the default of False is also appropriate
752 if you want all instances to share the same value state, e.g. if
753 they are each simply referring to a single global object like
754 a singleton. If instead each Parameterized should have its own
755 independently mutable value, instantiate should be set to
756 True, but note that there is then no simple way to change the
757 value of this Parameter at the class or superclass level,
758 because each instance, once created, will then have an
759 independently instantiated value.
760
761 constant: if true, the Parameter value can be changed only at
762 the class level or in a Parameterized constructor call. The
763 value is otherwise constant on the Parameterized instance,
764 once it has been constructed.
765
766 readonly: if true, the Parameter value cannot ordinarily be
767 changed by setting the attribute at the class or instance
768 levels at all. The value can still be changed in code by
769 temporarily overriding the value of this slot and then
770 restoring it, which is useful for reporting values that the
771 _user_ should never change but which do change during code
772 execution.
773
774 pickle_default_value: whether the default value should be
775 pickled. Usually, you would want the default value to be pickled,
776 but there are rare cases where that would not be the case (e.g.
777 for file search paths that are specific to a certain system).
778
779 per_instance: whether a separate Parameter instance will be
780 created for every Parameterized instance. True by default.
781 If False, all instances of a Parameterized class will share
782 the same Parameter object, including all validation
783 attributes (bounds, etc.). See also instantiate, which is
784 conceptually similar but affects the Parameter value rather
785 than the Parameter object.
786
787 allow_None: if True, None is accepted as a valid value for
788 this Parameter, in addition to any other values that are
789 allowed. If the default value is defined as None, allow_None
790 is set to True automatically.
791
792 default, doc, and precedence all default to None, which allows
689793 inheritance of Parameter slots (attributes) from the owning-class'
690794 class hierarchy (see ParameterizedMetaclass).
691
692 per_instance defaults to True and controls whether a new
693 Parameter instance can be created for every Parameterized
694 instance. If False, all instances of a Parameterized class
695 will share the same parameter object, including all validation
696 attributes.
697
698 In rare cases where the default value should not be pickled,
699 set pickle_default_value=False (e.g. for file search paths).
700 """
795 """
796
701797 self.name = None
702 self._internal_name = None
703798 self.owner = None
704 self._label = label
705799 self.precedence = precedence
706800 self.default = default
707801 self.doc = doc
708802 self.constant = constant or readonly # readonly => constant
709803 self.readonly = readonly
804 self._label = label
805 self._internal_name = None
710806 self._set_instantiate(instantiate)
711807 self.pickle_default_value = pickle_default_value
712808 self.allow_None = (default is None or allow_None)
713809 self.watchers = {}
714810 self.per_instance = per_instance
715811
812 @classmethod
813 def serialize(cls, value):
814 "Given the parameter value, return a Python value suitable for serialization"
815 return value
816
817 @classmethod
818 def deserialize(cls, value):
819 "Given a serializable Python value, return a value that the parameter can be set to"
820 return value
821
822 def schema(self, safe=False, subset=None, mode='json'):
823 if serializer is None:
824 raise ImportError('Cannot import serializer.py needed to generate schema')
825 if mode not in self._serializers:
826 raise KeyError('Mode %r not in available serialization formats %r'
827 % (mode, list(self._serializers.keys())))
828 return self._serializers[mode].parameter_schema(self.__class__.__name__, self,
829 safe=safe, subset=subset)
716830
717831 @property
718832 def label(self):
735849 else:
736850 self.instantiate = instantiate or self.constant # pylint: disable-msg=W0201
737851
738
739 # TODO: quick trick to allow subscription to the setting of
740 # parameter metadata. ParameterParameter?
741
742 # Note that unlike with parameter value setting, there's no access
743 # to the Parameterized instance, so no per-instance subscription.
744
745 def __setattr__(self,attribute,value):
746 implemented = (attribute!="default" and hasattr(self,'watchers') and attribute in self.watchers)
852 def __setattr__(self, attribute, value):
853 implemented = (attribute != "default" and hasattr(self, 'watchers') and attribute in self.watchers)
854 slot_attribute = attribute in self.__slots__
747855 try:
748 old = getattr(self,attribute) if implemented else NotImplemented
856 old = getattr(self, attribute) if implemented else NotImplemented
857 if slot_attribute:
858 self._on_set(attribute, old, value)
749859 except AttributeError as e:
750 if attribute in self.__slots__:
860 if slot_attribute:
751861 # If Parameter slot is defined but an AttributeError was raised
752862 # we are in __setstate__ and watchers should not be triggered
753863 old = NotImplemented
756866
757867 super(Parameter, self).__setattr__(attribute, value)
758868
759 if old is not NotImplemented:
760 event = Event(what=attribute,name=self.name,obj=None,cls=self.owner,old=old,new=value, type=None)
761 for watcher in self.watchers[attribute]:
762 self.owner.param._call_watcher(watcher, event)
763 if not self.owner.param._BATCH_WATCH:
764 self.owner.param._batch_call_watchers()
765
766
767 def __get__(self,obj,objtype): # pylint: disable-msg=W0613
869 if old is NotImplemented:
870 return
871
872 event = Event(what=attribute,name=self.name, obj=None, cls=self.owner,
873 old=old, new=value, type=None)
874 for watcher in self.watchers[attribute]:
875 self.owner.param._call_watcher(watcher, event)
876 if not self.owner.param._BATCH_WATCH:
877 self.owner.param._batch_call_watchers()
878
879 def _on_set(self, attribute, old, value):
880 """
881 Can be overridden on subclasses to handle changes when parameter
882 attribute is set.
883 """
884
885 def __get__(self, obj, objtype): # pylint: disable-msg=W0613
768886 """
769887 Return the value for this Parameter.
770888
785903 result = obj.__dict__.get(self._internal_name,self.default)
786904 return result
787905
788
789906 @instance_descriptor
790 def __set__(self,obj,val):
907 def __set__(self, obj, val):
791908 """
792909 Set the value for this Parameter.
793910
826943 # Parameterized class)
827944 if self.constant or self.readonly:
828945 if self.readonly:
829 raise TypeError("Read-only parameter '%s' cannot be modified"%self.name)
830 elif obj is None: #not obj
946 raise TypeError("Read-only parameter '%s' cannot be modified" % self.name)
947 elif obj is None:
831948 _old = self.default
832949 self.default = val
833950 elif not obj.initialized:
834 _old = obj.__dict__.get(self._internal_name,self.default)
951 _old = obj.__dict__.get(self._internal_name, self.default)
835952 obj.__dict__[self._internal_name] = val
836953 else:
837 raise TypeError("Constant parameter '%s' cannot be modified"%self.name)
838
954 _old = obj.__dict__.get(self._internal_name, self.default)
955 if val is not _old:
956 raise TypeError("Constant parameter '%s' cannot be modified"%self.name)
839957 else:
840958 if obj is None:
841959 _old = self.default
847965 self._post_setter(obj, val)
848966
849967 if obj is None:
850 watchers = self.watchers.get("value",[])
968 watchers = self.watchers.get("value")
969 elif hasattr(obj, '_param_watchers') and self.name in obj._param_watchers:
970 watchers = obj._param_watchers[self.name].get('value')
971 if watchers is None:
972 watchers = self.watchers.get("value")
851973 else:
852 watchers = getattr(obj,"_param_watchers",{}).get(self.name,{}).get('value',self.watchers.get("value",[]))
853
854 event = Event(what='value',name=self.name,obj=obj,cls=self.owner,old=_old,new=val, type=None)
974 watchers = None
975
855976 obj = self.owner if obj is None else obj
856 if obj is None:
977 if obj is None or not watchers:
857978 return
858979
980 event = Event(what='value',name=self.name, obj=obj, cls=self.owner,
981 old=_old, new=val, type=None)
859982 for watcher in watchers:
860983 obj.param._call_watcher(watcher, event)
861984 if not obj.param._BATCH_WATCH:
862985 obj.param._batch_call_watchers()
863986
987 def _validate_value(self, value, allow_None):
988 """Implements validation for parameter value"""
864989
865990 def _validate(self, val):
866 """Implements validation for the parameter"""
867
991 """Implements validation for the parameter value and attributes"""
992 self._validate_value(val, self.allow_None)
868993
869994 def _post_setter(self, obj, val):
870995 """Called after the parameter value has been validated and set"""
871996
872
873997 def __delete__(self,obj):
874998 raise TypeError("Cannot delete '%s': Parameters deletion not allowed." % self.name)
875
876999
8771000 def _set_names(self, attrib_name):
8781001 if None not in (self.owner, self.name) and attrib_name != self.name:
8851008 % (type(self).__name__, self.name,
8861009 self.owner.name, attrib_name))
8871010 self.name = attrib_name
888
889 self._internal_name = "_%s_param_value"%attrib_name
890
1011 self._internal_name = "_%s_param_value" % attrib_name
8911012
8921013 def __getstate__(self):
8931014 """
9311052 ip_regex = '^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$'
9321053 super(IPAddress, self).__init__(default=default, regex=ip_regex, **kwargs)
9331054
934
9351055 """
9361056
9371057 __slots__ = ['regex']
9421062 self.allow_None = (default is None or allow_None)
9431063 self._validate(default)
9441064
1065 def _validate_regex(self, val, regex):
1066 if (val is None and self.allow_None):
1067 return
1068 if regex is not None and re.match(regex, val) is None:
1069 raise ValueError("String parameter %r value %r does not match regex %r."
1070 % (self.name, val, regex))
1071
1072 def _validate_value(self, val, allow_None):
1073 if allow_None and val is None:
1074 return
1075 if not isinstance(val, basestring):
1076 raise ValueError("String parameter %r only takes a string value, "
1077 "not value of type %s." % (self.name, type(val)))
1078
9451079 def _validate(self, val):
946 if self.allow_None and val is None:
947 return
948
949 if not isinstance(val, basestring):
950 raise ValueError("String '%s' only takes a string value."%self.name)
951
952 if self.regex is not None and re.match(self.regex, val) is None:
953 raise ValueError("String '%s': '%s' does not match regex '%s'."%(self.name,val,self.regex))
1080 self._validate_value(val, self.allow_None)
1081 self._validate_regex(val, self.regex)
9541082
9551083
9561084 class shared_parameters(object):
9851113 @wraps(fn)
9861114 def override_initialization(self_,*args,**kw):
9871115 parameterized_instance = self_.self
988 original_initialized=parameterized_instance.initialized
989 parameterized_instance.initialized=False
990 fn(parameterized_instance,*args,**kw)
991 parameterized_instance.initialized=original_initialized
1116 original_initialized = parameterized_instance.initialized
1117 parameterized_instance.initialized = False
1118 fn(parameterized_instance, *args, **kw)
1119 parameterized_instance.initialized = original_initialized
9921120 return override_initialization
9931121
9941122
10611189 class or the instance as necessary.
10621190 """
10631191
1064 _disable_stubs = None # Flag used to disable stubs in the API1 tests
1192 _disable_stubs = False # Flag used to disable stubs in the API1 tests
10651193 # None for no action, True to raise and False to warn.
10661194
10671195 def __init__(self_, cls, self=None):
10711199 """
10721200 self_.cls = cls
10731201 self_.self = self
1074 self_._BATCH_WATCH = False # If true, Event and watcher objects are queued.
1075 self_._TRIGGER = False
1076 self_._events = [] # Queue of batched eventd
1077 self_._watchers = [] # Queue of batched watchers
1202
1203 @property
1204 def _BATCH_WATCH(self_):
1205 return self_.self_or_cls._parameters_state['BATCH_WATCH']
1206
1207 @_BATCH_WATCH.setter
1208 def _BATCH_WATCH(self_, value):
1209 self_.self_or_cls._parameters_state['BATCH_WATCH'] = value
1210
1211 @property
1212 def _TRIGGER(self_):
1213 return self_.self_or_cls._parameters_state['TRIGGER']
1214
1215 @_TRIGGER.setter
1216 def _TRIGGER(self_, value):
1217 self_.self_or_cls._parameters_state['TRIGGER'] = value
1218
1219 @property
1220 def _events(self_):
1221 return self_.self_or_cls._parameters_state['events']
1222
1223 @_events.setter
1224 def _events(self_, value):
1225 self_.self_or_cls._parameters_state['events'] = value
1226
1227 @property
1228 def _watchers(self_):
1229 return self_.self_or_cls._parameters_state['watchers']
1230
1231 @_watchers.setter
1232 def _watchers(self_, value):
1233 self_.self_or_cls._parameters_state['watchers'] = value
10781234
10791235 @property
10801236 def self_or_cls(self_):
10811237 return self_.cls if self_.self is None else self_.self
10821238
1239 def __setstate__(self, state):
1240 # Set old parameters state on Parameterized._parameters_state
1241 self_or_cls = state.get('self', state.get('cls'))
1242 for k in self_or_cls._parameters_state:
1243 key = '_'+k
1244 if key in state:
1245 self_or_cls._parameters_state[k] = state.pop(key)
1246 for k, v in state.items():
1247 setattr(self, k, v)
10831248
10841249 def __getitem__(self_, key):
10851250 """
10881253 inst = self_.self
10891254 parameters = self_.objects(False) if inst is None else inst.param.objects(False)
10901255 p = parameters[key]
1091 if (inst is not None and p.per_instance and
1256 if (inst is not None and getattr(inst, 'initialized', False) and p.per_instance and
10921257 not getattr(inst, '_disable_instance__params', False)):
10931258 if key not in inst._instance__params:
10941259 try:
10991264 except:
11001265 raise
11011266 finally:
1102 p.watchers = watchers
1267 p.watchers = {k: list(v) for k, v in watchers.items()}
11031268 p.owner = inst
11041269 inst._instance__params[key] = p
11051270 else:
11701335 First, ensures that all Parameters with 'instantiate=True'
11711336 (typically used for mutable Parameters) are copied directly
11721337 into each object, to ensure that there is an independent copy
1173 (to avoid suprising aliasing errors). Then sets each of the
1338 (to avoid surprising aliasing errors). Then sets each of the
11741339 keyword arguments, warning when any of them are not defined as
11751340 parameters.
11761341
11841349 for class_ in classlist(type(self)):
11851350 if not issubclass(class_, Parameterized):
11861351 continue
1187 for (k,v) in class_.__dict__.items():
1352 for (k, v) in class_.param._parameters.items():
11881353 # (avoid replacing name with the default of None)
1189 if isinstance(v,Parameter) and v.instantiate and k!="name":
1190 params_to_instantiate[k]=v
1354 if v.instantiate and k != "name":
1355 params_to_instantiate[k] = v
11911356
11921357 for p in params_to_instantiate.values():
11931358 self.param._instantiate_param(p)
11941359
11951360 ## keyword arg setting
1196 for name,val in params.items():
1361 for name, val in params.items():
11971362 desc = self.__class__.get_param_descriptor(name)[0] # pylint: disable-msg=E1101
11981363 if not desc:
1199 self.param.warning("Setting non-parameter attribute %s=%s using a mechanism intended only for parameters",name,val)
1364 self.param.warning("Setting non-parameter attribute %s=%s using a mechanism intended only for parameters", name, val)
12001365 # i.e. if not desc it's setting an attribute in __dict__, not a Parameter
1201 setattr(self,name,val)
1366 setattr(self, name, val)
12021367
12031368 @classmethod
12041369 def deprecate(cls, fn):
12311396
12321397
12331398 # CEBALERT: this is a bit ugly
1234 def _instantiate_param(self_,param_obj,dict_=None,key=None):
1399 def _instantiate_param(self_, param_obj, dict_=None, key=None):
12351400 # deepcopy param_obj.default into self.__dict__ (or dict_ if supplied)
12361401 # under the parameter's _internal_name (or key if supplied)
12371402 self = self_.self
12381403 dict_ = dict_ or self.__dict__
12391404 key = key or param_obj._internal_name
1240 param_key = (str(type(self)), param_obj.name)
12411405 if shared_parameters._share:
1406 param_key = (str(type(self)), param_obj.name)
12421407 if param_key in shared_parameters._shared_cache:
12431408 new_object = shared_parameters._shared_cache[param_key]
12441409 else:
12461411 shared_parameters._shared_cache[param_key] = new_object
12471412 else:
12481413 new_object = copy.deepcopy(param_obj.default)
1249 dict_[key]=new_object
1250
1251 if isinstance(new_object,Parameterized):
1414
1415 dict_[key] = new_object
1416
1417 if isinstance(new_object, Parameterized):
12521418 global object_count
1253 object_count+=1
1419 object_count += 1
12541420 # CB: writes over name given to the original object;
12551421 # should it instead keep the same name?
12561422 new_object.param._generate_name()
13081474 Includes Parameters from this class and its
13091475 superclasses.
13101476 """
1311 if self_.self is not None and self_.self._instance__params:
1312 self_.warning('The Parameterized instance has instance '
1313 'parameters created using new-style param '
1314 'APIs, which are incompatible with .params. '
1315 'Use the new more explicit APIs on the '
1316 '.param accessor to query parameter instances.'
1317 'To query all parameter instances use '
1318 '.param.objects with the option to return '
1319 'either class or instance parameter objects. '
1320 'Alternatively use .param[name] indexing to '
1321 'access a specific parameter object by name.')
1322
13231477 pdict = self_.objects(instance='existing')
13241478 if parameter_name is None:
13251479 return pdict
13491503 raise ValueError("Invalid positional arguments for %s.set_param" %
13501504 (self_or_cls.name))
13511505
1506 trigger_params = [k for k in kwargs
1507 if ((k in self_.self_or_cls.param) and
1508 hasattr(self_.self_or_cls.param[k], '_autotrigger_value'))]
1509
1510 for tp in trigger_params:
1511 self_.self_or_cls.param[tp]._mode = 'set'
1512
13521513 for (k, v) in kwargs.items():
13531514 if k not in self_or_cls.param:
13541515 self_.self_or_cls.param._BATCH_WATCH = False
13631524 if not BATCH_WATCH:
13641525 self_._batch_call_watchers()
13651526
1527 for tp in trigger_params:
1528 p = self_.self_or_cls.param[tp]
1529 p._mode = 'reset'
1530 setattr(self_or_cls, tp, p._autotrigger_reset_value)
1531 p._mode = 'set-reset'
13661532
13671533 def objects(self_, instance=True):
13681534 """
13971563
13981564 if instance and self_.self is not None:
13991565 if instance == 'existing':
1400 if self_.self._instance__params:
1566 if getattr(self_.self, 'initialized', False) and self_.self._instance__params:
14011567 return dict(pdict, **self_.self._instance__params)
14021568 return pdict
14031569 else:
14091575 """
14101576 Trigger watchers for the given set of parameter names. Watchers
14111577 will be triggered whether or not the parameter values have
1412 actually changed.
1413 """
1578 actually changed. As a special case, the value will actually be
1579 changed for a Parameter of type Event, setting it to True so
1580 that it is clear which Event parameter has been triggered.
1581 """
1582 trigger_params = [p for p in self_.self_or_cls.param
1583 if hasattr(self_.self_or_cls.param[p], '_autotrigger_value')]
1584 triggers = {p:self_.self_or_cls.param[p]._autotrigger_value
1585 for p in trigger_params if p in param_names}
1586
14141587 events = self_.self_or_cls.param._events
14151588 watchers = self_.self_or_cls.param._watchers
14161589 self_.self_or_cls.param._events = []
14181591 param_values = dict(self_.get_param_values())
14191592 params = {name: param_values[name] for name in param_names}
14201593 self_.self_or_cls.param._TRIGGER = True
1421 self_.set_param(**params)
1594 self_.set_param(**dict(params, **triggers))
14221595 self_.self_or_cls.param._TRIGGER = False
14231596 self_.self_or_cls.param._events += events
14241597 self_.self_or_cls.param._watchers += watchers
14341607 event_type = 'changed' if watcher.onlychanged else 'set'
14351608 return Event(what=event.what, name=event.name, obj=event.obj, cls=event.cls,
14361609 old=event.old, new=event.new, type=event_type)
1610
1611 def _execute_watcher(self, watcher, events):
1612 if watcher.mode == 'args':
1613 args, kwargs = events, {}
1614 else:
1615 args, kwargs = (), {event.name: event.new for event in events}
1616
1617 if iscoroutinefunction(watcher.fn):
1618 if async_executor is None:
1619 raise RuntimeError("Could not execute %s coroutine function. "
1620 "Please register a asynchronous executor on "
1621 "param.parameterized.async_executor, which "
1622 "schedules the function on an event loop." %
1623 watcher.fn)
1624 async_executor(partial(watcher.fn, *args, **kwargs))
1625 else:
1626 watcher.fn(*args, **kwargs)
14371627
14381628 def _call_watcher(self_, watcher, event):
14391629 """
14511641 else:
14521642 event = self_._update_event_type(watcher, event, self_.self_or_cls.param._TRIGGER)
14531643 with batch_watch(self_.self_or_cls, enable=watcher.queued, run=False):
1454 if watcher.mode == 'args':
1455 watcher.fn(event)
1456 else:
1457 watcher.fn(**{event.name: event.new})
1458
1644 self_._execute_watcher(watcher, (event,))
14591645
14601646 def _batch_call_watchers(self_):
14611647 """
14751661 for name in watcher.parameter_names
14761662 if (name, watcher.what) in event_dict]
14771663 with batch_watch(self_.self_or_cls, enable=watcher.queued, run=False):
1478 if watcher.mode == 'args':
1479 watcher.fn(*events)
1480 else:
1481 watcher.fn(**{c.name:c.new for c in events})
1482
1664 self_._execute_watcher(watcher, events)
14831665
14841666 def set_dynamic_time_fn(self_,time_fn,sublistattr=None):
14851667 """
15221704 for obj in sublist:
15231705 obj.param.set_dynamic_time_fn(time_fn,sublistattr)
15241706
1525 def get_param_values(self_,onlychanged=False):
1707 def serialize_parameters(self_, subset=None, mode='json'):
1708 self_or_cls = self_.self_or_cls
1709 if mode not in Parameter._serializers:
1710 raise ValueError('Mode %r not in available serialization formats %r'
1711 % (mode, list(Parameter._serializers.keys())))
1712 serializer = Parameter._serializers[mode]
1713 return serializer.serialize_parameters(self_or_cls, subset=subset)
1714
1715 def serialize_value(self_, pname, mode='json'):
1716 self_or_cls = self_.self_or_cls
1717 if mode not in Parameter._serializers:
1718 raise ValueError('Mode %r not in available serialization formats %r'
1719 % (mode, list(Parameter._serializers.keys())))
1720 serializer = Parameter._serializers[mode]
1721 return serializer.serialize_parameter_value(self_or_cls, pname)
1722
1723 def deserialize_parameters(self_, serialization, subset=None, mode='json'):
1724 self_or_cls = self_.self_or_cls
1725 serializer = Parameter._serializers[mode]
1726 return serializer.deserialize_parameters(self_or_cls, serialization, subset=subset)
1727
1728 def deserialize_value(self_, pname, value, mode='json'):
1729 self_or_cls = self_.self_or_cls
1730 if mode not in Parameter._serializers:
1731 raise ValueError('Mode %r not in available serialization formats %r'
1732 % (mode, list(Parameter._serializers.keys())))
1733 serializer = Parameter._serializers[mode]
1734 return serializer.deserialize_parameter_value(self_or_cls, pname, value)
1735
1736 def schema(self_, safe=False, subset=None, mode='json'):
1737 """
1738 Returns a schema for the parameters on this Parameterized object.
1739 """
1740 self_or_cls = self_.self_or_cls
1741 if mode not in Parameter._serializers:
1742 raise ValueError('Mode %r not in available serialization formats %r'
1743 % (mode, list(Parameter._serializers.keys())))
1744 serializer = Parameter._serializers[mode]
1745 return serializer.schema(self_or_cls, safe=safe, subset=subset)
1746
1747 def get_param_values(self_, onlychanged=False):
15261748 """
15271749 Return a list of name,value pairs for all Parameters of this
15281750 object.
15371759 # (would need to distinguish instantiation of default from
15381760 # user setting of value).
15391761 vals = []
1540 for name,val in self_or_cls.param.objects('existing').items():
1762 for name, val in self_or_cls.param.objects('existing').items():
15411763 value = self_or_cls.param.get_value_generator(name)
15421764 # (this is pointless for cls)
1543 if not onlychanged or not all_equal(value,val.default):
1544 vals.append((name,value))
1765 if not onlychanged or not all_equal(value, val.default):
1766 vals.append((name, value))
15451767
15461768 vals.sort(key=itemgetter(0))
15471769 return vals
17581980 """
17591981 self = self_.self
17601982 d = {}
1761 for param_name,param in self.param.objects('existing').items():
1983 for param_name, param in self.param.objects('existing').items():
17621984 if param.constant:
17631985 pass
1764 elif param.instantiate:
1765 self.param._instantiate_param(param,dict_=d,key=param_name)
1766 else:
1767 d[param_name]=param.default
1986 if param.instantiate:
1987 self.param._instantiate_param(param, dict_=d, key=param_name)
1988 d[param_name] = param.default
17681989 return d
17691990
17701991 # CEBALERT: designed to avoid any processing unless the print
18832104 # 'name' to '__name__'?)
18842105 mcs.name = name
18852106
1886 mcs.param = Parameters(mcs)
2107 mcs._parameters_state = {
2108 "BATCH_WATCH": False, # If true, Event and watcher objects are queued.
2109 "TRIGGER": False,
2110 "events": [], # Queue of batched events
2111 "watchers": [] # Queue of batched watchers
2112 }
2113 mcs._param = Parameters(mcs)
18872114
18882115 # All objects (with their names) of type Parameter that are
18892116 # defined in this class
18902117 parameters = [(n,o) for (n,o) in dict_.items()
1891 if isinstance(o,Parameter)]
2118 if isinstance(o, Parameter)]
2119
2120 mcs._param._parameters = dict(parameters)
18922121
18932122 for param_name,param in parameters:
18942123 mcs._initialize_parameter(param_name,param)
19602189 # _ParameterizedMetaclass__abstract before running, but
19612190 # the actual class object will have an attribute
19622191 # _ClassName__abstract. So, we have to mangle it ourselves at
1963 # runtime.
2192 # runtime. Mangling follows description in https://docs.python.org/2/tutorial/classes.html#private-variables-and-class-local-references
19642193 try:
1965 return getattr(mcs,'_%s__abstract'%mcs.__name__)
2194 return getattr(mcs,'_%s__abstract'%mcs.__name__.lstrip("_"))
19662195 except AttributeError:
19672196 return False
19682197
19692198 abstract = property(__is_abstract)
19702199
1971
2200 def _get_param(mcs):
2201 return mcs._param
2202
2203 param = property(_get_param)
19722204
19732205 def __setattr__(mcs,attribute_name,value):
19742206 """
20482280 Note that instantiate is handled differently: if there is a
20492281 parameter with the same name in one of the superclasses with
20502282 instantiate set to True, this parameter will inherit
2051 instatiate=True.
2283 instantiate=True.
20522284 """
20532285 # get all relevant slots (i.e. slots defined in all
20542286 # superclasses of this parameter)
22712503 dbprint_prefix=None
22722504
22732505
2274
2275
2276
2506 # Copy of Python 3.2 reprlib's recursive_repr but allowing extra arguments
2507 if sys.version_info.major >= 3:
2508 from threading import get_ident
2509 def recursive_repr(fillvalue='...'):
2510 'Decorator to make a repr function return fillvalue for a recursive call'
2511
2512 def decorating_function(user_function):
2513 repr_running = set()
2514
2515 def wrapper(self, *args, **kwargs):
2516 key = id(self), get_ident()
2517 if key in repr_running:
2518 return fillvalue
2519 repr_running.add(key)
2520 try:
2521 result = user_function(self, *args, **kwargs)
2522 finally:
2523 repr_running.discard(key)
2524 return result
2525 return wrapper
2526
2527 return decorating_function
2528 else:
2529 def recursive_repr(fillvalue='...'):
2530 def decorating_function(user_function):
2531 return user_function
2532 return decorating_function
22772533
22782534
22792535 @add_metaclass(ParameterizedMetaclass)
23202576 see documentation for the 'logging' module.
23212577 """
23222578
2323 name = String(default=None,constant=True,doc="""
2324 String identifier for this object.""")
2325
2326
2327 def __init__(self,**params):
2579 name = String(default=None, constant=True, doc="""
2580 String identifier for this object.""")
2581
2582 def __init__(self, **params):
23282583 global object_count
23292584
23302585 # Flag that can be tested to see if e.g. constant Parameters
23312586 # can still be set
2332 self.initialized=False
2333 # Override class level param namespace with instance namespace
2334 self.param = Parameters(self.__class__, self=self)
2587 self.initialized = False
2588 self._parameters_state = {
2589 "BATCH_WATCH": False, # If true, Event and watcher objects are queued.
2590 "TRIGGER": False,
2591 "events": [], # Queue of batched events
2592 "watchers": [] # Queue of batched watchers
2593 }
23352594 self._instance__params = {}
23362595 self._param_watchers = {}
23372596
23482607 # instantiation of Parameterized with watched deps. Will
23492608 # probably store expanded deps on class - see metaclass
23502609 # 'dependers'.
2351 for p in self.param.params_depended_on(n):
2610 grouped = defaultdict(list)
2611 for dep in self.param.params_depended_on(n):
2612 grouped[(id(dep.inst),id(dep.cls),dep.what)].append(dep)
2613 for group in grouped.values():
23522614 # TODO: can't remember why not just pass m (rather than _m_caller) here
2353 (p.inst or p.cls).param.watch(_m_caller(self, n), p.name, p.what, queued=queued)
2354
2355 self.initialized=True
2615 gdep = group[0] # Need to grab representative dep from this group
2616 (gdep.inst or gdep.cls).param.watch(_m_caller(self, n), [d.name for d in group], gdep.what, queued=queued)
2617
2618 self.initialized = True
2619
2620 @property
2621 def param(self):
2622 return Parameters(self.__class__, self=self)
23562623
23572624 # 'Special' methods
23582625
23642631 """
23652632 # remind me, why is it a copy? why not just state.update(self.__dict__)?
23662633 state = self.__dict__.copy()
2367
23682634 for slot in get_occupied_slots(self):
23692635 state[slot] = getattr(self,slot)
23702636
23852651 """
23862652 self.initialized=False
23872653
2654 # When making a copy the internal watchers have to be
2655 # recreated and point to the new instance
2656 if '_param_watchers' in state:
2657 param_watchers = state['_param_watchers']
2658 for p, attrs in param_watchers.items():
2659 for attr, watchers in attrs.items():
2660 new_watchers = []
2661 for watcher in watchers:
2662 watcher_args = list(watcher)
2663 if watcher.inst is not None:
2664 watcher_args[0] = self
2665 fn = watcher.fn
2666 if hasattr(fn, '_watcher_name'):
2667 watcher_args[2] = _m_caller(self, fn._watcher_name)
2668 elif get_method_owner(fn) is watcher.inst:
2669 watcher_args[2] = getattr(self, fn.__name__)
2670 new_watchers.append(Watcher(*watcher_args))
2671 param_watchers[p][attr] = new_watchers
2672
23882673 if '_instance__params' not in state:
23892674 state['_instance__params'] = {}
23902675 if '_param_watchers' not in state:
23912676 state['_param_watchers'] = {}
2677 state.pop('param', None)
23922678
23932679 for name,value in state.items():
23942680 setattr(self,name,value)
23952681 self.initialized=True
23962682
2683 @recursive_repr()
23972684 def __repr__(self):
23982685 """
23992686 Provide a nearly valid Python representation that could be used to recreate
24212708 return self.pprint(imports,prefix, unknown_value=None, qualify=True,
24222709 separator="\n")
24232710
2711 @recursive_repr()
24242712 # CEBALERT: not yet properly documented
24252713 def pprint(self, imports=None, prefix=" ", unknown_value='<?>',
24262714 qualify=False, separator=""):
27933081 cls = self_or_cls
27943082 else:
27953083 p = params
2796 params = dict(self_or_cls.get_param_values())
3084 params = dict(self_or_cls.param.get_param_values())
27973085 params.update(p)
27983086 params.pop('name')
27993087 cls = self_or_cls.__class__
0 """
1 Classes used to support string serialization of Parameters and
2 Parameterized objects.
3 """
4
5 import json
6
7 class UnserializableException(Exception):
8 pass
9
10 class UnsafeserializableException(Exception):
11 pass
12
13 def JSONNullable(json_type):
14 "Express a JSON schema type as nullable to easily support Parameters that allow_None"
15 return { "anyOf": [ json_type, { "type": "null"}] }
16
17
18
19 class Serialization(object):
20 """
21 Base class used to implement different types of serialization.
22 """
23
24 @classmethod
25 def schema(cls, pobj, subset=None):
26 raise NotImplementedError # noqa: unimplemented method
27
28 @classmethod
29 def serialize_parameters(cls, pobj, subset=None):
30 """
31 Serialize the parameters on a Parameterized object into a
32 single serialized object, e.g. a JSON string.
33 """
34 raise NotImplementedError # noqa: unimplemented method
35
36 @classmethod
37 def deserialize_parameters(cls, pobj, serialized, subset=None):
38 """
39 Deserialize a serialized object representing one or
40 more Parameters into a dictionary of parameter values.
41 """
42 raise NotImplementedError # noqa: unimplemented method
43
44 @classmethod
45 def serialize_parameter_value(cls, pobj, pname):
46 """
47 Serialize a single parameter value.
48 """
49 raise NotImplementedError # noqa: unimplemented method
50
51 @classmethod
52 def deserialize_parameter_value(cls, pobj, pname, value):
53 """
54 Deserialize a single parameter value.
55 """
56 raise NotImplementedError # noqa: unimplemented method
57
58
59 class JSONSerialization(Serialization):
60 """
61 Class responsible for specifying JSON serialization, deserialization
62 and JSON schemas for Parameters and Parameterized classes and
63 objects.
64 """
65
66 unserializable_parameter_types = ['Callable']
67
68 json_schema_literal_types = {int:'integer', float:'number', str:'string',
69 type(None):'null'}
70
71 @classmethod
72 def loads(cls, serialized):
73 return json.loads(serialized)
74
75 @classmethod
76 def dumps(cls, obj):
77 return json.dumps(obj)
78
79 @classmethod
80 def schema(cls, pobj, safe=False, subset=None):
81 schema = {}
82 for name, p in pobj.param.objects('existing').items():
83 if subset is not None and name not in subset:
84 continue
85 schema[name] = p.schema(safe=safe)
86 if p.doc:
87 schema[name]["description"] = p.doc.strip()
88 if p.label:
89 schema[name]["title"] = p.label
90 return schema
91
92 @classmethod
93 def serialize_parameters(cls, pobj, subset=None):
94 components = {}
95 for name, p in pobj.param.objects('existing').items():
96 if subset is not None and name not in subset:
97 continue
98 value = pobj.param.get_value_generator(name)
99 components[name] = p.serialize(value)
100 return cls.dumps(components)
101
102 @classmethod
103 def deserialize_parameters(cls, pobj, serialization, subset=None):
104 deserialized = cls.loads(serialization)
105 components = {}
106 for name, value in deserialized.items():
107 if subset is not None and name not in subset:
108 continue
109 deserialized = pobj.param[name].deserialize(value)
110 components[name] = deserialized
111 return components
112
113 # Parameter level methods
114
115 @classmethod
116 def _get_method(cls, ptype, suffix):
117 "Returns specialized method if available, otherwise None"
118 method_name = ptype.lower()+'_' + suffix
119 return getattr(cls, method_name, None)
120
121 @classmethod
122 def parameter_schema(cls, ptype, p, safe=False, subset=None):
123 if ptype in cls.unserializable_parameter_types:
124 raise UnserializableException
125 dispatch_method = cls._get_method(ptype, 'schema')
126 if dispatch_method:
127 schema = dispatch_method(p, safe=safe)
128 else:
129 schema = { "type": ptype.lower()}
130
131 return JSONNullable(schema) if p.allow_None else schema
132
133 @classmethod
134 def serialize_parameter_value(cls, pobj, pname):
135 value = pobj.param.get_value_generator(pname)
136 return cls.dumps(pobj.param[pname].serialize(value))
137
138 @classmethod
139 def deserialize_parameter_value(cls, pobj, pname, value):
140 value = cls.loads(value)
141 return pobj.param[pname].deserialize(value)
142
143 # Custom Schemas
144
145 @classmethod
146 def array_schema(cls, p, safe=False):
147 if safe is True:
148 msg = ('Array is not guaranteed to be safe for '
149 'serialization as the dtype is unknown')
150 raise UnsafeserializableException(msg)
151 return { "type": "array"}
152
153 @classmethod
154 def dict_schema(cls, p, safe=False):
155 if safe is True:
156 msg = ('Dict is not guaranteed to be safe for '
157 'serialization as the key and value types are unknown')
158 raise UnsafeserializableException(msg)
159 return { "type": "object"}
160
161 @classmethod
162 def date_schema(cls, p, safe=False):
163 return { "type": "string", "format": "date-time"}
164
165 @classmethod
166 def calendardate_schema(cls, p, safe=False):
167 return { "type": "string", "format": "date"}
168
169 @classmethod
170 def tuple_schema(cls, p, safe=False):
171 schema = { "type": "array"}
172 if p.length is not None:
173 schema['minItems'] = p.length
174 schema['maxItems'] = p.length
175 return schema
176
177 @classmethod
178 def number_schema(cls, p, safe=False):
179 schema = { "type": p.__class__.__name__.lower() }
180 return cls.declare_numeric_bounds(schema, p.bounds, p.inclusive_bounds)
181
182 @classmethod
183 def declare_numeric_bounds(cls, schema, bounds, inclusive_bounds):
184 "Given an applicable numeric schema, augment with bounds information"
185 if bounds is not None:
186 (low, high) = bounds
187 if low is not None:
188 key = 'minimum' if inclusive_bounds[0] else 'exclusiveMinimum'
189 schema[key] = low
190 if high is not None:
191 key = 'maximum' if inclusive_bounds[1] else 'exclusiveMaximum'
192 schema[key] = high
193 return schema
194
195 @classmethod
196 def integer_schema(cls, p, safe=False):
197 return cls.number_schema(p)
198
199 @classmethod
200 def numerictuple_schema(cls, p, safe=False):
201 schema = cls.tuple_schema(p, safe=safe)
202 schema["additionalItems"] = { "type": "number" }
203 return schema
204
205 @classmethod
206 def xycoordinates_schema(cls, p, safe=False):
207 return cls.numerictuple_schema(p, safe=safe)
208
209 @classmethod
210 def range_schema(cls, p, safe=False):
211 schema = cls.tuple_schema(p, safe=safe)
212 bounded_number = cls.declare_numeric_bounds({ "type": "number" },
213 p.bounds, p.inclusive_bounds)
214 schema["additionalItems"] = bounded_number
215 return schema
216
217 @classmethod
218 def list_schema(cls, p, safe=False):
219 schema = { "type": "array"}
220 if safe is True and p.item_type is None:
221 msg = ('List without a class specified cannot be guaranteed '
222 'to be safe for serialization')
223 raise UnsafeserializableException(msg)
224 if p.item_type is not None and p.item_type in cls.json_schema_literal_types:
225 schema['items'] = {"type": cls.json_schema_literal_types[p.item_type]}
226 return schema
227
228 @classmethod
229 def objectselector_schema(cls, p, safe=False):
230 try:
231 allowed_types = [{'type': cls.json_schema_literal_types[type(obj)]}
232 for obj in p.objects]
233 schema = { "anyOf": allowed_types}
234 schema['enum'] = p.objects
235 return schema
236 except:
237 if safe is True:
238 msg = ('ObjectSelector cannot be guaranteed to be safe for '
239 'serialization due to unserializable type in objects')
240 raise UnsafeserializableException(msg)
241 return {}
242
243 @classmethod
244 def listselector_schema(cls, p, safe=False):
245 if p.objects is None:
246 if safe is True:
247 msg = ('ListSelector cannot be guaranteed to be safe for '
248 'serialization as allowed objects unspecified')
249 return {'type': 'array'}
250 for obj in p.objects:
251 if type(obj) not in cls.json_schema_literal_types:
252 msg = "ListSelector cannot serialize type %s" % type(obj)
253 raise UnserializableException(msg)
254 return {'type': 'array', 'items':{'enum':p.objects}}
255
256
257 @classmethod
258 def dataframe_schema(cls, p, safe=False):
259 schema = {'type': 'array'}
260 if safe is True:
261 msg = ('DataFrame is not guaranteed to be safe for '
262 'serialization as the column dtypes are unknown')
263 raise UnsafeserializableException(msg)
264 if p.columns is None:
265 schema['items'] = {'type': 'object'}
266 return schema
267
268 mincols, maxcols = None, None
269 if isinstance(p.columns, int):
270 mincols, maxcols = p.columns, p.columns
271 elif isinstance(p.columns, tuple):
272 mincols, maxcols = p.columns
273
274 if isinstance(p.columns, int) or isinstance(p.columns, tuple):
275 schema['items'] = {'type': 'object',
276 'minItems': mincols,
277 'maxItems': maxcols}
278
279 if isinstance(p.columns, list) or isinstance(p.columns, set):
280 literal_types = [{'type':el} for el in cls.json_schema_literal_types.values()]
281 allowable_types = {"anyOf": literal_types}
282 properties = {name: allowable_types for name in p.columns}
283 schema['items'] = {'type': 'object',
284 'properties' : properties }
285
286
287 minrows, maxrows = None, None
288 if isinstance(p.rows, int):
289 minrows, maxrows = p.rows, p.rows
290 elif isinstance(p.rows, tuple):
291 minrows, maxrows = p.rows
292
293 if minrows is not None:
294 schema['minItems'] = minrows
295 if maxrows is not None:
296 schema['maxItems'] = maxrows
297
298 return schema
11 Provide consistent and up-to-date ``__version__`` strings for
22 Python packages.
33
4 See https://github.com/pyviz/autover for more information.
4 See https://github.com/holoviz/autover for more information.
55 """
66
77 # The Version class is a copy of autover.version.Version v0.2.5,
2525 cwd=cwd)
2626 output, error = (str(s.decode()).strip() for s in proc.communicate())
2727
28 if proc.returncode != 0:
28 # Detects errors as _either_ a non-zero return code _or_ messages
29 # printed to stderr, because the return code is erroneously fixed at
30 # zero in some cases (see https://github.com/holoviz/param/pull/389).
31 if proc.returncode != 0 or len(error) > 0:
2932 raise Exception(proc.returncode, error)
3033 return output
3134
173176 # Verify this is the correct repository (since fpath could
174177 # be an unrelated git repository, and autover could just have
175178 # been copied/installed into it).
176 output = run_cmd([cmd, 'remote', '-v'],
177 cwd=os.path.dirname(self.fpath))
178 repo_matches = ['', # No remote set
179 '/' + self.reponame + '.git' ,
179 remotes = run_cmd([cmd, 'remote', '-v'],
180 cwd=os.path.dirname(self.fpath))
181 repo_matches = ['/' + self.reponame + '.git' ,
180182 # A remote 'server:reponame.git' can also be referred
181183 # to (i.e. cloned) as `server:reponame`.
182184 '/' + self.reponame + ' ']
183 if not any(m in output for m in repo_matches):
184 return self
185
186 output = run_cmd([cmd, 'describe', '--long', '--match',
187 "v[0-9]*.[0-9]*.[0-9]*", '--dirty'],
188 cwd=os.path.dirname(self.fpath))
185 if not any(m in remotes for m in repo_matches):
186 try:
187 output = self._output_from_file()
188 if output is not None:
189 self._update_from_vcs(output)
190 except: pass
191 if output is None:
192 output = run_cmd([cmd, 'describe', '--long', '--match',
193 "v[0-9]*.[0-9]*.[0-9]*", '--dirty'],
194 cwd=os.path.dirname(self.fpath))
189195 if as_string: return output
190196 except Exception as e1:
191197 try:
0 Metadata-Version: 2.1
1 Name: param
2 Version: None
3 Summary: Make your Python code clearer and more reliable by declaring Parameters.
4 Home-page: http://param.holoviz.org/
5 Author: HoloViz
6 Author-email: developers@holoviz.org
7 Maintainer: HoloViz
8 Maintainer-email: developers@holoviz.org
9 License: BSD
10 Project-URL: Documentation, https://param.holoviz.org/
11 Project-URL: Releases, https://github.com/holoviz/param/releases
12 Project-URL: Bug Tracker, https://github.com/holoviz/param/issues
13 Project-URL: Source Code, https://github.com/holoviz/param
14 Project-URL: Panel Examples, https://panel.holoviz.org/user_guide/Param.html
15 Description: <img src="https://raw.githubusercontent.com/holoviz/param/master/doc/_static/logo_horizontal.png" width=250>
16
17 | | |
18 | --- | --- |
19 | Build Status | [![Linux/MacOS/Windows Build Status](https://github.com/holoviz/param/workflows/pytest/badge.svg)](https://github.com/holoviz/param/actions/workflows/test.yml)
20 | Coverage | [![coveralls](https://coveralls.io/repos/github/holoviz/param/badge.svg?branch=master)](https://coveralls.io/github/holoviz/param?branch=master) |
21 | Latest dev release | [![Github tag](https://img.shields.io/github/v/tag/holoviz/param.svg?label=tag&colorB=11ccbb)](https://github.com/holoviz/param/tags) [![dev-site](https://img.shields.io/website-up-down-green-red/https/pyviz-dev.github.io/param.svg?label=dev%20website)](https://pyviz-dev.github.io/param/) |
22 | Latest release | [![Github release](https://img.shields.io/github/release/holoviz/param.svg?label=tag&colorB=11ccbb)](https://github.com/holoviz/param/releases) [![PyPI version](https://img.shields.io/pypi/v/param.svg?colorB=cc77dd)](https://pypi.python.org/pypi/param) [![param version](https://img.shields.io/conda/v/pyviz/param.svg?colorB=4488ff&style=flat)](https://anaconda.org/pyviz/param) [![conda-forge version](https://img.shields.io/conda/v/conda-forge/param.svg?label=conda%7Cconda-forge&colorB=4488ff)](https://anaconda.org/conda-forge/param) [![defaults version](https://img.shields.io/conda/v/anaconda/param.svg?label=conda%7Cdefaults&style=flat&colorB=4488ff)](https://anaconda.org/anaconda/param) |
23 | Docs | [![gh-pages](https://img.shields.io/github/last-commit/holoviz/param/gh-pages.svg)](https://github.com/holoviz/param/tree/gh-pages) [![site](https://img.shields.io/website-up-down-green-red/https/param.holoviz.org.svg)](https://param.holoviz.org) |
24 | Support | [![Discourse](https://img.shields.io/discourse/status?server=https%3A%2F%2Fdiscourse.holoviz.org)](https://discourse.holoviz.org/) |
25
26 Param is a library providing Parameters: Python attributes extended to have features such as type and range checking, dynamically generated values, documentation strings, default values, etc., each of which is inherited from parent classes if not specified in a subclass.
27
28 Param contains only two required Python files, with no external dependencies, and is provided freely for both non-commercial and commercial use under a BSD license, so that it can easily be included as part of other projects.
29
30 Please see [param's website](https://param.holoviz.org) for official releases, installation instructions, documentation, and examples.
31
32 Platform: Windows
33 Platform: Mac OS X
34 Platform: Linux
35 Classifier: License :: OSI Approved :: BSD License
36 Classifier: Development Status :: 5 - Production/Stable
37 Classifier: Programming Language :: Python :: 2
38 Classifier: Programming Language :: Python :: 2.7
39 Classifier: Programming Language :: Python :: 3
40 Classifier: Programming Language :: Python :: 3.4
41 Classifier: Programming Language :: Python :: 3.5
42 Classifier: Programming Language :: Python :: 3.6
43 Classifier: Programming Language :: Python :: 3.7
44 Classifier: Programming Language :: Python :: 3.8
45 Classifier: Operating System :: OS Independent
46 Classifier: Intended Audience :: Science/Research
47 Classifier: Intended Audience :: Developers
48 Classifier: Natural Language :: English
49 Classifier: Topic :: Scientific/Engineering
50 Classifier: Topic :: Software Development :: Libraries
51 Provides: param
52 Provides: numbergen
53 Requires-Python: >=2.7
54 Description-Content-Type: text/markdown
55 Provides-Extra: all
56 Provides-Extra: doc
57 Provides-Extra: tests
0 LICENSE.txt
1 MANIFEST.in
2 README.md
3 setup.cfg
4 setup.py
5 numbergen/__init__.py
6 param/.version
7 param/__init__.py
8 param/ipython.py
9 param/parameterized.py
10 param/serializer.py
11 param/version.py
12 param.egg-info/PKG-INFO
13 param.egg-info/SOURCES.txt
14 param.egg-info/dependency_links.txt
15 param.egg-info/requires.txt
16 param.egg-info/top_level.txt
0
1 [all]
2 flake8
3 graphviz
4 myst-parser
5 myst_nb==0.12.2
6 nbconvert<6.0
7 nbsite>=0.6.1
8 pydata-sphinx-theme
9 pygraphviz
10 pytest
11 pytest-cov
12
13 [doc]
14 graphviz
15 myst-parser
16 myst_nb==0.12.2
17 nbconvert<6.0
18 nbsite>=0.6.1
19 pydata-sphinx-theme
20 pygraphviz
21
22 [tests]
23 flake8
24 pytest
25 pytest-cov
11 universal = 1
22
33 [flake8]
4 # TODO tests (one day)
54 include = setup.py param numbergen
6 exclude = .git,__pycache__,.tox,.eggs,*.egg,doc,dist,build,_build,tests
7 ignore = E1,
8 E2,
9 E3,
10 E4,
11 E5,
12 E701,
13 E702,
14 E703,
15 E704,
16 E722,
17 E741,
18 E742,
19 E743,
20 W503
5 exclude = .git,__pycache__,.tox,.eggs,*.egg,doc,dist,build,_build,tests,.ipynb_checkpoints,run_test.py
6 ignore = E114,
7 E116,
8 E126,
9 E128,
10 E129,
11 E2,
12 E3,
13 E4,
14 E5,
15 E731,
16 E701,
17 E702,
18 E703,
19 E704,
20 E722,
21 E741,
22 E742,
23 E743,
24 W503,
25 W504,
26 W605
2127
22 [nosetests]
23 verbosity = 2
24 with-doctest = 1
25 nologcapture = 1
28 [tool:pytest]
29 python_files = test*.py
30 addopts = --doctest-modules param numbergen
31
32 [egg_info]
33 tag_build =
34 tag_date = 0
35
1818 # pip doesn't support tests_require
1919 # (https://github.com/pypa/pip/issues/1197)
2020 'tests': [
21 'nose',
22 'flake8'
21 'pytest',
22 'pytest-cov',
23 'flake8',
24 ],
25 'doc': [
26 'pygraphviz',
27 'nbsite >=0.6.1',
28 'pydata-sphinx-theme',
29 'myst-parser',
30 'nbconvert <6.0',
31 'graphviz',
32 'myst_nb ==0.12.2'
2333 ]
2434 }
2535
3141 setup_args = dict(
3242 name='param',
3343 version=get_setup_version("param"),
34 description='Declarative Python programming using Parameters.',
35 long_description=open('README.rst').read() if os.path.isfile('README.rst') else 'Consult README.rst',
36 author="IOAM",
37 author_email="developers@topographica.org",
38 maintainer="IOAM",
39 maintainer_email="developers@topographica.org",
44 description='Make your Python code clearer and more reliable by declaring Parameters.',
45 long_description=open('README.md').read() if os.path.isfile('README.md') else 'Consult README.md',
46 long_description_content_type="text/markdown",
47 author="HoloViz",
48 author_email="developers@holoviz.org",
49 maintainer="HoloViz",
50 maintainer_email="developers@holoviz.org",
4051 platforms=['Windows', 'Mac OS X', 'Linux'],
4152 license='BSD',
42 url='http://ioam.github.com/param/',
53 url='http://param.holoviz.org/',
4354 packages=["param","numbergen"],
4455 provides=["param","numbergen"],
4556 include_package_data = True,
4758 install_requires=[],
4859 extras_require=extras_require,
4960 tests_require=extras_require['tests'],
61 project_urls={
62 "Documentation": "https://param.holoviz.org/",
63 "Releases": "https://github.com/holoviz/param/releases",
64 "Bug Tracker": "https://github.com/holoviz/param/issues",
65 "Source Code": "https://github.com/holoviz/param",
66 "Panel Examples": "https://panel.holoviz.org/user_guide/Param.html",
67 },
5068 classifiers=[
5169 "License :: OSI Approved :: BSD License",
5270 "Development Status :: 5 - Production/Stable",
5674 "Programming Language :: Python :: 3.4",
5775 "Programming Language :: Python :: 3.5",
5876 "Programming Language :: Python :: 3.6",
77 "Programming Language :: Python :: 3.7",
78 "Programming Language :: Python :: 3.8",
5979 "Operating System :: OS Independent",
6080 "Intended Audience :: Science/Research",
6181 "Intended Audience :: Developers",
+0
-0
tests/API0/__init__.py less more
(Empty file)
+0
-53
tests/API0/testcalendardateparam.py less more
0 """
1 Unit test for CalendarDate parameters.
2 """
3
4 import unittest
5 import datetime as dt
6 import param
7
8
9 class TestDateTimeParameters(unittest.TestCase):
10
11 def test_initialization_out_of_bounds(self):
12 try:
13 class Q(param.Parameterized):
14 q = param.Date(dt.date(2017,2,27),
15 bounds=(dt.date(2017,2,1),
16 dt.date(2017,2,26)))
17 except ValueError:
18 pass
19 else:
20 raise AssertionError("No exception raised on out-of-bounds date")
21
22 def test_set_out_of_bounds(self):
23 class Q(param.Parameterized):
24 q = param.Date(bounds=(dt.date(2017,2,1),
25 dt.date(2017,2,26)))
26 try:
27 Q.q = dt.date(2017,2,27)
28 except ValueError:
29 pass
30 else:
31 raise AssertionError("No exception raised on out-of-bounds date")
32
33 def test_set_exclusive_out_of_bounds(self):
34 class Q(param.Parameterized):
35 q = param.Date(bounds=(dt.date(2017,2,1),
36 dt.date(2017,2,26)),
37 inclusive_bounds=(True, False))
38 try:
39 Q.q = dt.date(2017,2,26)
40 except ValueError:
41 pass
42 else:
43 raise AssertionError("No exception raised on out-of-bounds date")
44
45 def test_get_soft_bounds(self):
46 q = param.Date(dt.date(2017,2,25),
47 bounds=(dt.date(2017,2,1),
48 dt.date(2017,2,26)),
49 softbounds=(dt.date(2017,2,1),
50 dt.date(2017,2,25)))
51 self.assertEqual(q.get_soft_bounds(), (dt.date(2017,2,1),
52 dt.date(2017,2,25)))
+0
-79
tests/API0/testcalendardaterangeparam.py less more
0 """
1 Unit tests for CalendarDateRange parameter.
2 """
3
4 import unittest
5 import datetime as dt
6 import param
7
8
9 # Assuming tests of range parameter cover most of what's needed to
10 # test date range.
11
12 class TestDateTimeRange(unittest.TestCase):
13
14 bad_range = (dt.date(2017,2,27),dt.date(2017,2,26))
15
16 def test_wrong_type_default(self):
17 try:
18 class Q(param.Parameterized):
19 a = param.CalendarDateRange(default=(1.0,2.0))
20 except ValueError:
21 pass
22 else:
23 raise AssertionError("Bad date type was accepted.")
24
25 def test_wrong_type_init(self):
26 class Q(param.Parameterized):
27 a = param.CalendarDateRange()
28
29 try:
30 Q(a=self.bad_range)
31 except ValueError:
32 pass
33 else:
34 raise AssertionError("Bad date type was accepted.")
35
36 def test_wrong_type_set(self):
37 class Q(param.Parameterized):
38 a = param.CalendarDateRange()
39 q = Q()
40
41 try:
42 q.a = self.bad_range
43 except ValueError:
44 pass
45 else:
46 raise AssertionError("Bad date type was accepted.")
47
48 def test_start_before_end_default(self):
49 try:
50 class Q(param.Parameterized):
51 a = param.CalendarDateRange(default=self.bad_range)
52 except ValueError:
53 pass
54 else:
55 raise AssertionError("Bad date range was accepted.")
56
57 def test_start_before_end_init(self):
58 class Q(param.Parameterized):
59 a = param.CalendarDateRange()
60
61 try:
62 Q(a=self.bad_range)
63 except ValueError:
64 pass
65 else:
66 raise AssertionError("Bad date range was accepted.")
67
68 def test_start_before_end_set(self):
69 class Q(param.Parameterized):
70 a = param.CalendarDateRange()
71
72 q = Q()
73 try:
74 q.a = self.bad_range
75 except ValueError:
76 pass
77 else:
78 raise AssertionError("Bad date range was accepted.")
+0
-65
tests/API0/testclassselector.py less more
0 """
1 Unit test for ClassSelector parameters.
2 """
3
4 import unittest
5 from numbers import Number
6
7 import param
8
9
10 class TestClassSelectorParameters(unittest.TestCase):
11
12 def setUp(self):
13
14 class P(param.Parameterized):
15 e = param.ClassSelector(default=1,class_=int)
16 f = param.ClassSelector(default=int,class_=Number, is_instance=False)
17 g = param.ClassSelector(default=1,class_=(int,str))
18 h = param.ClassSelector(default=int,class_=(int,str), is_instance=False)
19
20 self.P = P
21
22 def test_single_class_instance_constructor(self):
23 p = self.P(e=6)
24 self.assertEqual(p.e, 6)
25
26 def test_single_class_instance_error(self):
27 exception = "Parameter 'e' value must be an instance of int, not 'a'"
28 with self.assertRaisesRegexp(ValueError, exception):
29 self.P(e='a')
30
31 def test_single_class_type_constructor(self):
32 p = self.P(f=float)
33 self.assertEqual(p.f, float)
34
35 def test_single_class_type_error(self):
36 exception = "Parameter 'str' must be a subclass of Number, not 'type'"
37 with self.assertRaisesRegexp(ValueError, exception):
38 self.P(f=str)
39
40 def test_multiple_class_instance_constructor1(self):
41 p = self.P(g=1)
42 self.assertEqual(p.g, 1)
43
44 def test_multiple_class_instance_constructor2(self):
45 p = self.P(g='A')
46 self.assertEqual(p.g, 'A')
47
48 def test_multiple_class_instance_error(self):
49 exception = "Parameter 'g' value must be an instance of \(int, str\), not '3.0'"
50 with self.assertRaisesRegexp(ValueError, exception):
51 self.P(g=3.0)
52
53 def test_multiple_class_type_constructor1(self):
54 p = self.P(h=int)
55 self.assertEqual(p.h, int)
56
57 def test_multiple_class_type_constructor2(self):
58 p = self.P(h=str)
59 self.assertEqual(p.h, str)
60
61 def test_multiple_class_type_error(self):
62 exception = "Parameter 'float' must be a subclass of \(int, str\), not 'type'"
63 with self.assertRaisesRegexp(ValueError, exception):
64 self.P(h=float)
+0
-41
tests/API0/testcolorparameter.py less more
0 """
1 Unit test for Color parameters.
2 """
3
4 import unittest
5 import param
6
7
8 class TestColorParameters(unittest.TestCase):
9
10 def test_initialization_invalid_string(self):
11 try:
12 class Q(param.Parameterized):
13 q = param.Color('red')
14 except ValueError:
15 pass
16 else:
17 raise AssertionError("No exception raised on out-of-bounds date")
18
19 def test_set_invalid_string(self):
20 class Q(param.Parameterized):
21 q = param.Color()
22 try:
23 Q.q = 'red'
24 except ValueError:
25 pass
26 else:
27 raise AssertionError("No exception raised on out-of-bounds date")
28
29 def test_valid_long_hex(self):
30 class Q(param.Parameterized):
31 q = param.Color()
32 Q.q = '#ffffff'
33 self.assertEqual(Q.q, '#ffffff')
34
35 def test_valid_short_hex(self):
36 class Q(param.Parameterized):
37 q = param.Color()
38 Q.q = '#fff'
39 self.assertEqual(Q.q, '#fff')
40
+0
-99
tests/API0/testcompositeparams.py less more
0 """
1 Unit test for composite parameters.
2
3 Originally implemented as doctests in Topographica in the file
4 testCompositeParameter.txt
5 """
6
7 import unittest
8 import param
9
10 class TestCompositeParameters(unittest.TestCase):
11
12 def setUp(self):
13 # initialize a class with a compound parameter
14 class A(param.Parameterized):
15 x = param.Number(default=0)
16 y = param.Number(default=0)
17 xy = param.Composite(attribs=['x','y'])
18
19 self.A = A
20 self.a = self.A()
21
22 class SomeSequence(object):
23 "Can't use iter with Dynamic (doesn't pickle, doesn't copy)"
24 def __init__(self,sequence):
25 self.sequence=sequence
26 self.index=0
27 def __call__(self):
28 val=self.sequence[self.index]
29 self.index+=1
30 return val
31
32 self.SomeSequence = SomeSequence
33
34 def test_initialization(self):
35 "Make an instance and do default checks"
36 self.assertEqual(self.a.x, 0)
37 self.assertEqual(self.a.y, 0)
38 self.assertEqual(self.a.xy, [0,0])
39
40
41 def test_set_component(self):
42 self.a.x = 1
43 self.assertEqual(self.a.xy, [1,0])
44
45 def test_set_compound(self):
46 self.a.xy = (2,3)
47 self.assertEqual(self.a.x, 2)
48 self.assertEqual(self.a.y, 3)
49
50 def test_compound_class(self):
51 " Get the compound on the class "
52 self.assertEqual(self.A.xy, [0,0])
53
54 def test_set_compound_class_set(self):
55 self.A.xy = (5,6)
56 self.assertEqual(self.A.x, 5)
57 self.assertEqual(self.A.y, 6)
58
59 def test_set_compound_class_instance(self):
60 self.A.xy = (5,6)
61 # # Make a new instance
62 b = self.A()
63 self.assertEqual(b.x, 5)
64 self.assertEqual(b.y, 6)
65
66 def test_set_compound_class_instance_unchanged(self):
67 self.a.xy = (2,3)
68 self.A.xy = (5,6)
69 self.assertEqual(self.a.x, 2)
70 self.assertEqual(self.a.y, 3)
71
72 def test_composite_dynamic(self):
73 """
74 Check CompositeParameter is ok with Dynamic
75 CB: this test is really of Parameterized.
76 """
77 a2 = self.A(x=self.SomeSequence([1,2,3]),
78 y=self.SomeSequence([4,5,6]))
79
80 a2.x, a2.y # Call of x and y params
81 # inspect should not advance numbers
82 self.assertEqual(a2.inspect_value('xy'), [1, 4])
83
84 def test_composite_dynamic_generator(self):
85
86 a2 = self.A(x=self.SomeSequence([1,2,3]),
87 y=self.SomeSequence([4,5,6]))
88
89 a2.x, a2.y # Call of x and y params
90 ix,iy = a2.get_value_generator('xy')
91 # get_value_generator() should give the objects
92 self.assertEqual(ix(), 2)
93 self.assertEqual(iy(), 5)
94
95
96 if __name__ == "__main__":
97 import nose
98 nose.runmodule()
+0
-54
tests/API0/testdateparam.py less more
0 """
1 Unit test for Date parameters.
2 """
3
4 import unittest
5 import datetime as dt
6 import param
7
8
9 class TestDateParameters(unittest.TestCase):
10
11 def test_initialization_out_of_bounds(self):
12 try:
13 class Q(param.Parameterized):
14 q = param.Date(dt.datetime(2017,2,27),
15 bounds=(dt.datetime(2017,2,1),
16 dt.datetime(2017,2,26)))
17 except ValueError:
18 pass
19 else:
20 raise AssertionError("No exception raised on out-of-bounds date")
21
22 def test_set_out_of_bounds(self):
23 class Q(param.Parameterized):
24 q = param.Date(bounds=(dt.datetime(2017,2,1),
25 dt.datetime(2017,2,26)))
26 try:
27 Q.q = dt.datetime(2017,2,27)
28 except ValueError:
29 pass
30 else:
31 raise AssertionError("No exception raised on out-of-bounds date")
32
33 def test_set_exclusive_out_of_bounds(self):
34 class Q(param.Parameterized):
35 q = param.Date(bounds=(dt.datetime(2017,2,1),
36 dt.datetime(2017,2,26)),
37 inclusive_bounds=(True, False))
38 try:
39 Q.q = dt.datetime(2017,2,26)
40 except ValueError:
41 pass
42 else:
43 raise AssertionError("No exception raised on out-of-bounds date")
44
45 def test_get_soft_bounds(self):
46 q = param.Date(dt.datetime(2017,2,25),
47 bounds=(dt.datetime(2017,2,1),
48 dt.datetime(2017,2,26)),
49 softbounds=(dt.datetime(2017,2,1),
50 dt.datetime(2017,2,25)))
51 self.assertEqual(q.get_soft_bounds(), (dt.datetime(2017,2,1),
52 dt.datetime(2017,2,25)))
53
+0
-81
tests/API0/testdaterangeparam.py less more
0 """
1 Unit tests for DateRange parameter.
2 """
3
4 import unittest
5 import datetime as dt
6 import param
7
8
9 # Assuming tests of range parameter cover most of what's needed to
10 # test date range.
11
12 class TestDateRange(unittest.TestCase):
13
14 bad_range = (dt.datetime(2017,2,27),dt.datetime(2017,2,26))
15
16 def test_wrong_type_default(self):
17 try:
18 class Q(param.Parameterized):
19 a = param.DateRange(default=(1.0,2.0))
20 except ValueError:
21 pass
22 else:
23 raise AssertionError("Bad date type was accepted.")
24
25 def test_wrong_type_init(self):
26 class Q(param.Parameterized):
27 a = param.DateRange()
28
29 try:
30 Q(a=self.bad_range)
31 except ValueError:
32 pass
33 else:
34 raise AssertionError("Bad date type was accepted.")
35
36 def test_wrong_type_set(self):
37 class Q(param.Parameterized):
38 a = param.DateRange()
39 q = Q()
40
41 try:
42 q.a = self.bad_range
43 except ValueError:
44 pass
45 else:
46 raise AssertionError("Bad date type was accepted.")
47
48 def test_start_before_end_default(self):
49 try:
50 class Q(param.Parameterized):
51 a = param.DateRange(default=self.bad_range)
52 except ValueError:
53 pass
54 else:
55 raise AssertionError("Bad date range was accepted.")
56
57 def test_start_before_end_init(self):
58 class Q(param.Parameterized):
59 a = param.DateRange()
60
61 try:
62 Q(a=self.bad_range)
63 except ValueError:
64 pass
65 else:
66 raise AssertionError("Bad date range was accepted.")
67
68 def test_start_before_end_set(self):
69 class Q(param.Parameterized):
70 a = param.DateRange()
71
72 q = Q()
73 try:
74 q.a = self.bad_range
75 except ValueError:
76 pass
77 else:
78 raise AssertionError("Bad date range was accepted.")
79
80
+0
-60
tests/API0/testdefaults.py less more
0 """
1 Do all subclasses of Parameter supply a valid default?
2 """
3
4 import unittest
5
6 from param.parameterized import add_metaclass
7 from param import concrete_descendents, Parameter
8
9 # import all parameter types
10 from param import ClassSelector
11 from param import * # noqa
12
13
14 positional_args = {
15 ClassSelector: (object,)
16 }
17
18 skip = []
19
20 try:
21 import numpy # noqa
22 except ImportError:
23 skip.append('Array')
24
25 try:
26 import pandas # noqa
27 except ImportError:
28 skip.append('DataFrame')
29 skip.append('Series')
30
31
32 class TestDefaultsMetaclass(type):
33 def __new__(mcs, name, bases, dict_):
34
35 def test_skip(*args,**kw):
36 from nose.exc import SkipTest
37 raise SkipTest
38
39 def add_test(p):
40 def test(self):
41 # instantiate parameter with no default (but supply
42 # any required args)
43 p(*positional_args.get(p,tuple()))
44 return test
45
46 for p_name, p_type in concrete_descendents(Parameter).items():
47 dict_["test_default_of_%s"%p_name] = add_test(p_type) if p_name not in skip else test_skip
48
49 return type.__new__(mcs, name, bases, dict_)
50
51
52 @add_metaclass(TestDefaultsMetaclass)
53 class TestDefaults(unittest.TestCase):
54 pass
55
56
57 if __name__ == "__main__":
58 import nose
59 nose.runmodule()
+0
-293
tests/API0/testdynamicparams.py less more
0 """
1 Unit test for dynamic parameters.
2
3 Tests __get__, __set__ and that inspect_value() and
4 get_value_generator() work.
5
6 Originally implemented as doctests in Topographica in the file
7 testDynamicParameter.txt
8 """
9
10 import copy
11 import unittest
12 import param
13 import numbergen
14
15
16 class TestDynamicParameters(unittest.TestCase):
17
18 def setUp(self):
19 param.Dynamic.time_dependent = False
20
21 class TestPO1(param.Parameterized):
22 x = param.Dynamic(default=numbergen.UniformRandom(lbound=-1,ubound=1,seed=1),doc="nothing")
23 y = param.Dynamic(default=1)
24
25 class TestPO2(param.Parameterized):
26 x = param.Dynamic(default=numbergen.UniformRandom(lbound=-1,ubound=1,seed=30))
27 y = param.Dynamic(default=1.0)
28
29 self.TestPO2 = TestPO2
30 self.TestPO1 = TestPO1
31
32 self.t1 = self.TestPO1()
33 self.t2 = self.TestPO1(x=numbergen.UniformRandom(lbound=-1,ubound=1,seed=10))
34 self.t3 = self.TestPO1(x=numbergen.UniformRandom(lbound=-1,ubound=1,seed=10))
35 self.t2.set_dynamic_time_fn(None)
36 self.t3.set_dynamic_time_fn(None)
37
38 self.t6 = self.TestPO2()
39 self.t7 = self.TestPO2()
40
41
42 class TestDynamicParameterBasics(TestDynamicParameters):
43
44 def test_set_dynamic_time_fn_x(self):
45 self.t1.set_dynamic_time_fn(None)
46 self.assertEqual(
47 self.t1.params()['x']._value_is_dynamic(self.t1), True)
48
49 def test_set_dynamic_time_fn_y(self):
50 self.assertEqual(
51 self.t1.params()['y']._value_is_dynamic(self.t1), False)
52
53 def test_inspect_x(self):
54 "no value generated yet"
55 self.assertEqual(self.t1.inspect_value('x'), None)
56
57 def test_inspect_y(self):
58 self.assertEqual(self.t1.inspect_value('y'), 1)
59
60 def test_inspect_y_set(self):
61 self.t1.y = 2
62 self.assertEqual(self.t1.inspect_value('y'), 2)
63
64 def test_set_dynamic_numbergen(self):
65 is_numbergen = isinstance(self.t2.get_value_generator('x'),
66 numbergen.UniformRandom)
67 self.assertEqual(is_numbergen, True)
68
69 def test_matching_numbergen_streams(self):
70 "check that t2 and t3 have identical streams"
71 self.assertEqual(self.t2.x, self.t3.x)
72
73 def test_numbergen_objects_distinct(self):
74 "check t2 and t3 do not share UniformRandom objects"
75 self.t2.x
76 self.assertNotEqual(self.t2.inspect_value('x'),
77 self.t3.inspect_value('x'))
78
79 def test_numbergen_inspect(self):
80 " inspect_value() should return last generated value "
81 self.t2.x # Call 1
82 self.t2.x # Call 2
83 t2_last_value = self.t2.x # advance t2 beyond t3
84
85 self.assertEqual(self.t2.inspect_value('x'),
86 t2_last_value)
87 # ensure last_value is not shared
88 self.assertNotEqual(self.t3.inspect_value('x'), t2_last_value)
89
90 def test_dynamic_value_instantiated(self):
91 t6_first_value = self.t6.x
92 self.assertNotEqual(self.t7.inspect_value('x'),
93 t6_first_value)
94
95 def test_non_dynamic_value_not_instantiated(self):
96 " non-dynamic value not instantiated"
97 self.TestPO2.y = 4
98 self.assertEqual(self.t6.y, 4)
99 self.assertEqual(self.t7.y, 4)
100
101 def test_dynamic_value_setting(self):
102 self.t6.y = numbergen.UniformRandom()
103 t8 = self.TestPO2()
104 self.TestPO2.y = 10
105 # t6 got a dynamic value, but shouldn't have changed Parameter's instantiate
106 self.assertEqual(t8.y, 10)
107
108 def test_setting_y_param_numbergen(self):
109 self.TestPO2.y=numbergen.UniformRandom() # now the Parameter instantiate should be true
110 t9 = self.TestPO2()
111 self.assertEqual('_y_param_value' in t9.__dict__, True)
112
113 def test_shared_numbergen(self):
114 """
115 Instances of TestPO2 that don't have their own value for the
116 parameter share one UniformRandom object
117 """
118 self.TestPO2.y=numbergen.UniformRandom() # now the Parameter instantiate should be true
119 self.assertEqual(self.t7.get_value_generator('y') is self.TestPO2().params()['y'].default, True)
120 self.assertEqual(self.TestPO2().params()['y'].default.__class__.__name__, 'UniformRandom')
121
122 def test_copy_match(self):
123 "check a copy is the same"
124 t9 = copy.deepcopy(self.t7)
125 self.assertEqual(t9.get_value_generator('y') is self.TestPO2().params()['y'].default, True)
126
127
128
129 class TestDynamicTimeDependent(TestDynamicParameters):
130
131 def setUp(self):
132 super(TestDynamicTimeDependent, self).setUp()
133 param.Dynamic.time_dependent = True
134
135 class TestPO3(param.Parameterized):
136 x = param.Dynamic(default=numbergen.UniformRandom(name='xgen',
137 time_dependent=True))
138
139 class TestPO4(self.TestPO1):
140 "Nested parameterized objects"
141 z = param.Parameter(default=self.TestPO1())
142
143 self.TestPO3 = TestPO3
144 self.TestPO4 = TestPO4
145
146 self.t10 = self.TestPO1()
147 self.t11 = TestPO3()
148
149 def test_dynamic_values_unchanged_dependent(self):
150 param.Dynamic.time_dependent = True
151 call_1 = self.t10.x
152 call_2 = self.t10.x
153 call_3 = self.t10.x
154 self.assertEqual(call_1, call_2)
155 self.assertEqual(call_2, call_3)
156
157 def test_dynamic_values_changed_independent(self):
158 param.Dynamic.time_dependent = False
159 call_1 = self.t10.x
160 call_2 = self.t10.x
161 call_3 = self.t10.x
162 self.assertNotEqual(call_1, call_2)
163 self.assertNotEqual(call_2, call_3)
164
165 def test_dynamic_values_change(self):
166 param.Dynamic.time_dependent = True
167 with param.Dynamic.time_fn as t:
168 t(0)
169 call_1 = self.t10.x
170 t += 1
171 call_2 = self.t10.x
172 t(0)
173 call_3 = self.t10.x
174 self.assertNotEqual(call_1, call_2)
175 self.assertNotEqual(call_1, call_3)
176
177 def test_dynamic_values_time_dependent(self):
178 param.Dynamic.time_dependent = True
179 with param.Dynamic.time_fn as t:
180 t(0)
181 call_1 = self.t11.x
182 t += 1
183 call_2 = self.t11.x
184 t(0)
185 call_3 = self.t11.x
186 self.assertNotEqual(call_1, call_2)
187 self.assertEqual(call_1, call_3)
188
189 def test_class_dynamic_values_change(self):
190 call_1 = self.TestPO3.x
191 call_2 = self.TestPO3.x
192 self.assertEqual(call_1, call_2)
193 with param.Dynamic.time_fn as t:
194 t += 1
195 call_3 = self.TestPO3.x
196 self.assertNotEqual(call_2, call_3)
197
198 def test_dynamic_value_change_independent(self):
199 t12 = self.TestPO1()
200 t12.set_dynamic_time_fn(None)
201 self.assertNotEqual(t12.x, t12.x)
202 self.assertEqual(t12.y, t12.y)
203
204 def test_dynamic_value_change_disabled(self):
205 " time_fn set on the UniformRandom() when t13.y was set"
206 t13 = self.TestPO1()
207 t13.set_dynamic_time_fn(None)
208 t13.y = numbergen.UniformRandom()
209 self.assertNotEqual(t13.y, t13.y)
210
211 def test_dynamic_value_change_enabled(self):
212 " time_fn set on the UniformRandom() when t13.y was set"
213 t14 = self.TestPO1()
214 t14.y = numbergen.UniformRandom()
215 self.assertEqual(t14.y, t14.y)
216
217
218 def test_dynamic_time_fn_not_inherited(self):
219 " time_fn not inherited"
220 t15 = self.TestPO4()
221 t15.set_dynamic_time_fn(None)
222 with param.Dynamic.time_fn as t:
223 call_1 = t15.z.x
224 t += 1
225 call_2 = t15.z.x
226 self.assertNotEqual(call_1, call_2)
227
228
229
230 class TestDynamicSharedNumbergen(TestDynamicParameters):
231 "Check shared generator"
232 def setUp(self):
233 super(TestDynamicSharedNumbergen, self).setUp()
234 self.shared = numbergen.UniformRandom(lbound=-1,ubound=1,seed=20)
235
236 def test_dynamic_shared_numbergen(self):
237 param.Dynamic.time_dependent = True
238 t11 = self.TestPO1(x=self.shared)
239 t12 = self.TestPO1(x=self.shared)
240
241 with param.Dynamic.time_fn as t:
242 t += 1
243 call_1 = t11.x
244 self.assertEqual(call_1, t12.x)
245 t += 1
246 self.assertNotEqual(call_1, t12.x)
247
248
249
250 if __name__ == "__main__":
251 import nose
252 nose.runmodule()
253
254
255 # Commented out block in the original doctest version.
256 # Maybe these are features originally planned but never implemented
257
258 """
259 It is not yet possible to set time_fn for a Parameter instance
260 >>> class TestPO5(param.Parameterized):
261 ... x = param.Dynamic(default=numbergen.UniformRandom(),dynamic_time_fn=None)
262 """
263
264 """
265 We currently don't support iterators/generators in Dynamic unless
266 they're wrapped.
267
268 >>> i = iter([1,2,3])
269 >>> t11.x = i
270
271 >>> topo.sim.run(1)
272
273 >>> t11.x
274 1
275
276 >>> def gen():
277 ... yield 2
278 ... yield 4
279 ... yield 6
280
281 >>> g = gen()
282
283 >>> t11.x = g
284
285 >>> t11.x
286 2
287
288 >>> topo.sim.run(1)
289
290 >>> t11.x
291 4
292 """
+0
-67
tests/API0/testipythonmagic.py less more
0 """
1 Unit test for the IPython magic
2 """
3
4 import re
5 import sys
6 import unittest
7 import param
8
9
10 try:
11 import IPython # noqa
12 except ImportError:
13 import os
14 if os.getenv('PARAM_TEST_IPYTHON','0') == '1':
15 raise ImportError("PARAM_TEST_IPYTHON=1 but ipython not available.")
16
17 # TODO: is the below actually true?
18
19 # SkipTest will be raised if IPython unavailable
20 from param.ipython import ParamPager
21
22 test1_repr = """\x1b[1;32mParameters of 'TestClass'\n=========================\n\x1b[0m\n\x1b[1;31mParameters changed from their default values are marked in red.\x1b[0m\n\x1b[1;36mSoft bound values are marked in cyan.\x1b[0m\nC/V= Constant/Variable, RO/RW = ReadOnly/ReadWrite, AN=Allow None\n\n\x1b[1;34mNameValue Type Bounds Mode \x1b[0m\n\nu 4 Number V RW \nv 4 Number C RW \nw 4 Number C RO \nx None String V RW AN \ny 4 Number (-1, None) V RW \nz 4 Number (-1, 100) V RW \n\n\x1b[1;32mParameter docstrings:\n=====================\x1b[0m\n\n\x1b[1;34mu: < No docstring available >\x1b[0m\n\x1b[1;31mv: < No docstring available >\x1b[0m\n\x1b[1;34mw: < No docstring available >\x1b[0m\n\x1b[1;31mx: < No docstring available >\x1b[0m\n\x1b[1;34my: < No docstring available >\x1b[0m\n\x1b[1;31mz: < No docstring available >\x1b[0m"""
23
24
25 test2_repr = """\x1b[1;32mParameters of 'TestClass' instance\n==================================\n\x1b[0m\n\x1b[1;31mParameters changed from their default values are marked in red.\x1b[0m\n\x1b[1;36mSoft bound values are marked in cyan.\x1b[0m\nC/V= Constant/Variable, RO/RW = ReadOnly/ReadWrite, AN=Allow None\n\n\x1b[1;34mNameValue Type Bounds Mode \x1b[0m\n\nu 4 Number V RW \nv 4 Number C RW \nw 4 Number C RO \nx None String V RW AN \ny 4 Number (-1, None) V RW \nz 4 Number (-1, 100) V RW \n\n\x1b[1;32mParameter docstrings:\n=====================\x1b[0m\n\n\x1b[1;34mu: < No docstring available >\x1b[0m\n\x1b[1;31mv: < No docstring available >\x1b[0m\n\x1b[1;34mw: < No docstring available >\x1b[0m\n\x1b[1;31mx: < No docstring available >\x1b[0m\n\x1b[1;34my: < No docstring available >\x1b[0m\n\x1b[1;31mz: < No docstring available >\x1b[0m"""
26
27 class TestParamPager(unittest.TestCase):
28
29 def setUp(self):
30 self.maxDiff = None
31 class TestClass(param.Parameterized):
32 u = param.Number(4)
33 v = param.Number(4, constant=True)
34 w = param.Number(4, readonly=True)
35 x = param.String(None, allow_None=True)
36 y = param.Number(4, bounds=(-1, None))
37 z = param.Number(4, bounds=(-1, 100), softbounds=(-100, -200))
38
39 self.TestClass = TestClass
40 self.pager = ParamPager()
41
42 def test_parameterized_class(self):
43 page_string = self.pager(self.TestClass)
44 # Remove params automatic numbered names
45 page_string = re.sub('TestClass(\d+)', 'TestClass', page_string)
46 ref_string = re.sub('TestClass(\d+)', 'TestClass', test1_repr)
47
48 try:
49 self.assertEqual(page_string, ref_string)
50 except Exception as e:
51 sys.stderr.write(page_string) # Coloured output
52 sys.stderr.write("\nRAW STRING:\n\n%r\n\n" % page_string)
53 raise e
54
55 def test_parameterized_instance(self):
56 page_string = self.pager(self.TestClass())
57 # Remove params automatic numbered names
58 page_string = re.sub('TestClass(\d+)', 'TestClass', page_string)
59 ref_string = re.sub('TestClass(\d+)', 'TestClass', test2_repr)
60
61 try:
62 self.assertEqual(page_string, ref_string)
63 except Exception as e:
64 sys.stderr.write(page_string) # Coloured output
65 sys.stderr.write("\nRAW STRING:\n\n%r\n\n" % page_string)
66 raise e
+0
-161
tests/API0/testlistselector.py less more
0 import unittest
1 import param
2
3 # TODO: I copied the tests from testobjectselector, although I
4 # struggled to understand some of them. Both files should be reviewed
5 # and cleaned up together.
6
7 # TODO: tests copied from testobjectselector could use assertRaises
8 # context manager (and could be updated in testobjectselector too).
9
10 class TestListSelectorParameters(unittest.TestCase):
11
12 def setUp(self):
13
14 class P(param.Parameterized):
15 e = param.ListSelector(default=[5],objects=[5,6,7])
16 f = param.ListSelector(default=10)
17 h = param.ListSelector(default=None)
18 g = param.ListSelector(default=None,objects=[7,8])
19 i = param.ListSelector(default=[7],objects=[9],check_on_set=False)
20
21 self.P = P
22
23 def test_default_None(self):
24 class Q(param.Parameterized):
25 r = param.ListSelector(default=None)
26
27 def test_set_object_constructor(self):
28 p = self.P(e=[6])
29 self.assertEqual(p.e, [6])
30
31 def test_set_object_outside_bounds(self):
32 p = self.P(e=[6])
33 try:
34 p.e = [9]
35 except ValueError:
36 pass
37 else:
38 raise AssertionError("Object set outside range.")
39
40 def test_set_object_setattr(self):
41 p = self.P(e=[6])
42 p.f = [9]
43 self.assertEqual(p.f, [9])
44 p.g = [7]
45 self.assertEqual(p.g, [7])
46 p.i = [12]
47 self.assertEqual(p.i, [12])
48
49
50 def test_set_object_not_None(self):
51 p = self.P(e=[6])
52 p.g = [7]
53 try:
54 p.g = None
55 except TypeError:
56 pass
57 else:
58 raise AssertionError("Object set outside range.")
59
60 def test_set_one_object_not_None(self):
61 p = self.P(e=[6])
62 p.g = [7]
63 try:
64 p.g = [None]
65 except ValueError:
66 pass
67 else:
68 raise AssertionError("Object set outside range.")
69
70
71 def test_set_object_setattr_post_error(self):
72 p = self.P(e=[6])
73 p.f = [9]
74 self.assertEqual(p.f, [9])
75 p.g = [7]
76 try:
77 p.g = [None]
78 except ValueError:
79 pass
80 else:
81 raise AssertionError("Object set outside range.")
82
83 self.assertEqual(p.g, [7])
84 p.i = [12]
85 self.assertEqual(p.i, [12])
86
87 def test_initialization_out_of_bounds(self):
88 try:
89 class Q(param.Parameterized):
90 q = param.ListSelector([5],objects=[4])
91 except ValueError:
92 pass
93 else:
94 raise AssertionError("ListSelector created outside range.")
95
96
97 def test_initialization_no_bounds(self):
98 try:
99 class Q(param.Parameterized):
100 q = param.ListSelector([5],objects=10)
101 except TypeError:
102 pass
103 else:
104 raise AssertionError("ListSelector created without range.")
105
106
107 ##################################################################
108 ##################################################################
109 ### new tests (not copied from testobjectselector)
110
111 def test_bad_default(self):
112 with self.assertRaises(TypeError):
113 class Q(param.Parameterized):
114 r = param.ListSelector(default=6,check_on_set=True)
115
116 def test_implied_check_on_set(self):
117 with self.assertRaises(TypeError):
118 class Q(param.Parameterized):
119 r = param.ListSelector(default=7,objects=[7,8])
120
121 def test_default_not_checked(self):
122 class Q(param.Parameterized):
123 r = param.ListSelector(default=[6])
124
125 ##########################
126 # CEBALERT: not sure it makes sense for ListSelector to be set to
127 # a non-iterable value (except None). I.e. I think this first test
128 # should fail.
129 def test_default_not_checked_to_be_iterable(self):
130 class Q(param.Parameterized):
131 r = param.ListSelector(default=6)
132
133 def test_set_checked_to_be_iterable(self):
134 class Q(param.Parameterized):
135 r = param.ListSelector(default=6,check_on_set=False)
136
137 with self.assertRaises(TypeError):
138 Q.r = 6
139 ##########################
140
141
142 def test_compute_default(self):
143 class Q(param.Parameterized):
144 r = param.ListSelector(default=None, compute_default_fn=lambda: [1,2,3])
145
146 self.assertEqual(Q.r, None)
147 Q.params('r').compute_default()
148 self.assertEqual(Q.r, [1,2,3])
149 self.assertEqual(Q.params('r').objects, [1,2,3])
150
151 def test_bad_compute_default(self):
152 class Q(param.Parameterized):
153 r = param.ListSelector(default=None,compute_default_fn=lambda:1)
154
155 with self.assertRaises(TypeError):
156 Q.params('r').compute_default()
157
158 if __name__ == "__main__":
159 import nose
160 nose.runmodule()
+0
-39
tests/API0/testnumbergen.py less more
0 """
1 Test cases for the numbergen module.
2 """
3
4 import unittest
5 import numbergen
6
7
8 _seed = 0 # keep tests deterministic
9 _iterations = 1000
10
11
12 class TestUniformRandom(unittest.TestCase):
13 def test_range(self):
14 lbound = 2.0
15 ubound = 5.0
16 gen = numbergen.UniformRandom(
17 seed=_seed,
18 lbound=lbound,
19 ubound=ubound)
20 for _ in range(_iterations):
21 value = gen()
22 self.assertTrue(lbound <= value < ubound)
23
24 class TestUniformRandomOffset(unittest.TestCase):
25 def test_range(self):
26 lbound = 2.0
27 ubound = 5.0
28 gen = numbergen.UniformRandomOffset(
29 seed=_seed,
30 mean=(ubound + lbound) / 2,
31 range=ubound - lbound)
32 for _ in range(_iterations):
33 value = gen()
34 self.assertTrue(lbound <= value < ubound)
35
36 if __name__ == "__main__":
37 import nose
38 nose.runmodule()
+0
-40
tests/API0/testnumpy.py less more
0 """
1 If numpy's present, is numpy stuff ok?
2 """
3
4 import os
5 import unittest
6
7 import param
8
9
10 try:
11 import numpy
12 import numpy.testing
13 except ImportError:
14 if os.getenv('PARAM_TEST_NUMPY','0') == '1':
15 raise ImportError("PARAM_TEST_NUMPY=1 but numpy not available.")
16 else:
17 raise unittest.SkipTest("numpy not available")
18
19
20 def _is_array_and_equal(test,ref):
21 if not type(test) == numpy.ndarray:
22 raise AssertionError
23 numpy.testing.assert_array_equal(test,ref)
24
25 # TODO: incomplete
26 class TestNumpy(unittest.TestCase):
27 def test_array_param(self):
28 class Z(param.Parameterized):
29 z = param.Array(default=numpy.array([1]))
30
31 _is_array_and_equal(Z.z,[1])
32
33 z = Z(z=numpy.array([1,2]))
34 _is_array_and_equal(z.z,[1,2])
35
36
37 if __name__ == "__main__":
38 import nose
39 nose.runmodule()
+0
-108
tests/API0/testobjectselector.py less more
0 """
1 Unit test for object selector parameters.
2
3 Originally implemented as doctests in Topographica in the file
4 testEnumerationParameter.txt
5 """
6
7 import unittest
8 import param
9
10
11 opts=dict(A=[1,2],B=[3,4],C=dict(a=1,b=2))
12
13
14 class TestObjectSelectorParameters(unittest.TestCase):
15
16 def setUp(self):
17
18 class P(param.Parameterized):
19 e = param.ObjectSelector(default=5,objects=[5,6,7])
20 f = param.ObjectSelector(default=10)
21 h = param.ObjectSelector(default=None)
22 g = param.ObjectSelector(default=None,objects=[7,8])
23 i = param.ObjectSelector(default=7,objects=[9],check_on_set=False)
24 d = param.ObjectSelector(default=opts['B'],objects=opts)
25
26 self.P = P
27
28 def test_set_object_constructor(self):
29 p = self.P(e=6)
30 self.assertEqual(p.e, 6)
31
32 def test_get_range_mutable(self):
33 r = self.P.param.params("d").get_range()
34 self.assertEqual(r['A'],opts['A'])
35 self.assertEqual(r['C'],opts['C'])
36 self.d=opts['A']
37 self.d=opts['C']
38 self.d=opts['B']
39
40 def test_set_object_outside_bounds(self):
41 p = self.P(e=6)
42 try:
43 p.e = 9
44 except ValueError:
45 pass
46 else:
47 raise AssertionError("Object set outside range.")
48
49 def test_set_object_setattr(self):
50 p = self.P(e=6)
51 p.f = 9
52 self.assertEqual(p.f, 9)
53 p.g = 7
54 self.assertEqual(p.g, 7)
55 p.i = 12
56 self.assertEqual(p.i, 12)
57
58
59 def test_set_object_not_None(self):
60 p = self.P(e=6)
61 p.g = 7
62 try:
63 p.g = None
64 except ValueError:
65 pass
66 else:
67 raise AssertionError("Object set outside range.")
68
69 def test_set_object_setattr_post_error(self):
70 p = self.P(e=6)
71 p.f = 9
72 self.assertEqual(p.f, 9)
73 p.g = 7
74 try:
75 p.g = None
76 except ValueError:
77 pass
78 else:
79 raise AssertionError("Object set outside range.")
80
81 self.assertEqual(p.g, 7)
82 p.i = 12
83 self.assertEqual(p.i, 12)
84
85 def test_initialization_out_of_bounds(self):
86 try:
87 class Q(param.Parameterized):
88 q = param.ObjectSelector(5,objects=[4])
89 except ValueError:
90 pass
91 else:
92 raise AssertionError("ObjectSelector created outside range.")
93
94
95 def test_initialization_no_bounds(self):
96 try:
97 class Q(param.Parameterized):
98 q = param.ObjectSelector(5,objects=10)
99 except TypeError:
100 pass
101 else:
102 raise AssertionError("ObjectSelector created without range.")
103
104
105 if __name__ == "__main__":
106 import nose
107 nose.runmodule()
+0
-300
tests/API0/testparameterizedobject.py less more
0 """
1 Unit test for Parameterized.
2 """
3
4 import unittest
5 import param
6 import numbergen
7
8 # CEBALERT: not anything like a complete test of Parameterized!
9
10
11 import random
12 from nose.tools import istest, nottest
13
14
15 from param.parameterized import ParamOverrides, shared_parameters
16
17 @nottest
18 class _SomeRandomNumbers(object):
19 def __call__(self):
20 return random.random()
21
22 @nottest
23 class TestPO(param.Parameterized):
24 inst = param.Parameter(default=[1,2,3],instantiate=True)
25 notinst = param.Parameter(default=[1,2,3],instantiate=False)
26 const = param.Parameter(default=1,constant=True)
27 ro = param.Parameter(default="Hello",readonly=True)
28 ro2 = param.Parameter(default=object(),readonly=True,instantiate=True)
29
30 dyn = param.Dynamic(default=1)
31
32 @nottest
33 class AnotherTestPO(param.Parameterized):
34 instPO = param.Parameter(default=TestPO(),instantiate=True)
35 notinstPO = param.Parameter(default=TestPO(),instantiate=False)
36
37 @nottest
38 class TestAbstractPO(param.Parameterized):
39 __abstract = True
40
41 @nottest
42 class TestParamInstantiation(AnotherTestPO):
43 instPO = param.Parameter(default=AnotherTestPO(),instantiate=False)
44
45 @istest
46 class TestParameterized(unittest.TestCase):
47
48 def test_constant_parameter(self):
49 """Test that you can't set a constant parameter after construction."""
50 testpo = TestPO(const=17)
51 self.assertEqual(testpo.const,17)
52 self.assertRaises(TypeError,setattr,testpo,'const',10)
53
54 # check you can set on class
55 TestPO.const=9
56 testpo = TestPO()
57 self.assertEqual(testpo.const,9)
58
59 def test_readonly_parameter(self):
60 """Test that you can't set a read-only parameter on construction or as an attribute."""
61 testpo = TestPO()
62 self.assertEqual(testpo.ro,"Hello")
63
64 with self.assertRaises(TypeError):
65 t = TestPO(ro=20)
66
67 t=TestPO()
68 self.assertRaises(TypeError,setattr,t,'ro',10)
69
70 # check you cannot set on class
71 self.assertRaises(TypeError,setattr,TestPO,'ro',5)
72
73 self.assertEqual(testpo.params()['ro'].constant,True)
74
75 # check that instantiate was ignored for readonly
76 self.assertEqual(testpo.params()['ro2'].instantiate,False)
77
78
79
80 def test_basic_instantiation(self):
81 """Check that instantiated parameters are copied into objects."""
82
83 testpo = TestPO()
84
85 self.assertEqual(testpo.inst,TestPO.inst)
86 self.assertEqual(testpo.notinst,TestPO.notinst)
87
88 TestPO.inst[1]=7
89 TestPO.notinst[1]=7
90
91 self.assertEqual(testpo.notinst,[1,7,3])
92 self.assertEqual(testpo.inst,[1,2,3])
93
94
95 def test_more_instantiation(self):
96 """Show that objects in instantiated Parameters can still share data."""
97 anothertestpo = AnotherTestPO()
98
99 ### CB: AnotherTestPO.instPO is instantiated, but
100 ### TestPO.notinst is not instantiated - so notinst is still
101 ### shared, even by instantiated parameters of AnotherTestPO.
102 ### Seems like this behavior of Parameterized could be
103 ### confusing, so maybe mention it in documentation somewhere.
104 TestPO.notinst[1]=7
105 # (if you thought your instPO was completely an independent object, you
106 # might be expecting [1,2,3] here)
107 self.assertEqual(anothertestpo.instPO.notinst,[1,7,3])
108
109
110 def test_instantiation_inheritance(self):
111 """Check that instantiate=True is always inherited (SF.net #2483932)."""
112 t = TestParamInstantiation()
113 assert t.params('instPO').instantiate is True
114 assert isinstance(t.instPO,AnotherTestPO)
115
116
117 def test_abstract_class(self):
118 """Check that a class declared abstract actually shows up as abstract."""
119 self.assertEqual(TestAbstractPO.abstract,True)
120 self.assertEqual(TestPO.abstract,False)
121
122
123 def test_params(self):
124 """Basic tests of params() method."""
125
126
127 # CB: test not so good because it requires changes if params
128 # of PO are changed
129 assert 'name' in param.Parameterized.params()
130 assert len(param.Parameterized.params()) in [1,2]
131
132 ## check for bug where subclass Parameters were not showing up
133 ## if params() already called on a super class.
134 assert 'inst' in TestPO.params()
135 assert 'notinst' in TestPO.params()
136
137 ## check caching
138 assert param.Parameterized.params() is param.Parameterized().params(), "Results of params() should be cached." # just for performance reasons
139
140
141 def test_state_saving(self):
142 t = TestPO(dyn=_SomeRandomNumbers())
143 g = t.get_value_generator('dyn')
144 g._Dynamic_time_fn=None
145 assert t.dyn!=t.dyn
146 orig = t.dyn
147 t.state_push()
148 t.dyn
149 assert t.inspect_value('dyn')!=orig
150 t.state_pop()
151 assert t.inspect_value('dyn')==orig
152
153
154
155 from param import parameterized
156
157 @nottest
158 class some_fn(param.ParameterizedFunction):
159 num_phase = param.Number(18)
160 frequencies = param.List([99])
161 scale = param.Number(0.3)
162
163 def __call__(self,**params_to_override):
164 params = parameterized.ParamOverrides(self,params_to_override)
165 num_phase = params['num_phase']
166 frequencies = params['frequencies']
167 scale = params['scale']
168 return scale,num_phase,frequencies
169
170 instance = some_fn.instance()
171
172 @istest
173 class TestParameterizedFunction(unittest.TestCase):
174
175 def _basic_tests(self,fn):
176 self.assertEqual(fn(),(0.3,18,[99]))
177 self.assertEqual(fn(frequencies=[1,2,3]),(0.3,18,[1,2,3]))
178 self.assertEqual(fn(),(0.3,18,[99]))
179
180 fn.frequencies=[10,20,30]
181 self.assertEqual(fn(frequencies=[1,2,3]),(0.3,18,[1,2,3]))
182 self.assertEqual(fn(),(0.3,18,[10,20,30]))
183
184 def test_parameterized_function(self):
185 self._basic_tests(some_fn)
186
187 def test_parameterized_function_instance(self):
188 self._basic_tests(instance)
189
190 def test_pickle_instance(self):
191 import pickle
192 s = pickle.dumps(instance)
193 instance.scale=0.8
194 i = pickle.loads(s)
195 self.assertEqual(i(),(0.3,18,[10,20,30]))
196
197
198 @nottest
199 class TestPO1(param.Parameterized):
200 x = param.Number(default=numbergen.UniformRandom(lbound=-1,ubound=1,seed=1),bounds=(-1,1))
201 y = param.Number(default=1,bounds=(-1,1))
202
203 @istest
204 class TestNumberParameter(unittest.TestCase):
205
206 def test_outside_bounds(self):
207 t1 = TestPO1()
208 # Test bounds (non-dynamic number)
209 try:
210 t1.y = 10
211 except ValueError:
212 pass
213 else:
214 assert False, "Should raise ValueError."
215
216 def test_outside_bounds_numbergen(self):
217 t1 = TestPO1()
218 # Test bounds (dynamic number)
219 t1.x = numbergen.UniformRandom(lbound=2,ubound=3) # bounds not checked on set
220 try:
221 t1.x
222 except ValueError:
223 pass
224 else:
225 assert False, "Should raise ValueError."
226
227
228 @istest
229 class TestStringParameter(unittest.TestCase):
230
231 def setUp(self):
232 super(TestStringParameter, self).setUp()
233
234 class TestString(param.Parameterized):
235 a = param.String()
236 b = param.String(default='',allow_None=True)
237 c = param.String(default=None)
238
239 self._TestString = TestString
240
241 def test_handling_of_None(self):
242 t = self._TestString()
243
244 with self.assertRaises(ValueError):
245 t.a = None
246
247 t.b = None
248
249 assert t.c is None
250
251
252
253 @istest
254 class TestParamOverrides(unittest.TestCase):
255
256 def setUp(self):
257 super(TestParamOverrides, self).setUp()
258 self.po = param.Parameterized(name='A',print_level=0)
259
260 def test_init_name(self):
261 self.assertEqual(self.po.name, 'A')
262
263 def test_simple_override(self):
264 overrides = ParamOverrides(self.po,{'name':'B'})
265 self.assertEqual(overrides['name'], 'B')
266 self.assertEqual(overrides['print_level'], 0)
267
268 # CEBALERT: missing test for allow_extra_keywords (e.g. getting a
269 # warning on attempting to override non-existent parameter when
270 # allow_extra_keywords is False)
271
272 def test_missing_key(self):
273 overrides = ParamOverrides(self.po,{'name':'B'})
274 with self.assertRaises(AttributeError):
275 overrides['doesnotexist']
276
277
278 class TestSharedParameters(unittest.TestCase):
279
280 def setUp(self):
281 with shared_parameters():
282 self.p1 = TestPO(name='A', print_level=0)
283 self.p2 = TestPO(name='B', print_level=0)
284 self.ap1 = AnotherTestPO(name='A', print_level=0)
285 self.ap2 = AnotherTestPO(name='B', print_level=0)
286
287 def test_shared_object(self):
288 self.assertTrue(self.ap1.instPO is self.ap2.instPO)
289 self.assertTrue(self.ap1.params('instPO').default is not self.ap2.instPO)
290
291 def test_shared_list(self):
292 self.assertTrue(self.p1.inst is self.p2.inst)
293 self.assertTrue(self.p1.params('inst').default is not self.p2.inst)
294
295
296
297 if __name__ == "__main__":
298 import nose
299 nose.runmodule()
+0
-167
tests/API0/testparameterizedrepr.py less more
0 """
1 Unit test for the repr and pprint of parameterized objects.
2 """
3
4 import unittest
5 import param
6
7
8
9 class TestParameterizedRepr(unittest.TestCase):
10
11 def setUp(self):
12 # initialize a parameterized class
13 class A(param.Parameterized):
14 a = param.Number(4, precedence=-5)
15 b = param.String('B', precedence=-4)
16 c = param.Number(4, precedence=0)
17 d = param.Integer(-22, precedence=1)
18
19 x = param.Number(1, precedence=2)
20 y = param.Number(2, precedence=-1)
21 z = param.Number(3, precedence=-2)
22 def __init__(self, a, b, c=4, d=-22, **kwargs):
23 super(A, self).__init__(a=a, b=b, c=c, **kwargs)
24
25 self.A = A
26
27 class B(param.Parameterized): # Similar to A but no **kwargs
28 a = param.Number(4, precedence=-5)
29 b = param.String('B', precedence=-4)
30 c = param.Number(4, precedence=0)
31 d = param.Integer(-22, precedence=1)
32
33 x = param.Number(1, precedence=2)
34 def __init__(self, a, b, c=4, d=-22):
35 super(B, self).__init__(a=a, b=b, c=c, name='ClassB')
36
37 self.B = B
38
39 class C(param.Parameterized): # Similar to A but with *varargs
40 a = param.Number(4, precedence=-5)
41 b = param.String('B', precedence=-4)
42 c = param.Number(4, precedence=0)
43 d = param.Integer(-22, precedence=1)
44
45 x = param.Number(1, precedence=2)
46 y = param.Number(2, precedence=-1)
47 z = param.Number(3, precedence=-2)
48
49 def __init__(self, a, b, c=4, d=-22, *varargs, **kwargs):
50 super(C, self).__init__(a=a, b=b, c=c, **kwargs)
51
52 self.C = C
53
54
55 class D(param.Parameterized): # Similar to A but with missing parameters
56 a = param.Number(4, precedence=-5)
57 b = param.String('B', precedence=-4)
58
59 def __init__(self, a, b, c=4, d=-22, **kwargs):
60 super(D, self).__init__(a=a, b=b, **kwargs)
61
62 self.D = D
63
64
65 # More realistically, positional args are not params
66 class E(param.Parameterized):
67 a = param.Number(4, precedence=-5)
68
69 def __init__(self, p, q=4, **params): # (plus non-param kw too)
70 super(E, self).__init__(**params)
71
72 self.E = E
73
74
75 def testparameterizedrepr(self):
76 obj = self.A(4,'B', name='test1')
77 self.assertEqual(repr(obj),
78 "A(a=4, b='B', c=4, d=-22, name='test1', x=1, y=2, z=3)")
79
80 def testparameterizedscriptrepr1(self):
81 obj = self.A(4,'B', name='test')
82 self.assertEqual(obj.pprint(),
83 "A(4, 'B', name='test')")
84
85 def testparameterizedscriptrepr2(self):
86 obj = self.A(4,'B', c=5, name='test')
87 self.assertEqual(obj.pprint(),
88 "A(4, 'B', c=5, name='test')")
89
90 def testparameterizedscriptrepr3(self):
91 obj = self.A(4,'B', c=5, x=True, name='test')
92 self.assertEqual(obj.pprint(),
93 "A(4, 'B', c=5, name='test')")
94
95 def testparameterizedscriptrepr4(self):
96 obj = self.A(4,'B', c=5, x=10, name='test')
97 self.assertEqual(obj.pprint(),
98 "A(4, 'B', c=5, name='test', x=10)")
99
100
101 def testparameterizedscriptrepr5(self):
102 obj = self.A(4,'B', x=10, y=11, z=12, name='test')
103 self.assertEqual(obj.pprint(),
104 "A(4, 'B', name='test', z=12, y=11, x=10)")
105
106 def testparameterizedscriptrepr_nokwargs(self):
107 obj = self.B(4,'B', c=99)
108 obj.x = 10 # Modified but not passable through constructor
109 self.assertEqual(obj.pprint(),
110 "B(4, 'B', c=99)")
111
112 def testparameterizedscriptrepr_varags(self):
113 obj = self.C(4,'C', c=99)
114 self.assertEqual(obj.pprint(),
115 "C(4, 'C', c=99, **varargs)")
116
117 def testparameterizedscriptrepr_varags_kwargs(self):
118 obj = self.C(4,'C', c=99, x=10, y=11, z=12)
119 self.assertEqual(obj.pprint(),
120 "C(4, 'C', c=99, z=12, y=11, x=10, **varargs)")
121
122 def testparameterizedscriptrepr_missing_values(self):
123 obj = self.D(4,'D', c=99)
124 self.assertEqual(obj.pprint(),
125 "D(4, 'D', c=<?>, d=<?>)")
126
127 def testparameterizedscriptrepr_nonparams(self):
128 obj = self.E(10,q='hi', a=99)
129 self.assertEqual(obj.pprint(),
130 "E(<?>, q=<?>, a=99)")
131
132 def test_exceptions(self):
133 obj = self.E(10,q='hi',a=99)
134 try:
135 obj.pprint(unknown_value=False)
136 except Exception:
137 pass
138 else:
139 raise AssertionError
140
141 def test_suppression(self):
142 obj = self.E(10,q='hi',a=99)
143 self.assertEqual(obj.pprint(unknown_value=None),
144 "E(a=99)")
145
146 def test_imports_deduplication(self):
147 obj = self.E(10,q='hi', a=99)
148 imports = ['import me','import me']
149 obj.pprint(imports=imports)
150 self.assertEqual(imports.count('import me'),1)
151
152 def test_qualify(self):
153 obj = self.E(10,q='hi', a=99)
154
155 r = "E(<?>, q=<?>, a=99)"
156 self.assertEqual(obj.pprint(qualify=False),
157 r)
158
159 self.assertEqual(obj.pprint(qualify=True),
160 "tests.API0.testparameterizedrepr."+r)
161
162
163
164 if __name__ == "__main__":
165 import nose
166 nose.runmodule()
+0
-53
tests/API0/testrangeparameter.py less more
0 """
1 Unit test for Range parameters.
2 """
3
4 import unittest
5 import param
6
7
8 class TestRangeParameters(unittest.TestCase):
9
10 def test_initialization_out_of_bounds(self):
11 try:
12 class Q(param.Parameterized):
13 q = param.Range((0, 2), bounds=(0, 1))
14 except ValueError:
15 pass
16 else:
17 raise AssertionError("No exception raised on out-of-bounds date")
18
19 def test_set_exclusive_out_of_bounds_upper(self):
20 class Q(param.Parameterized):
21 q = param.Range(bounds=(0, 10), inclusive_bounds=(True, False))
22 try:
23 Q.q = (0, 10)
24 except ValueError:
25 pass
26 else:
27 raise AssertionError("No exception raised on out-of-bounds date")
28
29 def test_set_exclusive_out_of_bounds_lower(self):
30 class Q(param.Parameterized):
31 q = param.Range(bounds=(0, 10), inclusive_bounds=(False, True))
32 try:
33 Q.q = (0, 10)
34 except ValueError:
35 pass
36 else:
37 raise AssertionError("No exception raised on out-of-bounds date")
38
39 def test_set_out_of_bounds(self):
40 class Q(param.Parameterized):
41 q = param.Range(bounds=(0, 10))
42 try:
43 Q.q = (5, 11)
44 except ValueError:
45 pass
46 else:
47 raise AssertionError("No exception raised on out-of-bounds date")
48
49 def test_get_soft_bounds(self):
50 q = param.Range((1,3), bounds=(0, 10), softbounds=(1, 9))
51 self.assertEqual(q.get_soft_bounds(), (1, 9))
52
+0
-57
tests/API0/teststringparam.py less more
0 """
1 Unit test for String parameters
2 """
3
4 import unittest
5
6 import param
7
8
9 ip_regex = '^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$'
10
11 class TestStringParameters(unittest.TestCase):
12
13 def test_regex_ok(self):
14 class A(param.Parameterized):
15 s = param.String('0.0.0.0', ip_regex)
16
17 a = A()
18 a.s = '123.123.0.1'
19
20 def test_reject_none(self):
21 class A(param.Parameterized):
22 s = param.String('0.0.0.0', ip_regex)
23
24 a = A()
25
26 exception = "String 's' only takes a string value."
27 with self.assertRaisesRegexp(ValueError, exception):
28 a.s = None # because allow_None should be False
29
30 def test_default_none(self):
31 class A(param.Parameterized):
32 s = param.String(None, ip_regex)
33
34 a = A()
35 a.s = '123.123.0.1'
36 a.s = None # because allow_None should be True with default of None
37
38 def test_regex_incorrect(self):
39
40 class A(param.Parameterized):
41 s = param.String('0.0.0.0', regex=ip_regex)
42
43 a = A()
44
45 exception = "String 's': '123.123.0.256' does not match regex"
46 with self.assertRaisesRegexp(ValueError, exception):
47 a.s = '123.123.0.256'
48
49 def test_regex_incorrect_default(self):
50
51 exception = "String 'None': '' does not match regex"
52 with self.assertRaisesRegexp(ValueError, exception):
53 class A(param.Parameterized):
54 s = param.String(regex=ip_regex) # default value '' does not match regular expression
55
56
+0
-302
tests/API0/testtimedependent.py less more
0 """
1 Unit tests for the param.Time class, time dependent parameters and
2 time-dependent numbergenerators.
3 """
4 import unittest
5 import param
6 import numbergen
7 import copy
8
9 from nose.plugins.skip import SkipTest
10 import fractions
11
12 try:
13 import gmpy
14 except:
15 gmpy = None
16
17
18
19 class TestTimeClass(unittest.TestCase):
20
21 def test_time_init(self):
22 param.Time()
23
24 def test_time_init_int(self):
25 t = param.Time(time_type=int)
26 self.assertEqual(t(), 0)
27
28 def test_time_int_iter(self):
29 t = param.Time(time_type=int)
30 self.assertEqual(next(t), 0)
31 self.assertEqual(next(t), 1)
32
33 def test_time_init_timestep(self):
34 t = param.Time(time_type=int, timestep=2)
35 self.assertEqual(next(t), 0)
36 self.assertEqual(next(t), 2)
37
38 def test_time_int_until(self):
39 t = param.Time(time_type=int, until=3)
40 self.assertEqual(next(t), 0)
41 self.assertEqual(next(t), 1)
42 self.assertEqual(next(t), 2)
43 self.assertEqual(next(t), 3)
44 try:
45 self.assertEqual(next(t), 4)
46 raise AssertionError("StopIteration should have been raised")
47 except StopIteration:
48 pass
49
50 def test_time_int_eq(self):
51 t = param.Time(time_type=int)
52 s = param.Time(time_type=int)
53 t(3); s(3)
54 self.assertEqual(t == s, True)
55
56 def test_time_int_context(self):
57 t = param.Time(time_type=int)
58 t(3)
59 with t:
60 self.assertEqual(t(), 3)
61 t(5)
62 self.assertEqual(t(), 5)
63 self.assertEqual(t(), 3)
64
65 def test_time_int_context_iadd(self):
66
67 with param.Time(time_type=int) as t:
68 self.assertEqual(t(), 0)
69 t += 5
70 self.assertEqual(t(), 5)
71 self.assertEqual(t(), 0)
72
73 def test_time_int_change_type(self):
74 t = param.Time(time_type=int)
75 self.assertEqual(t(), 0)
76 t(1, fractions.Fraction)
77 self.assertEqual(t(), 1)
78 self.assertEqual(t.time_type, fractions.Fraction)
79
80 def test_time_init_gmpy(self):
81 if gmpy is None: raise SkipTest
82
83 t = param.Time(time_type=gmpy.mpq)
84 self.assertEqual(t(), gmpy.mpq(0))
85 t.advance(gmpy.mpq(0.25))
86 self.assertEqual(t(), gmpy.mpq(1,4))
87
88 def test_time_init_gmpy_advanced(self):
89 if gmpy is None: raise SkipTest
90 t = param.Time(time_type=gmpy.mpq,
91 timestep=gmpy.mpq(0.25),
92 until=1.5)
93 self.assertEqual(t(), gmpy.mpq(0,1))
94 t(0.5)
95 self.assertEqual(t(), gmpy.mpq(1,2))
96 with t:
97 t.advance(0.25)
98 self.assertEqual(t(), gmpy.mpq(3,4))
99 self.assertEqual(t(), gmpy.mpq(1,2))
100 tvals = [tval for tval in t]
101 self.assertEqual(tvals, [gmpy.mpq(1,2),
102 gmpy.mpq(3,4),
103 gmpy.mpq(1,1),
104 gmpy.mpq(5,4),
105 gmpy.mpq(3,2)])
106
107
108 class TestTimeDependentDynamic(unittest.TestCase):
109
110 def setUp(self):
111 param.Dynamic.time_dependent=None
112 self.time_fn= param.Time(time_type=int)
113
114 class Incrementer(object):
115 def __init__(self):
116 self.i = -1
117 def __call__(self):
118 self.i+=1
119 return self.i
120
121 self.Incrementer = Incrementer
122
123 class DynamicClass(param.Parameterized):
124 a = param.Number(default = self.Incrementer())
125
126 self.DynamicClass = DynamicClass
127 self._start_state = copy.copy([param.Dynamic.time_dependent,
128 numbergen.TimeAware.time_dependent,
129 param.Dynamic.time_fn,
130 numbergen.TimeAware.time_fn,
131 param.random_seed])
132
133 def tearDown(self):
134 param.Dynamic.time_dependent = self._start_state[0]
135 numbergen.TimeAware.time_dependent = self._start_state[1]
136 param.Dynamic.time_fn = self._start_state[2]
137 numbergen.TimeAware.time_fn = self._start_state[3]
138 param.random_seed = self._start_state[4]
139
140
141 def test_non_time_dependent(self):
142 """
143 With param.Dynamic.time_dependent=None every call should
144 increment.
145 """
146 param.Dynamic.time_dependent=None
147 param.Dynamic.time_fn = self.time_fn
148
149 dynamic = self.DynamicClass()
150 self.assertEqual(dynamic.a, 0)
151 self.assertEqual(dynamic.a, 1)
152 self.assertEqual(dynamic.a, 2)
153
154 def test_time_fixed(self):
155 """
156 With param.Dynamic.time_dependent=True the value should only
157 increment when the time value changes.
158 """
159 param.Dynamic.time_dependent=True
160 param.Dynamic.time_fn = self.time_fn
161
162 dynamic = self.DynamicClass()
163 self.assertEqual(dynamic.a, 0)
164 self.assertEqual(dynamic.a, 0)
165
166 self.time_fn += 1
167 self.assertEqual(dynamic.a, 1)
168 self.assertEqual(dynamic.a, 1)
169 param.Dynamic.time_fn -= 5
170 self.assertEqual(dynamic.a, 2)
171 self.assertEqual(dynamic.a, 2)
172
173
174 def test_time_dependent(self):
175 """
176 With param.Dynamic.time_dependent=True and param.Dynamic and
177 numbergen.TimeDependent sharing a common time_fn, the value
178 should be a function of time.
179 """
180 param.Dynamic.time_dependent=True
181 param.Dynamic.time_fn = self.time_fn
182 numbergen.TimeDependent.time_fn = self.time_fn
183
184 class DynamicClass(param.Parameterized):
185 b = param.Number(default = numbergen.ScaledTime(factor=2))
186
187 dynamic = DynamicClass()
188 self.time_fn(0)
189 self.assertEqual(dynamic.b, 0.0)
190 self.time_fn += 5
191 self.assertEqual(dynamic.b, 10.0)
192 self.assertEqual(dynamic.b, 10.0)
193 self.time_fn -= 2
194 self.assertEqual(dynamic.b, 6.0)
195 self.assertEqual(dynamic.b, 6.0)
196 self.time_fn -= 3
197 self.assertEqual(dynamic.b, 0.0)
198
199
200 def test_time_dependent_random(self):
201 """
202 When set to time_dependent=True, random number generators
203 should also be a function of time.
204 """
205 param.Dynamic.time_dependent=True
206 numbergen.TimeAware.time_dependent=True
207 param.Dynamic.time_fn = self.time_fn
208 numbergen.TimeAware.time_fn = self.time_fn
209 param.random_seed = 42
210
211 class DynamicClass(param.Parameterized):
212 c = param.Number(default = numbergen.UniformRandom(name = 'test1'))
213 d = param.Number(default = numbergen.UniformRandom(name = 'test2'))
214 e = param.Number(default = numbergen.UniformRandom(name = 'test1'))
215
216 dynamic = DynamicClass()
217
218 test1_t1 = 0.23589388250988552
219 test2_t1 = 0.12576257837158122
220 test1_t2 = 0.14117586161849593
221 test2_t2 = 0.9134917395930359
222
223 self.time_fn(0)
224 self.assertEqual(dynamic.c, test1_t1)
225 self.assertEqual(dynamic.c, dynamic.e)
226 self.assertNotEqual(dynamic.c, dynamic.d)
227 self.assertEqual(dynamic.d, test2_t1)
228 self.time_fn(1)
229 self.assertEqual(dynamic.c, test1_t2)
230 self.assertEqual(dynamic.c, test1_t2)
231 self.assertEqual(dynamic.d, test2_t2)
232 self.time_fn(0)
233 self.assertEqual(dynamic.c, test1_t1)
234 self.assertEqual(dynamic.d, test2_t1)
235
236
237 def test_time_hashing_integers(self):
238 """
239 Check that ints, fractions and strings hash to the same value
240 for integer values.
241 """
242 hashfn = numbergen.Hash("test", input_count=1)
243 hash_1 = hashfn(1)
244 hash_42 = hashfn(42)
245 hash_200001 = hashfn(200001)
246
247 self.assertEqual(hash_1, hashfn(fractions.Fraction(1)))
248 self.assertEqual(hash_1, hashfn("1"))
249
250 self.assertEqual(hash_42, hashfn(fractions.Fraction(42)))
251 self.assertEqual(hash_42, hashfn("42"))
252
253 self.assertEqual(hash_200001, hashfn(fractions.Fraction(200001)))
254 self.assertEqual(hash_200001, hashfn("200001"))
255
256
257 def test_time_hashing_rationals(self):
258 """
259 Check that hashes fractions and strings match for some
260 reasonable rational numbers.
261 """
262 hashfn = numbergen.Hash("test", input_count=1)
263 pi = "3.141592"
264 half = fractions.Fraction(0.5)
265 self.assertEqual(hashfn(0.5), hashfn(half))
266 self.assertEqual(hashfn(pi), hashfn(fractions.Fraction(pi)))
267
268
269 def test_time_hashing_integers_gmpy(self):
270 """
271 Check that hashes for gmpy values at the integers also matches
272 those of ints, fractions and strings.
273 """
274 if gmpy is None: raise SkipTest
275 hashfn = numbergen.Hash("test", input_count=1)
276 hash_1 = hashfn(1)
277 hash_42 = hashfn(42)
278
279 self.assertEqual(hash_1, hashfn(gmpy.mpq(1)))
280 self.assertEqual(hash_1, hashfn(1))
281
282 self.assertEqual(hash_42, hashfn(gmpy.mpq(42)))
283 self.assertEqual(hash_42, hashfn(42))
284
285 def test_time_hashing_rationals_gmpy(self):
286 """
287 Check that hashes of fractions and gmpy mpqs match for some
288 reasonable rational numbers.
289 """
290 if gmpy is None: raise SkipTest
291 pi = "3.141592"
292 hashfn = numbergen.Hash("test", input_count=1)
293 self.assertEqual(hashfn(0.5), hashfn(gmpy.mpq(0.5)))
294 self.assertEqual(hashfn(pi), hashfn(gmpy.mpq(3.141592)))
295
296
297
298
299 if __name__ == "__main__":
300 import nose
301 nose.runmodule()
+0
-10
tests/API1/__init__.py less more
0 import param
1 import unittest
2
3 class API1TestCase(unittest.TestCase):
4
5 def setUp(self):
6 param.parameterized.Parameters._disable_stubs = True
7
8 def tearDown(self):
9 param.parameterized.Parameters._disable_stubs = False
+0
-54
tests/API1/testcalendardateparam.py less more
0 """
1 Unit test for CalendarDate parameters.
2 """
3
4
5 import datetime as dt
6 import param
7 from . import API1TestCase
8
9
10 class TestDateTimeParameters(API1TestCase):
11
12 def test_initialization_out_of_bounds(self):
13 try:
14 class Q(param.Parameterized):
15 q = param.CalendarDate(dt.date(2017,2,27),
16 bounds=(dt.date(2017,2,1),
17 dt.date(2017,2,26)))
18 except ValueError:
19 pass
20 else:
21 raise AssertionError("No exception raised on out-of-bounds date")
22
23 def test_set_out_of_bounds(self):
24 class Q(param.Parameterized):
25 q = param.CalendarDate(bounds=(dt.date(2017,2,1),
26 dt.date(2017,2,26)))
27 try:
28 Q.q = dt.date(2017,2,27)
29 except ValueError:
30 pass
31 else:
32 raise AssertionError("No exception raised on out-of-bounds date")
33
34 def test_set_exclusive_out_of_bounds(self):
35 class Q(param.Parameterized):
36 q = param.CalendarDate(bounds=(dt.date(2017,2,1),
37 dt.date(2017,2,26)),
38 inclusive_bounds=(True, False))
39 try:
40 Q.q = dt.date(2017,2,26)
41 except ValueError:
42 pass
43 else:
44 raise AssertionError("No exception raised on out-of-bounds date")
45
46 def test_get_soft_bounds(self):
47 q = param.CalendarDate(dt.date(2017,2,25),
48 bounds=(dt.date(2017,2,1),
49 dt.date(2017,2,26)),
50 softbounds=(dt.date(2017,2,1),
51 dt.date(2017,2,25)))
52 self.assertEqual(q.get_soft_bounds(), (dt.date(2017,2,1),
53 dt.date(2017,2,25)))
+0
-78
tests/API1/testcalendardaterangeparam.py less more
0 """
1 Unit tests for CalendarDateRange parameter.
2 """
3
4 import datetime as dt
5 import param
6 from . import API1TestCase
7
8 # Assuming tests of range parameter cover most of what's needed to
9 # test date range.
10
11 class TestDateTimeRange(API1TestCase):
12
13 bad_range = (dt.date(2017,2,27),dt.date(2017,2,26))
14
15 def test_wrong_type_default(self):
16 try:
17 class Q(param.Parameterized):
18 a = param.CalendarDateRange(default=(1.0,2.0))
19 except ValueError:
20 pass
21 else:
22 raise AssertionError("Bad date type was accepted.")
23
24 def test_wrong_type_init(self):
25 class Q(param.Parameterized):
26 a = param.CalendarDateRange()
27
28 try:
29 Q(a=self.bad_range)
30 except ValueError:
31 pass
32 else:
33 raise AssertionError("Bad date type was accepted.")
34
35 def test_wrong_type_set(self):
36 class Q(param.Parameterized):
37 a = param.CalendarDateRange()
38 q = Q()
39
40 try:
41 q.a = self.bad_range
42 except ValueError:
43 pass
44 else:
45 raise AssertionError("Bad date type was accepted.")
46
47 def test_start_before_end_default(self):
48 try:
49 class Q(param.Parameterized):
50 a = param.CalendarDateRange(default=self.bad_range)
51 except ValueError:
52 pass
53 else:
54 raise AssertionError("Bad date range was accepted.")
55
56 def test_start_before_end_init(self):
57 class Q(param.Parameterized):
58 a = param.CalendarDateRange()
59
60 try:
61 Q(a=self.bad_range)
62 except ValueError:
63 pass
64 else:
65 raise AssertionError("Bad date range was accepted.")
66
67 def test_start_before_end_set(self):
68 class Q(param.Parameterized):
69 a = param.CalendarDateRange()
70
71 q = Q()
72 try:
73 q.a = self.bad_range
74 except ValueError:
75 pass
76 else:
77 raise AssertionError("Bad date range was accepted.")
+0
-97
tests/API1/testclassselector.py less more
0 """
1 Unit test for ClassSelector parameters.
2 """
3
4
5 from numbers import Number
6
7 import param
8 from . import API1TestCase
9
10
11 class TestClassSelectorParameters(API1TestCase):
12
13 def setUp(self):
14 super(TestClassSelectorParameters, self).setUp()
15 class P(param.Parameterized):
16 e = param.ClassSelector(default=1,class_=int)
17 f = param.ClassSelector(default=int,class_=Number, is_instance=False)
18 g = param.ClassSelector(default=1,class_=(int,str))
19 h = param.ClassSelector(default=int,class_=(int,str), is_instance=False)
20
21 self.P = P
22
23 def test_single_class_instance_constructor(self):
24 p = self.P(e=6)
25 self.assertEqual(p.e, 6)
26
27 def test_single_class_instance_error(self):
28 exception = "Parameter 'e' value must be an instance of int, not 'a'"
29 with self.assertRaisesRegexp(ValueError, exception):
30 self.P(e='a')
31
32 def test_single_class_type_constructor(self):
33 p = self.P(f=float)
34 self.assertEqual(p.f, float)
35
36 def test_single_class_type_error(self):
37 exception = "Parameter 'str' must be a subclass of Number, not 'type'"
38 with self.assertRaisesRegexp(ValueError, exception):
39 self.P(f=str)
40
41 def test_multiple_class_instance_constructor1(self):
42 p = self.P(g=1)
43 self.assertEqual(p.g, 1)
44
45 def test_multiple_class_instance_constructor2(self):
46 p = self.P(g='A')
47 self.assertEqual(p.g, 'A')
48
49 def test_multiple_class_instance_error(self):
50 exception = "Parameter 'g' value must be an instance of \(int, str\), not '3.0'"
51 with self.assertRaisesRegexp(ValueError, exception):
52 self.P(g=3.0)
53
54 def test_multiple_class_type_constructor1(self):
55 p = self.P(h=int)
56 self.assertEqual(p.h, int)
57
58 def test_multiple_class_type_constructor2(self):
59 p = self.P(h=str)
60 self.assertEqual(p.h, str)
61
62 def test_class_selector_get_range(self):
63 p = self.P()
64 classes = p.param.g.get_range()
65 self.assertIn('int', classes)
66 self.assertIn('str', classes)
67
68 def test_multiple_class_type_error(self):
69 exception = "Parameter 'float' must be a subclass of \(int, str\), not 'type'"
70 with self.assertRaisesRegexp(ValueError, exception):
71 self.P(h=float)
72
73
74 class TestDictParameters(API1TestCase):
75
76 def test_valid_dict_parameter(self):
77 valid_dict = {1:2, 3:3}
78
79 class Test(param.Parameterized):
80 items = param.Dict(default=valid_dict)
81
82 def test_valid_dict_parameter_positional(self):
83 valid_dict = {1:2, 3:3}
84
85 class Test(param.Parameterized):
86 items = param.Dict(valid_dict)
87
88 def test_dict_invalid_set(self):
89 valid_dict = {1:2, 3:3}
90 class Test(param.Parameterized):
91 items = param.Dict(valid_dict)
92
93 test = Test()
94 exception = "Parameter 'items' value must be an instance of dict, not '3'"
95 with self.assertRaisesRegexp(ValueError, exception):
96 test.items = 3
+0
-39
tests/API1/testcolorparameter.py less more
0 """
1 Unit test for Color parameters.
2 """
3 import param
4 from . import API1TestCase
5
6 class TestColorParameters(API1TestCase):
7
8 def test_initialization_invalid_string(self):
9 try:
10 class Q(param.Parameterized):
11 q = param.Color('red')
12 except ValueError:
13 pass
14 else:
15 raise AssertionError("No exception raised on out-of-bounds date")
16
17 def test_set_invalid_string(self):
18 class Q(param.Parameterized):
19 q = param.Color()
20 try:
21 Q.q = 'red'
22 except ValueError:
23 pass
24 else:
25 raise AssertionError("No exception raised on out-of-bounds date")
26
27 def test_valid_long_hex(self):
28 class Q(param.Parameterized):
29 q = param.Color()
30 Q.q = '#ffffff'
31 self.assertEqual(Q.q, '#ffffff')
32
33 def test_valid_short_hex(self):
34 class Q(param.Parameterized):
35 q = param.Color()
36 Q.q = '#fff'
37 self.assertEqual(Q.q, '#fff')
38
+0
-100
tests/API1/testcompositeparams.py less more
0 """
1 Unit test for composite parameters.
2
3 Originally implemented as doctests in Topographica in the file
4 testCompositeParameter.txt
5 """
6
7 import param
8 from . import API1TestCase
9
10 class TestCompositeParameters(API1TestCase):
11
12 def setUp(self):
13 super(TestCompositeParameters, self).setUp()
14 # initialize a class with a compound parameter
15 class A(param.Parameterized):
16 x = param.Number(default=0)
17 y = param.Number(default=0)
18 xy = param.Composite(attribs=['x','y'])
19
20 self.A = A
21 self.a = self.A()
22
23 class SomeSequence(object):
24 "Can't use iter with Dynamic (doesn't pickle, doesn't copy)"
25 def __init__(self,sequence):
26 self.sequence=sequence
27 self.index=0
28 def __call__(self):
29 val=self.sequence[self.index]
30 self.index+=1
31 return val
32
33 self.SomeSequence = SomeSequence
34
35 def test_initialization(self):
36 "Make an instance and do default checks"
37 self.assertEqual(self.a.x, 0)
38 self.assertEqual(self.a.y, 0)
39 self.assertEqual(self.a.xy, [0,0])
40
41
42 def test_set_component(self):
43 self.a.x = 1
44 self.assertEqual(self.a.xy, [1,0])
45
46 def test_set_compound(self):
47 self.a.xy = (2,3)
48 self.assertEqual(self.a.x, 2)
49 self.assertEqual(self.a.y, 3)
50
51 def test_compound_class(self):
52 " Get the compound on the class "
53 self.assertEqual(self.A.xy, [0,0])
54
55 def test_set_compound_class_set(self):
56 self.A.xy = (5,6)
57 self.assertEqual(self.A.x, 5)
58 self.assertEqual(self.A.y, 6)
59
60 def test_set_compound_class_instance(self):
61 self.A.xy = (5,6)
62 # # Make a new instance
63 b = self.A()
64 self.assertEqual(b.x, 5)
65 self.assertEqual(b.y, 6)
66
67 def test_set_compound_class_instance_unchanged(self):
68 self.a.xy = (2,3)
69 self.A.xy = (5,6)
70 self.assertEqual(self.a.x, 2)
71 self.assertEqual(self.a.y, 3)
72
73 def test_composite_dynamic(self):
74 """
75 Check CompositeParameter is ok with Dynamic
76 CB: this test is really of Parameterized.
77 """
78 a2 = self.A(x=self.SomeSequence([1,2,3]),
79 y=self.SomeSequence([4,5,6]))
80
81 a2.x, a2.y # Call of x and y params
82 # inspect should not advance numbers
83 self.assertEqual(a2.param.inspect_value('xy'), [1, 4])
84
85 def test_composite_dynamic_generator(self):
86
87 a2 = self.A(x=self.SomeSequence([1,2,3]),
88 y=self.SomeSequence([4,5,6]))
89
90 a2.x, a2.y # Call of x and y params
91 ix,iy = a2.param.get_value_generator('xy')
92 # get_value_generator() should give the objects
93 self.assertEqual(ix(), 2)
94 self.assertEqual(iy(), 5)
95
96
97 if __name__ == "__main__":
98 import nose
99 nose.runmodule()
+0
-54
tests/API1/testdateparam.py less more
0 """
1 Unit test for Date parameters.
2 """
3
4
5 import datetime as dt
6 import param
7 from . import API1TestCase
8
9 class TestDateParameters(API1TestCase):
10
11 def test_initialization_out_of_bounds(self):
12 try:
13 class Q(param.Parameterized):
14 q = param.Date(dt.datetime(2017,2,27),
15 bounds=(dt.datetime(2017,2,1),
16 dt.datetime(2017,2,26)))
17 except ValueError:
18 pass
19 else:
20 raise AssertionError("No exception raised on out-of-bounds date")
21
22 def test_set_out_of_bounds(self):
23 class Q(param.Parameterized):
24 q = param.Date(bounds=(dt.datetime(2017,2,1),
25 dt.datetime(2017,2,26)))
26 try:
27 Q.q = dt.datetime(2017,2,27)
28 except ValueError:
29 pass
30 else:
31 raise AssertionError("No exception raised on out-of-bounds date")
32
33 def test_set_exclusive_out_of_bounds(self):
34 class Q(param.Parameterized):
35 q = param.Date(bounds=(dt.datetime(2017,2,1),
36 dt.datetime(2017,2,26)),
37 inclusive_bounds=(True, False))
38 try:
39 Q.q = dt.datetime(2017,2,26)
40 except ValueError:
41 pass
42 else:
43 raise AssertionError("No exception raised on out-of-bounds date")
44
45 def test_get_soft_bounds(self):
46 q = param.Date(dt.datetime(2017,2,25),
47 bounds=(dt.datetime(2017,2,1),
48 dt.datetime(2017,2,26)),
49 softbounds=(dt.datetime(2017,2,1),
50 dt.datetime(2017,2,25)))
51 self.assertEqual(q.get_soft_bounds(), (dt.datetime(2017,2,1),
52 dt.datetime(2017,2,25)))
53
+0
-80
tests/API1/testdaterangeparam.py less more
0 """
1 Unit tests for DateRange parameter.
2 """
3
4 import datetime as dt
5 import param
6 from . import API1TestCase
7
8 # Assuming tests of range parameter cover most of what's needed to
9 # test date range.
10
11 class TestDateRange(API1TestCase):
12
13 bad_range = (dt.datetime(2017,2,27),dt.datetime(2017,2,26))
14
15 def test_wrong_type_default(self):
16 try:
17 class Q(param.Parameterized):
18 a = param.DateRange(default=(1.0,2.0))
19 except ValueError:
20 pass
21 else:
22 raise AssertionError("Bad date type was accepted.")
23
24 def test_wrong_type_init(self):
25 class Q(param.Parameterized):
26 a = param.DateRange()
27
28 try:
29 Q(a=self.bad_range)
30 except ValueError:
31 pass
32 else:
33 raise AssertionError("Bad date type was accepted.")
34
35 def test_wrong_type_set(self):
36 class Q(param.Parameterized):
37 a = param.DateRange()
38 q = Q()
39
40 try:
41 q.a = self.bad_range
42 except ValueError:
43 pass
44 else:
45 raise AssertionError("Bad date type was accepted.")
46
47 def test_start_before_end_default(self):
48 try:
49 class Q(param.Parameterized):
50 a = param.DateRange(default=self.bad_range)
51 except ValueError:
52 pass
53 else:
54 raise AssertionError("Bad date range was accepted.")
55
56 def test_start_before_end_init(self):
57 class Q(param.Parameterized):
58 a = param.DateRange()
59
60 try:
61 Q(a=self.bad_range)
62 except ValueError:
63 pass
64 else:
65 raise AssertionError("Bad date range was accepted.")
66
67 def test_start_before_end_set(self):
68 class Q(param.Parameterized):
69 a = param.DateRange()
70
71 q = Q()
72 try:
73 q.a = self.bad_range
74 except ValueError:
75 pass
76 else:
77 raise AssertionError("Bad date range was accepted.")
78
79
+0
-57
tests/API1/testdefaults.py less more
0 """
1 Do all subclasses of Parameter supply a valid default?
2 """
3
4 from param.parameterized import add_metaclass
5 from param import concrete_descendents, Parameter
6
7 # import all parameter types
8 from param import * # noqa
9 from param import ClassSelector
10 from . import API1TestCase
11
12 positional_args = {
13 ClassSelector: (object,)
14 }
15
16 skip = []
17
18 try:
19 import numpy # noqa
20 except ImportError:
21 skip.append('Array')
22 try:
23 import pandas # noqa
24 except ImportError:
25 skip.append('DataFrame')
26 skip.append('Series')
27
28
29 class TestDefaultsMetaclass(type):
30 def __new__(mcs, name, bases, dict_):
31
32 def test_skip(*args,**kw):
33 from nose.exc import SkipTest
34 raise SkipTest
35
36 def add_test(p):
37 def test(self):
38 # instantiate parameter with no default (but supply
39 # any required args)
40 p(*positional_args.get(p,tuple()))
41 return test
42
43 for p_name, p_type in concrete_descendents(Parameter).items():
44 dict_["test_default_of_%s"%p_name] = add_test(p_type) if p_name not in skip else test_skip
45
46 return type.__new__(mcs, name, bases, dict_)
47
48
49 @add_metaclass(TestDefaultsMetaclass)
50 class TestDefaults(API1TestCase):
51 pass
52
53
54 if __name__ == "__main__":
55 import nose
56 nose.runmodule()
+0
-294
tests/API1/testdynamicparams.py less more
0 """
1 Unit test for dynamic parameters.
2
3 Tests __get__, __set__ and that inspect_value() and
4 get_value_generator() work.
5
6 Originally implemented as doctests in Topographica in the file
7 testDynamicParameter.txt
8 """
9
10 import copy
11 import param
12 import numbergen
13 from . import API1TestCase
14
15
16 class TestDynamicParameters(API1TestCase):
17
18 def setUp(self):
19 super(TestDynamicParameters, self).setUp()
20 param.Dynamic.time_dependent = False
21
22 class TestPO1(param.Parameterized):
23 x = param.Dynamic(default=numbergen.UniformRandom(lbound=-1,ubound=1,seed=1),doc="nothing")
24 y = param.Dynamic(default=1)
25
26 class TestPO2(param.Parameterized):
27 x = param.Dynamic(default=numbergen.UniformRandom(lbound=-1,ubound=1,seed=30))
28 y = param.Dynamic(default=1.0)
29
30 self.TestPO2 = TestPO2
31 self.TestPO1 = TestPO1
32
33 self.t1 = self.TestPO1()
34 self.t2 = self.TestPO1(x=numbergen.UniformRandom(lbound=-1,ubound=1,seed=10))
35 self.t3 = self.TestPO1(x=numbergen.UniformRandom(lbound=-1,ubound=1,seed=10))
36 self.t2.param.set_dynamic_time_fn(None)
37 self.t3.param.set_dynamic_time_fn(None)
38
39 self.t6 = self.TestPO2()
40 self.t7 = self.TestPO2()
41
42
43 class TestDynamicParameterBasics(TestDynamicParameters):
44
45 def test_set_dynamic_time_fn_x(self):
46 self.t1.param.set_dynamic_time_fn(None)
47 self.assertEqual(
48 self.t1.param.params()['x']._value_is_dynamic(self.t1), True)
49
50 def test_set_dynamic_time_fn_y(self):
51 self.assertEqual(
52 self.t1.param.params()['y']._value_is_dynamic(self.t1), False)
53
54 def test_inspect_x(self):
55 "no value generated yet"
56 self.assertEqual(self.t1.param.inspect_value('x'), None)
57
58 def test_inspect_y(self):
59 self.assertEqual(self.t1.param.inspect_value('y'), 1)
60
61 def test_inspect_y_set(self):
62 self.t1.y = 2
63 self.assertEqual(self.t1.param.inspect_value('y'), 2)
64
65 def test_set_dynamic_numbergen(self):
66 is_numbergen = isinstance(self.t2.param.get_value_generator('x'),
67 numbergen.UniformRandom)
68 self.assertEqual(is_numbergen, True)
69
70 def test_matching_numbergen_streams(self):
71 "check that t2 and t3 have identical streams"
72 self.assertEqual(self.t2.x, self.t3.x)
73
74 def test_numbergen_objects_distinct(self):
75 "check t2 and t3 do not share UniformRandom objects"
76 self.t2.x
77 self.assertNotEqual(self.t2.param.inspect_value('x'),
78 self.t3.param.inspect_value('x'))
79
80 def test_numbergen_inspect(self):
81 " inspect_value() should return last generated value "
82 self.t2.x # Call 1
83 self.t2.x # Call 2
84 t2_last_value = self.t2.x # advance t2 beyond t3
85
86 self.assertEqual(self.t2.param.inspect_value('x'),
87 t2_last_value)
88 # ensure last_value is not shared
89 self.assertNotEqual(self.t3.param.inspect_value('x'), t2_last_value)
90
91 def test_dynamic_value_instantiated(self):
92 t6_first_value = self.t6.x
93 self.assertNotEqual(self.t7.param.inspect_value('x'),
94 t6_first_value)
95
96 def test_non_dynamic_value_not_instantiated(self):
97 " non-dynamic value not instantiated"
98 self.TestPO2.y = 4
99 self.assertEqual(self.t6.y, 4)
100 self.assertEqual(self.t7.y, 4)
101
102 def test_dynamic_value_setting(self):
103 self.t6.y = numbergen.UniformRandom()
104 t8 = self.TestPO2()
105 self.TestPO2.y = 10
106 # t6 got a dynamic value, but shouldn't have changed Parameter's instantiate
107 self.assertEqual(t8.y, 10)
108
109 def test_setting_y_param_numbergen(self):
110 self.TestPO2.y=numbergen.UniformRandom() # now the Parameter instantiate should be true
111 t9 = self.TestPO2()
112 self.assertEqual('_y_param_value' in t9.__dict__, True)
113
114 def test_shared_numbergen(self):
115 """
116 Instances of TestPO2 that don't have their own value for the
117 parameter share one UniformRandom object
118 """
119 self.TestPO2.y=numbergen.UniformRandom() # now the Parameter instantiate should be true
120 self.assertEqual(self.t7.param.get_value_generator('y') is self.TestPO2().param.params()['y'].default, True)
121 self.assertEqual(self.TestPO2().param.params()['y'].default.__class__.__name__, 'UniformRandom')
122
123 def test_copy_match(self):
124 "check a copy is the same"
125 t9 = copy.deepcopy(self.t7)
126 self.assertEqual(t9.param.get_value_generator('y') is self.TestPO2().param.params()['y'].default, True)
127
128
129
130 class TestDynamicTimeDependent(TestDynamicParameters):
131
132 def setUp(self):
133 super(TestDynamicTimeDependent, self).setUp()
134 param.Dynamic.time_dependent = True
135
136 class TestPO3(param.Parameterized):
137 x = param.Dynamic(default=numbergen.UniformRandom(name='xgen',
138 time_dependent=True))
139
140 class TestPO4(self.TestPO1):
141 "Nested parameterized objects"
142 z = param.Parameter(default=self.TestPO1())
143
144 self.TestPO3 = TestPO3
145 self.TestPO4 = TestPO4
146
147 self.t10 = self.TestPO1()
148 self.t11 = TestPO3()
149
150 def test_dynamic_values_unchanged_dependent(self):
151 param.Dynamic.time_dependent = True
152 call_1 = self.t10.x
153 call_2 = self.t10.x
154 call_3 = self.t10.x
155 self.assertEqual(call_1, call_2)
156 self.assertEqual(call_2, call_3)
157
158 def test_dynamic_values_changed_independent(self):
159 param.Dynamic.time_dependent = False
160 call_1 = self.t10.x
161 call_2 = self.t10.x
162 call_3 = self.t10.x
163 self.assertNotEqual(call_1, call_2)
164 self.assertNotEqual(call_2, call_3)
165
166 def test_dynamic_values_change(self):
167 param.Dynamic.time_dependent = True
168 with param.Dynamic.time_fn as t:
169 t(0)
170 call_1 = self.t10.x
171 t += 1
172 call_2 = self.t10.x
173 t(0)
174 call_3 = self.t10.x
175 self.assertNotEqual(call_1, call_2)
176 self.assertNotEqual(call_1, call_3)
177
178 def test_dynamic_values_time_dependent(self):
179 param.Dynamic.time_dependent = True
180 with param.Dynamic.time_fn as t:
181 t(0)
182 call_1 = self.t11.x
183 t += 1
184 call_2 = self.t11.x
185 t(0)
186 call_3 = self.t11.x
187 self.assertNotEqual(call_1, call_2)
188 self.assertEqual(call_1, call_3)
189
190 def test_class_dynamic_values_change(self):
191 call_1 = self.TestPO3.x
192 call_2 = self.TestPO3.x
193 self.assertEqual(call_1, call_2)
194 with param.Dynamic.time_fn as t:
195 t += 1
196 call_3 = self.TestPO3.x
197 self.assertNotEqual(call_2, call_3)
198
199 def test_dynamic_value_change_independent(self):
200 t12 = self.TestPO1()
201 t12.param.set_dynamic_time_fn(None)
202 self.assertNotEqual(t12.x, t12.x)
203 self.assertEqual(t12.y, t12.y)
204
205 def test_dynamic_value_change_disabled(self):
206 " time_fn set on the UniformRandom() when t13.y was set"
207 t13 = self.TestPO1()
208 t13.param.set_dynamic_time_fn(None)
209 t13.y = numbergen.UniformRandom()
210 self.assertNotEqual(t13.y, t13.y)
211
212 def test_dynamic_value_change_enabled(self):
213 " time_fn set on the UniformRandom() when t13.y was set"
214 t14 = self.TestPO1()
215 t14.y = numbergen.UniformRandom()
216 self.assertEqual(t14.y, t14.y)
217
218
219 def test_dynamic_time_fn_not_inherited(self):
220 " time_fn not inherited"
221 t15 = self.TestPO4()
222 t15.param.set_dynamic_time_fn(None)
223 with param.Dynamic.time_fn as t:
224 call_1 = t15.z.x
225 t += 1
226 call_2 = t15.z.x
227 self.assertNotEqual(call_1, call_2)
228
229
230
231 class TestDynamicSharedNumbergen(TestDynamicParameters):
232 "Check shared generator"
233 def setUp(self):
234 super(TestDynamicSharedNumbergen, self).setUp()
235 self.shared = numbergen.UniformRandom(lbound=-1,ubound=1,seed=20)
236
237 def test_dynamic_shared_numbergen(self):
238 param.Dynamic.time_dependent = True
239 t11 = self.TestPO1(x=self.shared)
240 t12 = self.TestPO1(x=self.shared)
241
242 with param.Dynamic.time_fn as t:
243 t += 1
244 call_1 = t11.x
245 self.assertEqual(call_1, t12.x)
246 t += 1
247 self.assertNotEqual(call_1, t12.x)
248
249
250
251 if __name__ == "__main__":
252 import nose
253 nose.runmodule()
254
255
256 # Commented out block in the original doctest version.
257 # Maybe these are features originally planned but never implemented
258
259 """
260 It is not yet possible to set time_fn for a Parameter instance
261 >>> class TestPO5(param.Parameterized):
262 ... x = param.Dynamic(default=numbergen.UniformRandom(),dynamic_time_fn=None)
263 """
264
265 """
266 We currently don't support iterators/generators in Dynamic unless
267 they're wrapped.
268
269 >>> i = iter([1,2,3])
270 >>> t11.x = i
271
272 >>> topo.sim.run(1)
273
274 >>> t11.x
275 1
276
277 >>> def gen():
278 ... yield 2
279 ... yield 4
280 ... yield 6
281
282 >>> g = gen()
283
284 >>> t11.x = g
285
286 >>> t11.x
287 2
288
289 >>> topo.sim.run(1)
290
291 >>> t11.x
292 4
293 """
+0
-67
tests/API1/testipythonmagic.py less more
0 """
1 Unit test for the IPython magic
2 """
3
4 import re
5 import sys
6 import param
7 from . import API1TestCase
8
9 try:
10 import IPython # noqa
11 except ImportError:
12 import os
13 if os.getenv('PARAM_TEST_IPYTHON','0') == '1':
14 raise ImportError("PARAM_TEST_IPYTHON=1 but ipython not available.")
15
16 # TODO: is the below actually true?
17
18 # SkipTest will be raised if IPython unavailable
19 from param.ipython import ParamPager
20
21 test1_repr = """\x1b[1;32mParameters of 'TestClass'\n=========================\n\x1b[0m\n\x1b[1;31mParameters changed from their default values are marked in red.\x1b[0m\n\x1b[1;36mSoft bound values are marked in cyan.\x1b[0m\nC/V= Constant/Variable, RO/RW = ReadOnly/ReadWrite, AN=Allow None\n\n\x1b[1;34mNameValue Type Bounds Mode \x1b[0m\n\nu 4 Number V RW \nv 4 Number C RW \nw 4 Number C RO \nx None String V RW AN \ny 4 Number (-1, None) V RW \nz 4 Number (-1, 100) V RW \n\n\x1b[1;32mParameter docstrings:\n=====================\x1b[0m\n\n\x1b[1;34mu: < No docstring available >\x1b[0m\n\x1b[1;31mv: < No docstring available >\x1b[0m\n\x1b[1;34mw: < No docstring available >\x1b[0m\n\x1b[1;31mx: < No docstring available >\x1b[0m\n\x1b[1;34my: < No docstring available >\x1b[0m\n\x1b[1;31mz: < No docstring available >\x1b[0m"""
22
23
24 test2_repr = """\x1b[1;32mParameters of 'TestClass' instance\n==================================\n\x1b[0m\n\x1b[1;31mParameters changed from their default values are marked in red.\x1b[0m\n\x1b[1;36mSoft bound values are marked in cyan.\x1b[0m\nC/V= Constant/Variable, RO/RW = ReadOnly/ReadWrite, AN=Allow None\n\n\x1b[1;34mNameValue Type Bounds Mode \x1b[0m\n\nu 4 Number V RW \nv 4 Number C RW \nw 4 Number C RO \nx None String V RW AN \ny 4 Number (-1, None) V RW \nz 4 Number (-1, 100) V RW \n\n\x1b[1;32mParameter docstrings:\n=====================\x1b[0m\n\n\x1b[1;34mu: < No docstring available >\x1b[0m\n\x1b[1;31mv: < No docstring available >\x1b[0m\n\x1b[1;34mw: < No docstring available >\x1b[0m\n\x1b[1;31mx: < No docstring available >\x1b[0m\n\x1b[1;34my: < No docstring available >\x1b[0m\n\x1b[1;31mz: < No docstring available >\x1b[0m"""
25
26 class TestParamPager(API1TestCase):
27
28 def setUp(self):
29 super(TestParamPager, self).setUp()
30 self.maxDiff = None
31 class TestClass(param.Parameterized):
32 u = param.Number(4)
33 v = param.Number(4, constant=True)
34 w = param.Number(4, readonly=True)
35 x = param.String(None, allow_None=True)
36 y = param.Number(4, bounds=(-1, None))
37 z = param.Number(4, bounds=(-1, 100), softbounds=(-100, -200))
38
39 self.TestClass = TestClass
40 self.pager = ParamPager()
41
42 def test_parameterized_class(self):
43 page_string = self.pager(self.TestClass)
44 # Remove params automatic numbered names
45 page_string = re.sub('TestClass(\d+)', 'TestClass', page_string)
46 ref_string = re.sub('TestClass(\d+)', 'TestClass', test1_repr)
47
48 try:
49 self.assertEqual(page_string, ref_string)
50 except Exception as e:
51 sys.stderr.write(page_string) # Coloured output
52 sys.stderr.write("\nRAW STRING:\n\n%r\n\n" % page_string)
53 raise e
54
55 def test_parameterized_instance(self):
56 page_string = self.pager(self.TestClass())
57 # Remove params automatic numbered names
58 page_string = re.sub('TestClass(\d+)', 'TestClass', page_string)
59 ref_string = re.sub('TestClass(\d+)', 'TestClass', test2_repr)
60
61 try:
62 self.assertEqual(page_string, ref_string)
63 except Exception as e:
64 sys.stderr.write(page_string) # Coloured output
65 sys.stderr.write("\nRAW STRING:\n\n%r\n\n" % page_string)
66 raise e
+0
-160
tests/API1/testlistselector.py less more
0 import param
1 from . import API1TestCase
2 # TODO: I copied the tests from testobjectselector, although I
3 # struggled to understand some of them. Both files should be reviewed
4 # and cleaned up together.
5
6 # TODO: tests copied from testobjectselector could use assertRaises
7 # context manager (and could be updated in testobjectselector too).
8
9 class TestListSelectorParameters(API1TestCase):
10
11 def setUp(self):
12 super(TestListSelectorParameters, self).setUp()
13 class P(param.Parameterized):
14 e = param.ListSelector(default=[5],objects=[5,6,7])
15 f = param.ListSelector(default=10)
16 h = param.ListSelector(default=None)
17 g = param.ListSelector(default=None,objects=[7,8])
18 i = param.ListSelector(default=[7],objects=[9],check_on_set=False)
19
20 self.P = P
21
22 def test_default_None(self):
23 class Q(param.Parameterized):
24 r = param.ListSelector(default=None)
25
26 def test_set_object_constructor(self):
27 p = self.P(e=[6])
28 self.assertEqual(p.e, [6])
29
30 def test_set_object_outside_bounds(self):
31 p = self.P(e=[6])
32 try:
33 p.e = [9]
34 except ValueError:
35 pass
36 else:
37 raise AssertionError("Object set outside range.")
38
39 def test_set_object_setattr(self):
40 p = self.P(e=[6])
41 p.f = [9]
42 self.assertEqual(p.f, [9])
43 p.g = [7]
44 self.assertEqual(p.g, [7])
45 p.i = [12]
46 self.assertEqual(p.i, [12])
47
48
49 def test_set_object_not_None(self):
50 p = self.P(e=[6])
51 p.g = [7]
52 try:
53 p.g = None
54 except TypeError:
55 pass
56 else:
57 raise AssertionError("Object set outside range.")
58
59 def test_set_one_object_not_None(self):
60 p = self.P(e=[6])
61 p.g = [7]
62 try:
63 p.g = [None]
64 except ValueError:
65 pass
66 else:
67 raise AssertionError("Object set outside range.")
68
69
70 def test_set_object_setattr_post_error(self):
71 p = self.P(e=[6])
72 p.f = [9]
73 self.assertEqual(p.f, [9])
74 p.g = [7]
75 try:
76 p.g = [None]
77 except ValueError:
78 pass
79 else:
80 raise AssertionError("Object set outside range.")
81
82 self.assertEqual(p.g, [7])
83 p.i = [12]
84 self.assertEqual(p.i, [12])
85
86 def test_initialization_out_of_bounds(self):
87 try:
88 class Q(param.Parameterized):
89 q = param.ListSelector([5],objects=[4])
90 except ValueError:
91 pass
92 else:
93 raise AssertionError("ListSelector created outside range.")
94
95
96 def test_initialization_no_bounds(self):
97 try:
98 class Q(param.Parameterized):
99 q = param.ListSelector([5],objects=10)
100 except TypeError:
101 pass
102 else:
103 raise AssertionError("ListSelector created without range.")
104
105
106 ##################################################################
107 ##################################################################
108 ### new tests (not copied from testobjectselector)
109
110 def test_bad_default(self):
111 with self.assertRaises(TypeError):
112 class Q(param.Parameterized):
113 r = param.ListSelector(default=6,check_on_set=True)
114
115 def test_implied_check_on_set(self):
116 with self.assertRaises(TypeError):
117 class Q(param.Parameterized):
118 r = param.ListSelector(default=7,objects=[7,8])
119
120 def test_default_not_checked(self):
121 class Q(param.Parameterized):
122 r = param.ListSelector(default=[6])
123
124 ##########################
125 # CEBALERT: not sure it makes sense for ListSelector to be set to
126 # a non-iterable value (except None). I.e. I think this first test
127 # should fail.
128 def test_default_not_checked_to_be_iterable(self):
129 class Q(param.Parameterized):
130 r = param.ListSelector(default=6)
131
132 def test_set_checked_to_be_iterable(self):
133 class Q(param.Parameterized):
134 r = param.ListSelector(default=6,check_on_set=False)
135
136 with self.assertRaises(TypeError):
137 Q.r = 6
138 ##########################
139
140
141 def test_compute_default(self):
142 class Q(param.Parameterized):
143 r = param.ListSelector(default=None, compute_default_fn=lambda: [1,2,3])
144
145 self.assertEqual(Q.r, None)
146 Q.param.params('r').compute_default()
147 self.assertEqual(Q.r, [1,2,3])
148 self.assertEqual(Q.param.params('r').objects, [1,2,3])
149
150 def test_bad_compute_default(self):
151 class Q(param.Parameterized):
152 r = param.ListSelector(default=None,compute_default_fn=lambda:1)
153
154 with self.assertRaises(TypeError):
155 Q.param.params('r').compute_default()
156
157 if __name__ == "__main__":
158 import nose
159 nose.runmodule()
+0
-37
tests/API1/testnumbergen.py less more
0 """
1 Test cases for the numbergen module.
2 """
3 import numbergen
4 from . import API1TestCase
5
6 _seed = 0 # keep tests deterministic
7 _iterations = 1000
8
9
10 class TestUniformRandom(API1TestCase):
11 def test_range(self):
12 lbound = 2.0
13 ubound = 5.0
14 gen = numbergen.UniformRandom(
15 seed=_seed,
16 lbound=lbound,
17 ubound=ubound)
18 for _ in range(_iterations):
19 value = gen()
20 self.assertTrue(lbound <= value < ubound)
21
22 class TestUniformRandomOffset(API1TestCase):
23 def test_range(self):
24 lbound = 2.0
25 ubound = 5.0
26 gen = numbergen.UniformRandomOffset(
27 seed=_seed,
28 mean=(ubound + lbound) / 2,
29 range=ubound - lbound)
30 for _ in range(_iterations):
31 value = gen()
32 self.assertTrue(lbound <= value < ubound)
33
34 if __name__ == "__main__":
35 import nose
36 nose.runmodule()
+0
-54
tests/API1/testnumberparameter.py less more
0 """
1 Unit test for Number parameters and their subclasses.
2 """
3 import param
4 import datetime as dt
5 from . import API1TestCase
6
7
8 class TestNumberParameters(API1TestCase):
9
10 def test_initialization_without_step_class(self):
11 class Q(param.Parameterized):
12 q = param.Number(default=1)
13
14 self.assertEqual(Q.param['q'].step, None)
15
16 def test_initialization_with_step_class(self):
17 class Q(param.Parameterized):
18 q = param.Number(default=1, step=0.5)
19
20 self.assertEqual(Q.param['q'].step, 0.5)
21
22 def test_initialization_without_step_instance(self):
23 class Q(param.Parameterized):
24 q = param.Number(default=1)
25
26 self.assertEqual(Q.param['q'].step, None)
27
28 def test_initialization_with_step_instance(self):
29 class Q(param.Parameterized):
30 q = param.Number(default=1, step=0.5)
31
32 qobj = Q()
33 self.assertEqual(qobj.param['q'].step, 0.5)
34
35 def test_step_invalid_type_number_parameter(self):
36 exception = "Step parameter can only be None or a numeric value"
37 with self.assertRaisesRegexp(ValueError, exception):
38 param.Number(step='invalid value')
39
40 def test_step_invalid_type_integer_parameter(self):
41 exception = "Step parameter can only be None or an integer value"
42 with self.assertRaisesRegexp(ValueError, exception):
43 param.Integer(step=3.4)
44
45 def test_step_invalid_type_datetime_parameter(self):
46 exception = "Step parameter can only be None, a datetime or datetime type"
47 with self.assertRaisesRegexp(ValueError, exception):
48 param.Date(dt.datetime(2017,2,27), step=3.2)
49
50 def test_step_invalid_type_date_parameter(self):
51 exception = "Step parameter can only be None or a date type"
52 with self.assertRaisesRegexp(ValueError, exception):
53 param.CalendarDate(dt.date(2017,2,27), step=3.2)
+0
-47
tests/API1/testnumpy.py less more
0 """
1 If numpy's present, is numpy stuff ok?
2 """
3 import unittest
4 import os
5
6 import param
7 from . import API1TestCase
8
9 try:
10 import numpy
11 import numpy.testing
12 except ImportError:
13 if os.getenv('PARAM_TEST_NUMPY','0') == '1':
14 raise ImportError("PARAM_TEST_NUMPY=1 but numpy not available.")
15 else:
16 raise unittest.SkipTest("numpy not available")
17
18
19 def _is_array_and_equal(test,ref):
20 if not type(test) == numpy.ndarray:
21 raise AssertionError
22 numpy.testing.assert_array_equal(test,ref)
23
24 # TODO: incomplete
25 class TestNumpy(API1TestCase):
26 def test_array_param(self):
27 class Z(param.Parameterized):
28 z = param.Array(default=numpy.array([1]))
29
30 _is_array_and_equal(Z.z,[1])
31
32 z = Z(z=numpy.array([1,2]))
33 _is_array_and_equal(z.z,[1,2])
34
35 def test_array_param_positional(self):
36 class Z(param.Parameterized):
37 z = param.Array(numpy.array([1]))
38
39 _is_array_and_equal(Z.z,[1])
40
41 z = Z(z=numpy.array([1,2]))
42 _is_array_and_equal(z.z,[1,2])
43
44 if __name__ == "__main__":
45 import nose
46 nose.runmodule()
+0
-120
tests/API1/testobjectselector.py less more
0 """
1 Unit test for object selector parameters.
2
3 Originally implemented as doctests in Topographica in the file
4 testEnumerationParameter.txt
5 """
6
7 import param
8 from . import API1TestCase
9 from collections import OrderedDict
10
11
12 opts=dict(A=[1,2],B=[3,4],C=dict(a=1,b=2))
13
14
15 class TestObjectSelectorParameters(API1TestCase):
16
17 def setUp(self):
18 super(TestObjectSelectorParameters, self).setUp()
19 class P(param.Parameterized):
20 e = param.ObjectSelector(default=5,objects=[5,6,7])
21 f = param.ObjectSelector(default=10)
22 h = param.ObjectSelector(default=None)
23 g = param.ObjectSelector(default=None,objects=[7,8])
24 i = param.ObjectSelector(default=7,objects=[9],check_on_set=False)
25 s = param.ObjectSelector(default=3,objects=OrderedDict(one=1,two=2,three=3))
26 d = param.ObjectSelector(default=opts['B'],objects=opts)
27
28 self.P = P
29
30 def test_set_object_constructor(self):
31 p = self.P(e=6)
32 self.assertEqual(p.e, 6)
33
34 def test_get_range_list(self):
35 r = self.P.param.params("g").get_range()
36 self.assertEqual(r['7'],7)
37 self.assertEqual(r['8'],8)
38
39 def test_get_range_dict(self):
40 r = self.P.param.params("s").get_range()
41 self.assertEqual(r['one'],1)
42 self.assertEqual(r['two'],2)
43
44 def test_get_range_mutable(self):
45 r = self.P.param.params("d").get_range()
46 self.assertEqual(r['A'],opts['A'])
47 self.assertEqual(r['C'],opts['C'])
48 self.d=opts['A']
49 self.d=opts['C']
50 self.d=opts['B']
51
52 def test_set_object_outside_bounds(self):
53 p = self.P(e=6)
54 try:
55 p.e = 9
56 except ValueError:
57 pass
58 else:
59 raise AssertionError("Object set outside range.")
60
61 def test_set_object_setattr(self):
62 p = self.P(e=6)
63 p.f = 9
64 self.assertEqual(p.f, 9)
65 p.g = 7
66 self.assertEqual(p.g, 7)
67 p.i = 12
68 self.assertEqual(p.i, 12)
69
70
71 def test_set_object_not_None(self):
72 p = self.P(e=6)
73 p.g = 7
74 try:
75 p.g = None
76 except ValueError:
77 pass
78 else:
79 raise AssertionError("Object set outside range.")
80
81 def test_set_object_setattr_post_error(self):
82 p = self.P(e=6)
83 p.f = 9
84 self.assertEqual(p.f, 9)
85 p.g = 7
86 try:
87 p.g = None
88 except ValueError:
89 pass
90 else:
91 raise AssertionError("Object set outside range.")
92
93 self.assertEqual(p.g, 7)
94 p.i = 12
95 self.assertEqual(p.i, 12)
96
97 def test_initialization_out_of_bounds(self):
98 try:
99 class Q(param.Parameterized):
100 q = param.ObjectSelector(5,objects=[4])
101 except ValueError:
102 pass
103 else:
104 raise AssertionError("ObjectSelector created outside range.")
105
106
107 def test_initialization_no_bounds(self):
108 try:
109 class Q(param.Parameterized):
110 q = param.ObjectSelector(5,objects=10)
111 except TypeError:
112 pass
113 else:
114 raise AssertionError("ObjectSelector created without range.")
115
116
117 if __name__ == "__main__":
118 import nose
119 nose.runmodule()
+0
-181
tests/API1/testpandas.py less more
0 """
1 Test Parameters based on pandas
2 """
3 import unittest
4 import os
5
6 import param
7 from . import API1TestCase
8
9 try:
10 import pandas
11 except ImportError:
12 if os.getenv('PARAM_TEST_PANDAS','0') == '1':
13 raise ImportError("PARAM_TEST_PANDAS=1 but pandas not available.")
14 else:
15 raise unittest.SkipTest("pandas not available")
16
17
18 class TestDataFrame(API1TestCase):
19
20 def test_dataframe_positional_argument(self):
21 valid_df = pandas.DataFrame({'a':[1,2], 'b':[2,3], 'c':[4,5]},
22 columns=['b', 'a', 'c'])
23 class Test(param.Parameterized):
24 df = param.DataFrame(valid_df)
25
26 def test_empty_dataframe_param_invalid_set(self):
27 empty = pandas.DataFrame()
28 class Test(param.Parameterized):
29 df = param.DataFrame(default=empty)
30
31 test = Test()
32 exception = "Parameter 'df' value must be an instance of DataFrame, not '3'"
33 with self.assertRaisesRegexp(ValueError, exception):
34 test.df = 3
35
36 def test_dataframe_unordered_column_set_valid(self):
37 valid_df = pandas.DataFrame({'a':[1,2], 'b':[2,3], 'c':[4,5]}, columns=['b', 'a', 'c'])
38 class Test(param.Parameterized):
39 df = param.DataFrame(default=valid_df, columns={'a', 'b'})
40
41
42 def test_dataframe_unordered_column_set_invalid(self):
43 valid_df = pandas.DataFrame({'a':[1,2], 'b':[2,3], 'd':[4,5]}, columns=['b', 'a', 'd'])
44 invalid_df = pandas.DataFrame({'a':[1,2], 'b':[2,3], 'c':[4,5]}, columns=['b', 'a', 'c'])
45
46 class Test(param.Parameterized):
47 df = param.DataFrame(default=valid_df, columns={'a', 'd'})
48
49
50 test = Test()
51 self.assertEquals(test.param.params('df').ordered, False)
52 exception = "Provided DataFrame columns \['b', 'a', 'c'\] does not contain required columns \['a', 'd'\]"
53 with self.assertRaisesRegexp(ValueError, exception):
54 test.df = invalid_df
55
56 def test_dataframe_ordered_column_list_valid(self):
57 valid_df = pandas.DataFrame({'a':[1,2], 'b':[2,3], 'c':[4,5]}, columns=['b', 'a', 'c'])
58 class Test(param.Parameterized):
59 test = param.DataFrame(default=valid_df, columns=['b', 'a', 'c'])
60
61
62 def test_dataframe_ordered_column_list_invalid(self):
63 valid_df = pandas.DataFrame({'a':[1,2], 'b':[2,3], 'd':[4,5]}, columns=['b', 'a', 'd'])
64 invalid_df = pandas.DataFrame({'a':[1,2], 'b':[2,3], 'c':[4,5]}, columns=['a', 'b', 'd'])
65
66 class Test(param.Parameterized):
67 df = param.DataFrame(default=valid_df, columns=['b', 'a', 'd'])
68
69 test = Test()
70 self.assertEquals(test.param.params('df').ordered, True)
71
72 exception = "Provided DataFrame columns \['a', 'b', 'd'\] must exactly match \['b', 'a', 'd'\]"
73 with self.assertRaisesRegexp(ValueError, exception):
74 test.df = invalid_df
75
76
77 def test_dataframe_unordered_column_number_valid_df(self):
78 valid_df = pandas.DataFrame({'a':[1,2], 'b':[2,3], 'c':[4,5]}, columns=['b', 'a', 'c'])
79 class Test(param.Parameterized):
80 df = param.DataFrame(default=valid_df, columns=3)
81
82 def test_dataframe_unordered_column_number_invalid(self):
83 valid_df = pandas.DataFrame({'a':[1,2], 'b':[2,3], 'c':[4,5]}, columns=['b', 'a', 'c'])
84 invalid_df = pandas.DataFrame({'a':[1,2], 'b':[2,3]}, columns=['b', 'a'])
85 class Test(param.Parameterized):
86 df = param.DataFrame(default=valid_df, columns=3)
87
88 test = Test()
89 self.assertEquals(test.param.params('df').ordered, None)
90
91 exception = "Column length 2 does not match declared bounds of 3"
92 with self.assertRaisesRegexp(ValueError, exception):
93 test.df = invalid_df
94
95
96 def test_dataframe_unordered_column_tuple_valid(self):
97 valid_df = pandas.DataFrame({'a':[1,2], 'b':[2,3], 'c':[4,5]}, columns=['b', 'a', 'c'])
98 class Test(param.Parameterized):
99 df = param.DataFrame(default=valid_df, columns=(None,3))
100
101 def test_dataframe_unordered_column_tuple_invalid(self):
102
103 invalid_df = pandas.DataFrame({'a':[1,2], 'b':[2,3], 'c':[4,5]}, columns=['b', 'a', 'c'])
104
105 exception = "Columns length 3 does not match declared bounds of \(None, 2\)"
106 with self.assertRaisesRegexp(ValueError, exception):
107 class Test(param.Parameterized):
108 df = param.DataFrame(default=invalid_df, columns=(None,2))
109
110 def test_dataframe_row_number_valid_df(self):
111 valid_df = pandas.DataFrame({'a':[1,2], 'b':[2,3], 'c':[4,5]}, columns=['b', 'a', 'c'])
112 class Test(param.Parameterized):
113 df = param.DataFrame(default=valid_df, rows=2)
114
115 def test_dataframe_row_number_invalid(self):
116 valid_df = pandas.DataFrame({'a':[1,2], 'b':[2,3]}, columns=['b', 'a'])
117 invalid_df = pandas.DataFrame({'a':[1,2,4], 'b':[2,3,4]}, columns=['b', 'a'])
118 class Test(param.Parameterized):
119 df = param.DataFrame(default=valid_df, rows=2)
120
121 test = Test()
122 exception = "Row length 3 does not match declared bounds of 2"
123 with self.assertRaisesRegexp(ValueError, exception):
124 test.df = invalid_df
125
126 def test_dataframe_unordered_row_tuple_valid(self):
127 valid_df = pandas.DataFrame({'a':[1,2], 'b':[2,3], 'c':[4,5]}, columns=['b', 'a', 'c'])
128 class Test(param.Parameterized):
129 df = param.DataFrame(default=valid_df, rows=(None,3))
130
131 def test_dataframe_unordered_row_tuple_invalid(self):
132
133 invalid_df = pandas.DataFrame({'a':[1,2], 'b':[2,3], 'c':[4,5]}, columns=['b', 'a', 'c'])
134
135 exception = "Row length 2 does not match declared bounds of \(5, 7\)"
136 with self.assertRaisesRegexp(ValueError, exception):
137 class Test(param.Parameterized):
138 df = param.DataFrame(default=invalid_df, rows=(5,7))
139
140
141 class TestSeries(API1TestCase):
142
143 def test_series_positional_argument(self):
144 valid_series = pandas.Series([1,2])
145 class Test(param.Parameterized):
146 series = param.Series(valid_series, rows=2)
147
148 def test_series_row_number_valid(self):
149 valid_series = pandas.Series([1,2])
150 class Test(param.Parameterized):
151 series = param.Series(default=valid_series, rows=2)
152
153 def test_series_row_number_invalid(self):
154 valid_series = pandas.Series([1,2])
155 invalid_series = pandas.Series([1,2,3])
156 class Test(param.Parameterized):
157 series = param.Series(default=valid_series, rows=2)
158
159 test = Test()
160 exception = "Row length 3 does not match declared bounds of 2"
161 with self.assertRaisesRegexp(ValueError, exception):
162 test.series = invalid_series
163
164 def test_series_unordered_row_tuple_valid(self):
165 valid_series = pandas.Series([1,2,3])
166 class Test(param.Parameterized):
167 series = param.Series(default=valid_series, rows=(None,3))
168
169 def test_series_unordered_row_tuple_invalid(self):
170
171 invalid_series = pandas.Series([1,2])
172
173 exception = "Row length 2 does not match declared bounds of \(5, 7\)"
174 with self.assertRaisesRegexp(ValueError, exception):
175 class Test(param.Parameterized):
176 series = param.Series(default=invalid_series, rows=(5,7))
177
178 if __name__ == "__main__":
179 import nose
180 nose.runmodule()
+0
-158
tests/API1/testparamdepends.py less more
0 """
1 Unit test for param.depends.
2 """
3
4
5 import param
6 from . import API1TestCase
7
8
9 class TestParamDepends(API1TestCase):
10
11 def setUp(self):
12 class P(param.Parameterized):
13 a = param.Parameter()
14 b = param.Parameter()
15
16 @param.depends('a')
17 def single_parameter(self):
18 pass
19
20 @param.depends('a:constant')
21 def constant(self):
22 pass
23
24 @param.depends('a.param')
25 def nested(self):
26 pass
27
28 class P2(param.Parameterized):
29
30 @param.depends(P.param.a)
31 def external_param(self, a):
32 pass
33
34 self.P = P
35 self.P2 = P2
36
37 def test_param_depends_instance(self):
38 p = self.P()
39 pinfos = p.param.params_depended_on('single_parameter')
40 self.assertEqual(len(pinfos), 1)
41 pinfo = pinfos[0]
42 self.assertIs(pinfo.cls, self.P)
43 self.assertIs(pinfo.inst, p)
44 self.assertEqual(pinfo.name, 'a')
45 self.assertEqual(pinfo.what, 'value')
46
47 def test_param_depends_class(self):
48 pinfos = self.P.param.params_depended_on('single_parameter')
49 self.assertEqual(len(pinfos), 1)
50 pinfo = pinfos[0]
51 self.assertIs(pinfo.cls, self.P)
52 self.assertIs(pinfo.inst, None)
53 self.assertEqual(pinfo.name, 'a')
54 self.assertEqual(pinfo.what, 'value')
55
56 def test_param_depends_constant(self):
57 pinfos = self.P.param.params_depended_on('constant')
58 self.assertEqual(len(pinfos), 1)
59 pinfo = pinfos[0]
60 self.assertIs(pinfo.cls, self.P)
61 self.assertIs(pinfo.inst, None)
62 self.assertEqual(pinfo.name, 'a')
63 self.assertEqual(pinfo.what, 'constant')
64
65 def test_param_depends_nested(self):
66 inst = self.P(a=self.P())
67 pinfos = inst.param.params_depended_on('nested')
68 self.assertEqual(len(pinfos), 4)
69 pinfos = {(pi.inst, pi.name): pi for pi in pinfos}
70 pinfo = pinfos[(inst, 'a')]
71 self.assertIs(pinfo.cls, self.P)
72 self.assertIs(pinfo.inst, inst)
73 self.assertEqual(pinfo.name, 'a')
74 self.assertEqual(pinfo.what, 'value')
75 for p in ['name', 'a', 'b']:
76 info = pinfos[(inst.a, p)]
77 self.assertEqual(info.name, p)
78 self.assertIs(info.inst, inst.a)
79
80 def test_param_external_param_instance(self):
81 inst = self.P2()
82 pinfos = inst.param.params_depended_on('external_param')
83 pinfo = pinfos[0]
84 self.assertIs(pinfo.cls, self.P)
85 self.assertIs(pinfo.inst, None)
86 self.assertEqual(pinfo.name, 'a')
87 self.assertEqual(pinfo.what, 'value')
88
89
90
91 class TestParamDependsFunction(API1TestCase):
92
93 def setUp(self):
94 class P(param.Parameterized):
95 a = param.Parameter()
96 b = param.Parameter()
97
98
99 self.P = P
100
101 def test_param_depends_function_instance_params(self):
102 p = self.P()
103
104 @param.depends(p.param.a, c=p.param.b)
105 def function(value, c):
106 pass
107
108 dependencies = {
109 'dependencies': (p.param.a,),
110 'kw': {'c': p.param.b},
111 'watch': False
112 }
113 self.assertEqual(function._dinfo, dependencies)
114
115 def test_param_depends_function_class_params(self):
116 p = self.P
117
118 @param.depends(p.param.a, c=p.param.b)
119 def function(value, c):
120 pass
121
122 dependencies = {
123 'dependencies': (p.param.a,),
124 'kw': {'c': p.param.b},
125 'watch': False
126 }
127 self.assertEqual(function._dinfo, dependencies)
128
129 def test_param_depends_function_instance_params_watch(self):
130 p = self.P(a=1, b=2)
131
132 d = []
133
134 @param.depends(p.param.a, c=p.param.b, watch=True)
135 def function(value, c):
136 d.append(value+c)
137
138 p.a = 2
139 self.assertEqual(d, [4])
140 p.b = 3
141 self.assertEqual(d, [4, 5])
142
143 def test_param_depends_function_class_params_watch(self):
144 p = self.P
145 p.a = 1
146 p.b = 2
147
148 d = []
149
150 @param.depends(p.param.a, c=p.param.b, watch=True)
151 def function(value, c):
152 d.append(value+c)
153
154 p.a = 2
155 self.assertEqual(d, [4])
156 p.b = 3
157 self.assertEqual(d, [4, 5])
+0
-500
tests/API1/testparameterizedobject.py less more
0 """
1 Unit test for Parameterized.
2 """
3
4 import param
5 import numbergen
6
7 from . import API1TestCase
8 from .utils import MockLoggingHandler
9
10 # CEBALERT: not anything like a complete test of Parameterized!
11
12
13 import random
14 from nose.tools import istest, nottest
15
16
17 from param.parameterized import ParamOverrides, shared_parameters
18 from param.parameterized import default_label_formatter, no_instance_params
19
20 @nottest
21 class _SomeRandomNumbers(object):
22 def __call__(self):
23 return random.random()
24
25 @nottest
26 class TestPO(param.Parameterized):
27 inst = param.Parameter(default=[1,2,3],instantiate=True)
28 notinst = param.Parameter(default=[1,2,3],instantiate=False, per_instance=False)
29 const = param.Parameter(default=1,constant=True)
30 ro = param.Parameter(default="Hello",readonly=True)
31 ro2 = param.Parameter(default=object(),readonly=True,instantiate=True)
32 ro_label = param.Parameter(default=object(), label='Ro Label')
33 ro_format = param.Parameter(default=object())
34
35 dyn = param.Dynamic(default=1)
36
37 @nottest
38 class TestPOValidation(param.Parameterized):
39 value = param.Number(default=2, bounds=(0, 4))
40
41 @nottest
42 @no_instance_params
43 class TestPONoInstance(TestPO):
44 pass
45
46 @nottest
47 class AnotherTestPO(param.Parameterized):
48 instPO = param.Parameter(default=TestPO(),instantiate=True)
49 notinstPO = param.Parameter(default=TestPO(),instantiate=False)
50
51 @nottest
52 class TestAbstractPO(param.Parameterized):
53 __abstract = True
54
55 @nottest
56 class TestParamInstantiation(AnotherTestPO):
57 instPO = param.Parameter(default=AnotherTestPO(),instantiate=False)
58
59 @istest
60 class TestParameterized(API1TestCase):
61
62 @classmethod
63 def setUpClass(cls):
64 super(TestParameterized, cls).setUpClass()
65 log = param.parameterized.get_logger()
66 cls.log_handler = MockLoggingHandler(level='DEBUG')
67 log.addHandler(cls.log_handler)
68
69
70 def test_constant_parameter(self):
71 """Test that you can't set a constant parameter after construction."""
72 testpo = TestPO(const=17)
73 self.assertEqual(testpo.const,17)
74 self.assertRaises(TypeError,setattr,testpo,'const',10)
75
76 # check you can set on class
77 TestPO.const=9
78 testpo = TestPO()
79 self.assertEqual(testpo.const,9)
80
81
82 def test_readonly_parameter(self):
83 """Test that you can't set a read-only parameter on construction or as an attribute."""
84 testpo = TestPO()
85 self.assertEqual(testpo.ro,"Hello")
86
87 with self.assertRaises(TypeError):
88 t = TestPO(ro=20)
89
90 t=TestPO()
91 self.assertRaises(TypeError,setattr,t,'ro',10)
92
93 # check you cannot set on class
94 self.assertRaises(TypeError,setattr,TestPO,'ro',5)
95
96 self.assertEqual(testpo.param.params()['ro'].constant,True)
97
98 # check that instantiate was ignored for readonly
99 self.assertEqual(testpo.param.params()['ro2'].instantiate,False)
100
101
102 def test_basic_instantiation(self):
103 """Check that instantiated parameters are copied into objects."""
104
105 testpo = TestPO()
106
107 self.assertEqual(testpo.inst,TestPO.inst)
108 self.assertEqual(testpo.notinst,TestPO.notinst)
109
110 TestPO.inst[1]=7
111 TestPO.notinst[1]=7
112
113 self.assertEqual(testpo.notinst,[1,7,3])
114 self.assertEqual(testpo.inst,[1,2,3])
115
116
117 def test_more_instantiation(self):
118 """Show that objects in instantiated Parameters can still share data."""
119 anothertestpo = AnotherTestPO()
120
121 ### CB: AnotherTestPO.instPO is instantiated, but
122 ### TestPO.notinst is not instantiated - so notinst is still
123 ### shared, even by instantiated parameters of AnotherTestPO.
124 ### Seems like this behavior of Parameterized could be
125 ### confusing, so maybe mention it in documentation somewhere.
126 TestPO.notinst[1]=7
127 # (if you thought your instPO was completely an independent object, you
128 # might be expecting [1,2,3] here)
129 self.assertEqual(anothertestpo.instPO.notinst,[1,7,3])
130
131
132 def test_instantiation_inheritance(self):
133 """Check that instantiate=True is always inherited (SF.net #2483932)."""
134 t = TestParamInstantiation()
135 assert t.param.params('instPO').instantiate is True
136 assert isinstance(t.instPO,AnotherTestPO)
137
138
139 def test_abstract_class(self):
140 """Check that a class declared abstract actually shows up as abstract."""
141 self.assertEqual(TestAbstractPO.abstract,True)
142 self.assertEqual(TestPO.abstract,False)
143
144
145 def test_override_class_param_validation(self):
146 test = TestPOValidation()
147 test.param.value.bounds = (0, 3)
148 with self.assertRaises(ValueError):
149 test.value = 4
150 TestPOValidation.value = 4
151
152
153 def test_remove_class_param_validation(self):
154 test = TestPOValidation()
155 test.param.value.bounds = None
156 test.value = 20
157 with self.assertRaises(ValueError):
158 TestPOValidation.value = 10
159
160
161 def test_params(self):
162 """Basic tests of params() method."""
163
164 # CB: test not so good because it requires changes if params
165 # of PO are changed
166 assert 'name' in param.Parameterized.param.params()
167 assert len(param.Parameterized.param.params()) in [1,2]
168
169 ## check for bug where subclass Parameters were not showing up
170 ## if params() already called on a super class.
171 assert 'inst' in TestPO.param.params()
172 assert 'notinst' in TestPO.param.params()
173
174 ## check caching
175 assert param.Parameterized.param.params() is param.Parameterized().param.params(), "Results of params() should be cached." # just for performance reasons
176
177
178 def test_param_iterator(self):
179 self.assertEqual(set(TestPO.param), {'name', 'inst', 'notinst', 'const', 'dyn',
180 'ro', 'ro2', 'ro_label', 'ro_format'})
181
182
183 def test_param_contains(self):
184 for p in ['name', 'inst', 'notinst', 'const', 'dyn', 'ro', 'ro2']:
185 self.assertIn(p, TestPO.param)
186
187
188 def test_class_param_objects(self):
189 objects = TestPO.param.objects()
190
191 self.assertEqual(set(objects),
192 {'name', 'inst', 'notinst', 'const', 'dyn',
193 'ro', 'ro2', 'ro_label', 'ro_format'})
194
195 # Check caching
196 assert TestPO.param.objects() is objects
197
198
199 def test_instance_param_objects(self):
200 inst = TestPO()
201 objects = inst.param.objects()
202
203 for p, obj in objects.items():
204 if p == 'notinst':
205 assert obj is TestPO.param[p]
206 else:
207 assert obj is not TestPO.param[p]
208
209
210 def test_instance_param_objects_set_to_false(self):
211 inst = TestPO()
212 objects = inst.param.objects(instance=False)
213
214 for p, obj in objects.items():
215 assert obj is TestPO.param[p]
216
217
218 def test_instance_param_objects_set_to_current(self):
219 inst = TestPO()
220 inst_param = inst.param.inst
221 objects = inst.param.objects(instance='existing')
222
223 for p, obj in objects.items():
224 if p == 'inst':
225 assert obj is inst_param
226 else:
227 assert obj is TestPO.param[p]
228
229
230 def test_instance_param_objects_warn_on_params(self):
231 inst = TestPO()
232 inst.param['inst']
233
234 inst.param.params()
235 self.log_handler.assertContains(
236 'WARNING', 'The Parameterized instance has instance parameters')
237
238
239 def test_instance_param_getitem(self):
240 test = TestPO()
241 assert test.param['inst'] is not TestPO.param['inst']
242
243
244 def test_instance_param_getitem_not_per_instance(self):
245 test = TestPO()
246 assert test.param['notinst'] is TestPO.param['notinst']
247
248
249 def test_instance_param_getitem_no_instance_params(self):
250 test = TestPONoInstance()
251 assert test.param['inst'] is TestPO.param['inst']
252
253
254 def test_instance_param_getattr(self):
255 test = TestPO()
256 assert test.param.inst is not TestPO.param.inst
257
258 # Assert no deep copy
259 assert test.param.inst.default is TestPO.param.inst.default
260
261
262 def test_pprint_instance_params(self):
263 # Ensure pprint does not make instance parameter copies
264 test = TestPO()
265 test.pprint()
266 for p, obj in TestPO.param.objects('current').items():
267 assert obj is TestPO.param[p]
268
269
270 def test_set_param_instance_params(self):
271 # Ensure set_param does not make instance parameter copies
272 test = TestPO()
273 test.param.set_param(inst=3)
274 for p, obj in TestPO.param.objects('current').items():
275 assert obj is TestPO.param[p]
276
277
278 def test_get_param_values_instance_params(self):
279 # Ensure get_param_values does not make instance parameter copies
280 test = TestPO()
281 test.param.get_param_values()
282 for p, obj in TestPO.param.objects('current').items():
283 assert obj is TestPO.param[p]
284
285
286 def test_defaults_instance_params(self):
287 # Ensure get_param_values does not make instance parameter copies
288 test = TestPO()
289 test.param.defaults()
290 for p, obj in TestPO.param.objects('current').items():
291 assert obj is TestPO.param[p]
292
293
294 def test_state_saving(self):
295 t = TestPO(dyn=_SomeRandomNumbers())
296 g = t.param.get_value_generator('dyn')
297 g._Dynamic_time_fn=None
298 assert t.dyn!=t.dyn
299 orig = t.dyn
300 t.state_push()
301 t.dyn
302 assert t.param.inspect_value('dyn')!=orig
303 t.state_pop()
304 assert t.param.inspect_value('dyn')==orig
305
306
307 def test_label(self):
308 t = TestPO()
309 assert t.param.params('ro_label').label == 'Ro Label'
310
311 def test_label_set(self):
312 t = TestPO()
313 assert t.param.params('ro_label').label == 'Ro Label'
314 t.param.params('ro_label').label = 'Ro relabeled'
315 assert t.param.params('ro_label').label == 'Ro relabeled'
316
317 def test_label_default_format(self):
318 t = TestPO()
319 assert t.param.params('ro_format').label == 'Ro format'
320
321
322 def test_label_custom_format(self):
323 param.parameterized.label_formatter = default_label_formatter.instance(capitalize=False)
324 t = TestPO()
325 assert t.param.params('ro_format').label == 'ro format'
326 param.parameterized.label_formatter = default_label_formatter
327
328 def test_label_constant_format(self):
329 param.parameterized.label_formatter = lambda x: 'Foo'
330 t = TestPO()
331 assert t.param.params('ro_format').label == 'Foo'
332 param.parameterized.label_formatter = default_label_formatter
333
334
335 from param import parameterized
336
337 @nottest
338 class some_fn(param.ParameterizedFunction):
339 num_phase = param.Number(18)
340 frequencies = param.List([99])
341 scale = param.Number(0.3)
342
343 def __call__(self,**params_to_override):
344 params = parameterized.ParamOverrides(self,params_to_override)
345 num_phase = params['num_phase']
346 frequencies = params['frequencies']
347 scale = params['scale']
348 return scale,num_phase,frequencies
349
350 instance = some_fn.instance()
351
352 @istest
353 class TestParameterizedFunction(API1TestCase):
354
355 def _basic_tests(self,fn):
356 self.assertEqual(fn(),(0.3,18,[99]))
357 self.assertEqual(fn(frequencies=[1,2,3]),(0.3,18,[1,2,3]))
358 self.assertEqual(fn(),(0.3,18,[99]))
359
360 fn.frequencies=[10,20,30]
361 self.assertEqual(fn(frequencies=[1,2,3]),(0.3,18,[1,2,3]))
362 self.assertEqual(fn(),(0.3,18,[10,20,30]))
363
364 def test_parameterized_function(self):
365 self._basic_tests(some_fn)
366
367 def test_parameterized_function_instance(self):
368 self._basic_tests(instance)
369
370 def test_pickle_instance(self):
371 import pickle
372 s = pickle.dumps(instance)
373 instance.scale=0.8
374 i = pickle.loads(s)
375 self.assertEqual(i(),(0.3,18,[10,20,30]))
376
377
378 @nottest
379 class TestPO1(param.Parameterized):
380 x = param.Number(default=numbergen.UniformRandom(lbound=-1,ubound=1,seed=1),bounds=(-1,1))
381 y = param.Number(default=1,bounds=(-1,1))
382
383 @istest
384 class TestNumberParameter(API1TestCase):
385
386 def test_outside_bounds(self):
387 t1 = TestPO1()
388 # Test bounds (non-dynamic number)
389 try:
390 t1.y = 10
391 except ValueError:
392 pass
393 else:
394 assert False, "Should raise ValueError."
395
396 def test_outside_bounds_numbergen(self):
397 t1 = TestPO1()
398 # Test bounds (dynamic number)
399 t1.x = numbergen.UniformRandom(lbound=2,ubound=3) # bounds not checked on set
400 try:
401 t1.x
402 except ValueError:
403 pass
404 else:
405 assert False, "Should raise ValueError."
406
407
408 @istest
409 class TestStringParameter(API1TestCase):
410
411 def setUp(self):
412 super(TestStringParameter, self).setUp()
413
414 class TestString(param.Parameterized):
415 a = param.String()
416 b = param.String(default='',allow_None=True)
417 c = param.String(default=None)
418
419 self._TestString = TestString
420
421 def test_handling_of_None(self):
422 t = self._TestString()
423
424 with self.assertRaises(ValueError):
425 t.a = None
426
427 t.b = None
428
429 assert t.c is None
430
431
432 @istest
433 class TestParameterizedUtilities(API1TestCase):
434
435 def setUp(self):
436 super(TestParameterizedUtilities, self).setUp()
437
438
439 def test_default_label_formatter(self):
440 assert default_label_formatter('a_b_C') == 'A b C'
441
442
443 def test_default_label_formatter_not_capitalized(self):
444 assert default_label_formatter.instance(capitalize=False)('a_b_C') == 'a b C'
445
446
447 def test_default_label_formatter_not_replace_underscores(self):
448 assert default_label_formatter.instance(replace_underscores=False)('a_b_C') == 'A_b_C'
449 def test_default_label_formatter_overrides(self):
450 assert default_label_formatter.instance(overrides={'a': 'b'})('a') == 'b'
451
452 @istest
453 class TestParamOverrides(API1TestCase):
454
455 def setUp(self):
456 super(TestParamOverrides, self).setUp()
457 self.po = param.Parameterized(name='A',print_level=0)
458
459 def test_init_name(self):
460 self.assertEqual(self.po.name, 'A')
461
462 def test_simple_override(self):
463 overrides = ParamOverrides(self.po,{'name':'B'})
464 self.assertEqual(overrides['name'], 'B')
465 self.assertEqual(overrides['print_level'], 0)
466
467 # CEBALERT: missing test for allow_extra_keywords (e.g. getting a
468 # warning on attempting to override non-existent parameter when
469 # allow_extra_keywords is False)
470
471 def test_missing_key(self):
472 overrides = ParamOverrides(self.po,{'name':'B'})
473 with self.assertRaises(AttributeError):
474 overrides['doesnotexist']
475
476
477 class TestSharedParameters(API1TestCase):
478
479 def setUp(self):
480 super(TestSharedParameters, self).setUp()
481 with shared_parameters():
482 self.p1 = TestPO(name='A', print_level=0)
483 self.p2 = TestPO(name='B', print_level=0)
484 self.ap1 = AnotherTestPO(name='A', print_level=0)
485 self.ap2 = AnotherTestPO(name='B', print_level=0)
486
487 def test_shared_object(self):
488 self.assertTrue(self.ap1.instPO is self.ap2.instPO)
489 self.assertTrue(self.ap1.param.params('instPO').default is not self.ap2.instPO)
490
491 def test_shared_list(self):
492 self.assertTrue(self.p1.inst is self.p2.inst)
493 self.assertTrue(self.p1.param.params('inst').default is not self.p2.inst)
494
495
496
497 if __name__ == "__main__":
498 import nose
499 nose.runmodule()
+0
-167
tests/API1/testparameterizedrepr.py less more
0 """
1 Unit test for the repr and pprint of parameterized objects.
2 """
3
4 import param
5 from . import API1TestCase
6
7
8 class TestParameterizedRepr(API1TestCase):
9
10 def setUp(self):
11 super(TestParameterizedRepr, self).setUp()
12 # initialize a parameterized class
13 class A(param.Parameterized):
14 a = param.Number(4, precedence=-5)
15 b = param.String('B', precedence=-4)
16 c = param.Number(4, precedence=0)
17 d = param.Integer(-22, precedence=1)
18
19 x = param.Number(1, precedence=2)
20 y = param.Number(2, precedence=-1)
21 z = param.Number(3, precedence=-2)
22 def __init__(self, a, b, c=4, d=-22, **kwargs):
23 super(A, self).__init__(a=a, b=b, c=c, **kwargs)
24
25 self.A = A
26
27 class B(param.Parameterized): # Similar to A but no **kwargs
28 a = param.Number(4, precedence=-5)
29 b = param.String('B', precedence=-4)
30 c = param.Number(4, precedence=0)
31 d = param.Integer(-22, precedence=1)
32
33 x = param.Number(1, precedence=2)
34 def __init__(self, a, b, c=4, d=-22):
35 super(B, self).__init__(a=a, b=b, c=c, name='ClassB')
36
37 self.B = B
38
39 class C(param.Parameterized): # Similar to A but with *varargs
40 a = param.Number(4, precedence=-5)
41 b = param.String('B', precedence=-4)
42 c = param.Number(4, precedence=0)
43 d = param.Integer(-22, precedence=1)
44
45 x = param.Number(1, precedence=2)
46 y = param.Number(2, precedence=-1)
47 z = param.Number(3, precedence=-2)
48
49 def __init__(self, a, b, c=4, d=-22, *varargs, **kwargs):
50 super(C, self).__init__(a=a, b=b, c=c, **kwargs)
51
52 self.C = C
53
54
55 class D(param.Parameterized): # Similar to A but with missing parameters
56 a = param.Number(4, precedence=-5)
57 b = param.String('B', precedence=-4)
58
59 def __init__(self, a, b, c=4, d=-22, **kwargs):
60 super(D, self).__init__(a=a, b=b, **kwargs)
61
62 self.D = D
63
64
65 # More realistically, positional args are not params
66 class E(param.Parameterized):
67 a = param.Number(4, precedence=-5)
68
69 def __init__(self, p, q=4, **params): # (plus non-param kw too)
70 super(E, self).__init__(**params)
71
72 self.E = E
73
74
75 def testparameterizedrepr(self):
76 obj = self.A(4,'B', name='test1')
77 self.assertEqual(repr(obj),
78 "A(a=4, b='B', c=4, d=-22, name='test1', x=1, y=2, z=3)")
79
80 def testparameterizedscriptrepr1(self):
81 obj = self.A(4,'B', name='test')
82 self.assertEqual(obj.pprint(),
83 "A(4, 'B', name='test')")
84
85 def testparameterizedscriptrepr2(self):
86 obj = self.A(4,'B', c=5, name='test')
87 self.assertEqual(obj.pprint(),
88 "A(4, 'B', c=5, name='test')")
89
90 def testparameterizedscriptrepr3(self):
91 obj = self.A(4,'B', c=5, x=True, name='test')
92 self.assertEqual(obj.pprint(),
93 "A(4, 'B', c=5, name='test')")
94
95 def testparameterizedscriptrepr4(self):
96 obj = self.A(4,'B', c=5, x=10, name='test')
97 self.assertEqual(obj.pprint(),
98 "A(4, 'B', c=5, name='test', x=10)")
99
100
101 def testparameterizedscriptrepr5(self):
102 obj = self.A(4,'B', x=10, y=11, z=12, name='test')
103 self.assertEqual(obj.pprint(),
104 "A(4, 'B', name='test', z=12, y=11, x=10)")
105
106 def testparameterizedscriptrepr_nokwargs(self):
107 obj = self.B(4,'B', c=99)
108 obj.x = 10 # Modified but not passable through constructor
109 self.assertEqual(obj.pprint(),
110 "B(4, 'B', c=99)")
111
112 def testparameterizedscriptrepr_varags(self):
113 obj = self.C(4,'C', c=99)
114 self.assertEqual(obj.pprint(),
115 "C(4, 'C', c=99, **varargs)")
116
117 def testparameterizedscriptrepr_varags_kwargs(self):
118 obj = self.C(4,'C', c=99, x=10, y=11, z=12)
119 self.assertEqual(obj.pprint(),
120 "C(4, 'C', c=99, z=12, y=11, x=10, **varargs)")
121
122 def testparameterizedscriptrepr_missing_values(self):
123 obj = self.D(4,'D', c=99)
124 self.assertEqual(obj.pprint(),
125 "D(4, 'D', c=<?>, d=<?>)")
126
127 def testparameterizedscriptrepr_nonparams(self):
128 obj = self.E(10,q='hi', a=99)
129 self.assertEqual(obj.pprint(),
130 "E(<?>, q=<?>, a=99)")
131
132 def test_exceptions(self):
133 obj = self.E(10,q='hi',a=99)
134 try:
135 obj.pprint(unknown_value=False)
136 except Exception:
137 pass
138 else:
139 raise AssertionError
140
141 def test_suppression(self):
142 obj = self.E(10,q='hi',a=99)
143 self.assertEqual(obj.pprint(unknown_value=None),
144 "E(a=99)")
145
146 def test_imports_deduplication(self):
147 obj = self.E(10,q='hi', a=99)
148 imports = ['import me','import me']
149 obj.pprint(imports=imports)
150 self.assertEqual(imports.count('import me'),1)
151
152 def test_qualify(self):
153 obj = self.E(10,q='hi', a=99)
154
155 r = "E(<?>, q=<?>, a=99)"
156 self.assertEqual(obj.pprint(qualify=False),
157 r)
158
159 self.assertEqual(obj.pprint(qualify=True),
160 "tests.API1.testparameterizedrepr."+r)
161
162
163
164 if __name__ == "__main__":
165 import nose
166 nose.runmodule()
+0
-232
tests/API1/testparamoutput.py less more
0 """
1 Unit test for param.output.
2 """
3 import sys
4
5 from unittest import SkipTest
6
7 import param
8
9 from . import API1TestCase
10
11
12 class TestParamDepends(API1TestCase):
13
14 def test_simple_output(self):
15 class P(param.Parameterized):
16
17 @param.output()
18 def single_output(self):
19 return 1
20
21 p = P()
22 outputs = p.param.outputs()
23 self.assertEqual(list(outputs), ['single_output'])
24
25 otype, method, idx = outputs['single_output']
26 self.assertIs(type(otype), param.Parameter)
27 self.assertEqual(method, p.single_output)
28 self.assertEqual(idx, None)
29
30 def test_subclass_output(self):
31 class A(param.Parameterized):
32
33 @param.output()
34 def single_output(self):
35 return 1
36
37 class B(param.Parameterized):
38
39 @param.output()
40 def another_output(self):
41 return 2
42
43 class C(A, B):
44 pass
45
46 p = C()
47 outputs = p.param.outputs()
48 self.assertEqual(sorted(outputs), ['another_output', 'single_output'])
49
50 otype, method, idx = outputs['single_output']
51 self.assertIs(type(otype), param.Parameter)
52 self.assertEqual(method, p.single_output)
53 self.assertEqual(idx, None)
54
55 otype, method, idx = outputs['another_output']
56 self.assertIs(type(otype), param.Parameter)
57 self.assertEqual(method, p.another_output)
58 self.assertEqual(idx, None)
59
60
61 def test_named_kwarg_output(self):
62 class P(param.Parameterized):
63
64 @param.output(value=param.Integer)
65 def single_output(self):
66 return 1
67
68 p = P()
69 outputs = p.param.outputs()
70 self.assertEqual(list(outputs), ['value'])
71
72 otype, method, idx = outputs['value']
73 self.assertIs(type(otype), param.Integer)
74 self.assertEqual(method, p.single_output)
75 self.assertEqual(idx, None)
76
77 def test_named_and_typed_arg_output(self):
78 class P(param.Parameterized):
79
80 @param.output(('value', param.Integer))
81 def single_output(self):
82 return 1
83
84 p = P()
85 outputs = p.param.outputs()
86 self.assertEqual(list(outputs), ['value'])
87
88 otype, method, idx = outputs['value']
89 self.assertIs(type(otype), param.Integer)
90 self.assertEqual(method, p.single_output)
91 self.assertEqual(idx, None)
92
93 def test_named_arg_output(self):
94 class P(param.Parameterized):
95
96 @param.output('value')
97 def single_output(self):
98 return 1
99
100 p = P()
101 outputs = p.param.outputs()
102 self.assertEqual(list(outputs), ['value'])
103
104 otype, method, idx = outputs['value']
105 self.assertIs(type(otype), param.Parameter)
106 self.assertEqual(method, p.single_output)
107 self.assertEqual(idx, None)
108
109 def test_typed_arg_output(self):
110 class P(param.Parameterized):
111
112 @param.output(int)
113 def single_output(self):
114 return 1
115
116 p = P()
117 outputs = p.param.outputs()
118 self.assertEqual(list(outputs), ['single_output'])
119
120 otype, method, idx = outputs['single_output']
121 self.assertIs(type(otype), param.ClassSelector)
122 self.assertIs(otype.class_, int)
123 self.assertEqual(method, p.single_output)
124 self.assertEqual(idx, None)
125
126 def test_multiple_named_kwarg_output(self):
127 py_major = sys.version_info.major
128 py_minor = sys.version_info.minor
129 if (py_major < 3 or (py_major == 3 and py_minor < 6)):
130 raise SkipTest('Multiple keyword output declarations only '
131 'supported in Python >= 3.6, skipping test.')
132
133 class P(param.Parameterized):
134
135 @param.output(value=param.Integer, value2=param.String)
136 def multi_output(self):
137 return (1, 'string')
138
139 p = P()
140 outputs = p.param.outputs()
141 self.assertEqual(set(outputs), {'value', 'value2'})
142
143 otype, method, idx = outputs['value']
144 self.assertIs(type(otype), param.Integer)
145 self.assertEqual(method, p.multi_output)
146 self.assertEqual(idx, 0)
147
148 otype, method, idx = outputs['value2']
149 self.assertIs(type(otype), param.String)
150 self.assertEqual(method, p.multi_output)
151 self.assertEqual(idx, 1)
152
153 def test_multi_named_and_typed_arg_output(self):
154 class P(param.Parameterized):
155
156 @param.output(('value', param.Integer), ('value2', param.String))
157 def multi_output(self):
158 return (1, 'string')
159
160 p = P()
161 outputs = p.param.outputs()
162 self.assertEqual(set(outputs), {'value', 'value2'})
163 otype, method, idx = outputs['value']
164 self.assertIs(type(otype), param.Integer)
165 self.assertEqual(method, p.multi_output)
166 self.assertEqual(idx, 0)
167
168 otype, method, idx = outputs['value2']
169 self.assertIs(type(otype), param.String)
170 self.assertEqual(method, p.multi_output)
171 self.assertEqual(idx, 1)
172
173 def test_multi_named_arg_output(self):
174 class P(param.Parameterized):
175
176 @param.output('value', 'value2')
177 def multi_output(self):
178 return (1, 2)
179
180 p = P()
181 outputs = p.param.outputs()
182 self.assertEqual(set(outputs), {'value', 'value2'})
183
184 otype, method, idx = outputs['value']
185 self.assertIs(type(otype), param.Parameter)
186 self.assertEqual(method, p.multi_output)
187 self.assertEqual(idx, 0)
188
189 otype, method, idx = outputs['value2']
190 self.assertIs(type(otype), param.Parameter)
191 self.assertEqual(method, p.multi_output)
192 self.assertEqual(idx, 1)
193
194 def test_multi_typed_arg_output(self):
195 with self.assertRaises(ValueError):
196 class P(param.Parameterized):
197
198 @param.output(int, str)
199 def single_output(self):
200 return 1
201
202 def test_multi_method_named_and_typed_arg_output(self):
203 class P(param.Parameterized):
204
205 @param.output(('value', param.Integer), ('value2', str))
206 def multi_output(self):
207 return (1, 'string')
208
209 @param.output(('value3', param.Number))
210 def single_output(self):
211 return 3.0
212
213 p = P()
214 outputs = p.param.outputs()
215 self.assertEqual(set(outputs), {'value', 'value2', 'value3'})
216
217 otype, method, idx = outputs['value']
218 self.assertIs(type(otype), param.Integer)
219 self.assertEqual(method, p.multi_output)
220 self.assertEqual(idx, 0)
221
222 otype, method, idx = outputs['value2']
223 self.assertIs(type(otype), param.ClassSelector)
224 self.assertIs(otype.class_, str)
225 self.assertEqual(method, p.multi_output)
226 self.assertEqual(idx, 1)
227
228 otype, method, idx = outputs['value3']
229 self.assertIs(type(otype), param.Number)
230 self.assertEqual(method, p.single_output)
231 self.assertEqual(idx, None)
+0
-64
tests/API1/testparamunion.py less more
0 """
1 UnitTest for param_union helper
2 """
3
4 import logging
5 import param
6 from . import API1TestCase
7
8 class MyHandler(logging.StreamHandler):
9
10 def __init__(self):
11 super(MyHandler, self).__init__()
12 self.records = []
13
14 def emit(self, record):
15 self.records.append(record)
16
17 class TestParamUnion(API1TestCase):
18
19 def setUp(self):
20 self.logger = param.get_logger()
21 self.handler = MyHandler()
22 self.logger.addHandler(self.handler)
23
24 def tearDown(self):
25 self.logger.removeHandler(self.handler)
26
27 def test_param_union_values(self):
28 class A(param.Parameterized):
29 a = param.Number(1)
30 class B(param.Parameterized):
31 b = param.Number(2)
32 class C(A, B):
33 pass
34 a = A()
35 a.a = 10
36 b = B()
37 b.b = 5
38 c_1 = C(**param.param_union(a))
39 self.assertTrue(c_1.a == 10 and c_1.b == 2)
40 c_2 = C(**param.param_union(b))
41 self.assertTrue(c_2.a == 1 and c_2.b == 5)
42 c_3 = C(**param.param_union(a, b))
43 self.assertTrue(c_3.a == 10 and c_3.b == 5)
44 c_4 = C(**param.param_union())
45 self.assertTrue(c_4.a == 1 and c_4.b == 2)
46
47 def test_param_union_warnings(self):
48 class A(param.Parameterized):
49 a = param.Number(1)
50 a = A()
51 A(**param.param_union(a))
52 self.assertFalse(self.handler.records)
53 A(**param.param_union())
54 self.assertFalse(self.handler.records)
55 A(**param.param_union(a, a))
56 self.assertTrue(self.handler.records)
57 self.handler.records.pop()
58 A(**param.param_union(a, a, warn=False))
59 self.assertFalse(self.handler.records)
60
61 def test_param_union_raises_on_unexpected_kwarg(self):
62 with self.assertRaises(TypeError):
63 param.param_union(dumbdumbface=True)
+0
-52
tests/API1/testrangeparameter.py less more
0 """
1 Unit test for Range parameters.
2 """
3 import param
4 from . import API1TestCase
5
6
7 class TestRangeParameters(API1TestCase):
8
9 def test_initialization_out_of_bounds(self):
10 try:
11 class Q(param.Parameterized):
12 q = param.Range((0, 2), bounds=(0, 1))
13 except ValueError:
14 pass
15 else:
16 raise AssertionError("No exception raised on out-of-bounds date")
17
18 def test_set_exclusive_out_of_bounds_upper(self):
19 class Q(param.Parameterized):
20 q = param.Range(bounds=(0, 10), inclusive_bounds=(True, False))
21 try:
22 Q.q = (0, 10)
23 except ValueError:
24 pass
25 else:
26 raise AssertionError("No exception raised on out-of-bounds date")
27
28 def test_set_exclusive_out_of_bounds_lower(self):
29 class Q(param.Parameterized):
30 q = param.Range(bounds=(0, 10), inclusive_bounds=(False, True))
31 try:
32 Q.q = (0, 10)
33 except ValueError:
34 pass
35 else:
36 raise AssertionError("No exception raised on out-of-bounds date")
37
38 def test_set_out_of_bounds(self):
39 class Q(param.Parameterized):
40 q = param.Range(bounds=(0, 10))
41 try:
42 Q.q = (5, 11)
43 except ValueError:
44 pass
45 else:
46 raise AssertionError("No exception raised on out-of-bounds date")
47
48 def test_get_soft_bounds(self):
49 q = param.Range((1,3), bounds=(0, 10), softbounds=(1, 9))
50 self.assertEqual(q.get_soft_bounds(), (1, 9))
51
+0
-120
tests/API1/testselector.py less more
0 """
1 Unit test for object selector parameters.
2
3 Originally implemented as doctests in Topographica in the file
4 testEnumerationParameter.txt
5 """
6
7 import param
8 from . import API1TestCase
9 from collections import OrderedDict
10
11
12 opts=dict(A=[1,2],B=[3,4],C=dict(a=1,b=2))
13
14
15 class TestSelectorParameters(API1TestCase):
16
17 def setUp(self):
18 super(TestSelectorParameters, self).setUp()
19 class P(param.Parameterized):
20 e = param.Selector([5,6,7])
21 f = param.Selector(default=10)
22 h = param.Selector(default=None)
23 g = param.Selector([7,8])
24 i = param.Selector([9],default=7, check_on_set=False)
25 s = param.Selector(OrderedDict(one=1,two=2,three=3), default=3)
26 d = param.Selector(opts, default=opts['B'])
27
28 self.P = P
29
30 def test_set_object_constructor(self):
31 p = self.P(e=6)
32 self.assertEqual(p.e, 6)
33
34 def test_get_range_list(self):
35 r = self.P.param.params("g").get_range()
36 self.assertEqual(r['7'],7)
37 self.assertEqual(r['8'],8)
38
39 def test_get_range_dict(self):
40 r = self.P.param.params("s").get_range()
41 self.assertEqual(r['one'],1)
42 self.assertEqual(r['two'],2)
43
44 def test_get_range_mutable(self):
45 r = self.P.param.params("d").get_range()
46 self.assertEqual(r['A'],opts['A'])
47 self.assertEqual(r['C'],opts['C'])
48 self.d=opts['A']
49 self.d=opts['C']
50 self.d=opts['B']
51
52 def test_set_object_outside_bounds(self):
53 p = self.P(e=6)
54 try:
55 p.e = 9
56 except ValueError:
57 pass
58 else:
59 raise AssertionError("Object set outside range.")
60
61 def test_set_object_setattr(self):
62 p = self.P(e=6)
63 p.f = 9
64 self.assertEqual(p.f, 9)
65 p.g = 7
66 self.assertEqual(p.g, 7)
67 p.i = 12
68 self.assertEqual(p.i, 12)
69
70
71 def test_set_object_not_None(self):
72 p = self.P(e=6)
73 p.g = 7
74 try:
75 p.g = None
76 except ValueError:
77 pass
78 else:
79 raise AssertionError("Object set outside range.")
80
81 def test_set_object_setattr_post_error(self):
82 p = self.P(e=6)
83 p.f = 9
84 self.assertEqual(p.f, 9)
85 p.g = 7
86 try:
87 p.g = None
88 except ValueError:
89 pass
90 else:
91 raise AssertionError("Object set outside range.")
92
93 self.assertEqual(p.g, 7)
94 p.i = 12
95 self.assertEqual(p.i, 12)
96
97 def test_initialization_out_of_bounds(self):
98 try:
99 class Q(param.Parameterized):
100 q = param.Selector([4], 5)
101 except ValueError:
102 pass
103 else:
104 raise AssertionError("Selector created outside range.")
105
106
107 def test_initialization_no_bounds(self):
108 try:
109 class Q(param.Parameterized):
110 q = param.Selector(10, default=5)
111 except TypeError:
112 pass
113 else:
114 raise AssertionError("Selector created without range.")
115
116
117 if __name__ == "__main__":
118 import nose
119 nose.runmodule()
+0
-56
tests/API1/teststringparam.py less more
0 """
1 Unit test for String parameters
2 """
3 from . import API1TestCase
4
5 import param
6
7
8 ip_regex = '^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$'
9
10 class TestStringParameters(API1TestCase):
11
12 def test_regex_ok(self):
13 class A(param.Parameterized):
14 s = param.String('0.0.0.0', ip_regex)
15
16 a = A()
17 a.s = '123.123.0.1'
18
19 def test_reject_none(self):
20 class A(param.Parameterized):
21 s = param.String('0.0.0.0', ip_regex)
22
23 a = A()
24
25 exception = "String 's' only takes a string value."
26 with self.assertRaisesRegexp(ValueError, exception):
27 a.s = None # because allow_None should be False
28
29 def test_default_none(self):
30 class A(param.Parameterized):
31 s = param.String(None, ip_regex)
32
33 a = A()
34 a.s = '123.123.0.1'
35 a.s = None # because allow_None should be True with default of None
36
37 def test_regex_incorrect(self):
38
39 class A(param.Parameterized):
40 s = param.String('0.0.0.0', regex=ip_regex)
41
42 a = A()
43
44 exception = "String 's': '123.123.0.256' does not match regex"
45 with self.assertRaisesRegexp(ValueError, exception):
46 a.s = '123.123.0.256'
47
48 def test_regex_incorrect_default(self):
49
50 exception = "String 'None': '' does not match regex"
51 with self.assertRaisesRegexp(ValueError, exception):
52 class A(param.Parameterized):
53 s = param.String(regex=ip_regex) # default value '' does not match regular expression
54
55
+0
-302
tests/API1/testtimedependent.py less more
0 """
1 Unit tests for the param.Time class, time dependent parameters and
2 time-dependent numbergenerators.
3 """
4 import param
5 import numbergen
6 import copy
7
8 from . import API1TestCase
9 from nose.plugins.skip import SkipTest
10 import fractions
11
12 try:
13 import gmpy
14 except:
15 gmpy = None
16
17
18
19 class TestTimeClass(API1TestCase):
20
21 def test_time_init(self):
22 param.Time()
23
24 def test_time_init_int(self):
25 t = param.Time(time_type=int)
26 self.assertEqual(t(), 0)
27
28 def test_time_int_iter(self):
29 t = param.Time(time_type=int)
30 self.assertEqual(next(t), 0)
31 self.assertEqual(next(t), 1)
32
33 def test_time_init_timestep(self):
34 t = param.Time(time_type=int, timestep=2)
35 self.assertEqual(next(t), 0)
36 self.assertEqual(next(t), 2)
37
38 def test_time_int_until(self):
39 t = param.Time(time_type=int, until=3)
40 self.assertEqual(next(t), 0)
41 self.assertEqual(next(t), 1)
42 self.assertEqual(next(t), 2)
43 self.assertEqual(next(t), 3)
44 try:
45 self.assertEqual(next(t), 4)
46 raise AssertionError("StopIteration should have been raised")
47 except StopIteration:
48 pass
49
50 def test_time_int_eq(self):
51 t = param.Time(time_type=int)
52 s = param.Time(time_type=int)
53 t(3); s(3)
54 self.assertEqual(t == s, True)
55
56 def test_time_int_context(self):
57 t = param.Time(time_type=int)
58 t(3)
59 with t:
60 self.assertEqual(t(), 3)
61 t(5)
62 self.assertEqual(t(), 5)
63 self.assertEqual(t(), 3)
64
65 def test_time_int_context_iadd(self):
66
67 with param.Time(time_type=int) as t:
68 self.assertEqual(t(), 0)
69 t += 5
70 self.assertEqual(t(), 5)
71 self.assertEqual(t(), 0)
72
73 def test_time_int_change_type(self):
74 t = param.Time(time_type=int)
75 self.assertEqual(t(), 0)
76 t(1, fractions.Fraction)
77 self.assertEqual(t(), 1)
78 self.assertEqual(t.time_type, fractions.Fraction)
79
80 def test_time_init_gmpy(self):
81 if gmpy is None: raise SkipTest
82
83 t = param.Time(time_type=gmpy.mpq)
84 self.assertEqual(t(), gmpy.mpq(0))
85 t.advance(gmpy.mpq(0.25))
86 self.assertEqual(t(), gmpy.mpq(1,4))
87
88 def test_time_init_gmpy_advanced(self):
89 if gmpy is None: raise SkipTest
90 t = param.Time(time_type=gmpy.mpq,
91 timestep=gmpy.mpq(0.25),
92 until=1.5)
93 self.assertEqual(t(), gmpy.mpq(0,1))
94 t(0.5)
95 self.assertEqual(t(), gmpy.mpq(1,2))
96 with t:
97 t.advance(0.25)
98 self.assertEqual(t(), gmpy.mpq(3,4))
99 self.assertEqual(t(), gmpy.mpq(1,2))
100 tvals = [tval for tval in t]
101 self.assertEqual(tvals, [gmpy.mpq(1,2),
102 gmpy.mpq(3,4),
103 gmpy.mpq(1,1),
104 gmpy.mpq(5,4),
105 gmpy.mpq(3,2)])
106
107
108 class TestTimeDependentDynamic(API1TestCase):
109
110 def setUp(self):
111 super(TestTimeDependentDynamic, self).setUp()
112 param.Dynamic.time_dependent=None
113 self.time_fn= param.Time(time_type=int)
114
115 class Incrementer(object):
116 def __init__(self):
117 self.i = -1
118 def __call__(self):
119 self.i+=1
120 return self.i
121
122 self.Incrementer = Incrementer
123
124 class DynamicClass(param.Parameterized):
125 a = param.Number(default = self.Incrementer())
126
127 self.DynamicClass = DynamicClass
128 self._start_state = copy.copy([param.Dynamic.time_dependent,
129 numbergen.TimeAware.time_dependent,
130 param.Dynamic.time_fn,
131 numbergen.TimeAware.time_fn,
132 param.random_seed])
133
134 def tearDown(self):
135 param.Dynamic.time_dependent = self._start_state[0]
136 numbergen.TimeAware.time_dependent = self._start_state[1]
137 param.Dynamic.time_fn = self._start_state[2]
138 numbergen.TimeAware.time_fn = self._start_state[3]
139 param.random_seed = self._start_state[4]
140
141 def test_non_time_dependent(self):
142 """
143 With param.Dynamic.time_dependent=None every call should
144 increment.
145 """
146 param.Dynamic.time_dependent=None
147 param.Dynamic.time_fn = self.time_fn
148
149 dynamic = self.DynamicClass()
150 self.assertEqual(dynamic.a, 0)
151 self.assertEqual(dynamic.a, 1)
152 self.assertEqual(dynamic.a, 2)
153
154 def test_time_fixed(self):
155 """
156 With param.Dynamic.time_dependent=True the value should only
157 increment when the time value changes.
158 """
159 param.Dynamic.time_dependent=True
160 param.Dynamic.time_fn = self.time_fn
161
162 dynamic = self.DynamicClass()
163 self.assertEqual(dynamic.a, 0)
164 self.assertEqual(dynamic.a, 0)
165
166 self.time_fn += 1
167 self.assertEqual(dynamic.a, 1)
168 self.assertEqual(dynamic.a, 1)
169 param.Dynamic.time_fn -= 5
170 self.assertEqual(dynamic.a, 2)
171 self.assertEqual(dynamic.a, 2)
172
173
174 def test_time_dependent(self):
175 """
176 With param.Dynamic.time_dependent=True and param.Dynamic and
177 numbergen.TimeDependent sharing a common time_fn, the value
178 should be a function of time.
179 """
180 param.Dynamic.time_dependent=True
181 param.Dynamic.time_fn = self.time_fn
182 numbergen.TimeDependent.time_fn = self.time_fn
183
184 class DynamicClass(param.Parameterized):
185 b = param.Number(default = numbergen.ScaledTime(factor=2))
186
187 dynamic = DynamicClass()
188 self.time_fn(0)
189 self.assertEqual(dynamic.b, 0.0)
190 self.time_fn += 5
191 self.assertEqual(dynamic.b, 10.0)
192 self.assertEqual(dynamic.b, 10.0)
193 self.time_fn -= 2
194 self.assertEqual(dynamic.b, 6.0)
195 self.assertEqual(dynamic.b, 6.0)
196 self.time_fn -= 3
197 self.assertEqual(dynamic.b, 0.0)
198
199
200 def test_time_dependent_random(self):
201 """
202 When set to time_dependent=True, random number generators
203 should also be a function of time.
204 """
205 param.Dynamic.time_dependent=True
206 numbergen.TimeAware.time_dependent=True
207 param.Dynamic.time_fn = self.time_fn
208 numbergen.TimeAware.time_fn = self.time_fn
209 param.random_seed = 42
210
211 class DynamicClass(param.Parameterized):
212 c = param.Number(default = numbergen.UniformRandom(name = 'test1'))
213 d = param.Number(default = numbergen.UniformRandom(name = 'test2'))
214 e = param.Number(default = numbergen.UniformRandom(name = 'test1'))
215
216 dynamic = DynamicClass()
217
218 test1_t1 = 0.23589388250988552
219 test2_t1 = 0.12576257837158122
220 test1_t2 = 0.14117586161849593
221 test2_t2 = 0.9134917395930359
222
223 self.time_fn(0)
224 self.assertEqual(dynamic.c, test1_t1)
225 self.assertEqual(dynamic.c, dynamic.e)
226 self.assertNotEqual(dynamic.c, dynamic.d)
227 self.assertEqual(dynamic.d, test2_t1)
228 self.time_fn(1)
229 self.assertEqual(dynamic.c, test1_t2)
230 self.assertEqual(dynamic.c, test1_t2)
231 self.assertEqual(dynamic.d, test2_t2)
232 self.time_fn(0)
233 self.assertEqual(dynamic.c, test1_t1)
234 self.assertEqual(dynamic.d, test2_t1)
235
236
237 def test_time_hashing_integers(self):
238 """
239 Check that ints, fractions and strings hash to the same value
240 for integer values.
241 """
242 hashfn = numbergen.Hash("test", input_count=1)
243 hash_1 = hashfn(1)
244 hash_42 = hashfn(42)
245 hash_200001 = hashfn(200001)
246
247 self.assertEqual(hash_1, hashfn(fractions.Fraction(1)))
248 self.assertEqual(hash_1, hashfn("1"))
249
250 self.assertEqual(hash_42, hashfn(fractions.Fraction(42)))
251 self.assertEqual(hash_42, hashfn("42"))
252
253 self.assertEqual(hash_200001, hashfn(fractions.Fraction(200001)))
254 self.assertEqual(hash_200001, hashfn("200001"))
255
256
257 def test_time_hashing_rationals(self):
258 """
259 Check that hashes fractions and strings match for some
260 reasonable rational numbers.
261 """
262 hashfn = numbergen.Hash("test", input_count=1)
263 pi = "3.141592"
264 half = fractions.Fraction(0.5)
265 self.assertEqual(hashfn(0.5), hashfn(half))
266 self.assertEqual(hashfn(pi), hashfn(fractions.Fraction(pi)))
267
268
269 def test_time_hashing_integers_gmpy(self):
270 """
271 Check that hashes for gmpy values at the integers also matches
272 those of ints, fractions and strings.
273 """
274 if gmpy is None: raise SkipTest
275 hashfn = numbergen.Hash("test", input_count=1)
276 hash_1 = hashfn(1)
277 hash_42 = hashfn(42)
278
279 self.assertEqual(hash_1, hashfn(gmpy.mpq(1)))
280 self.assertEqual(hash_1, hashfn(1))
281
282 self.assertEqual(hash_42, hashfn(gmpy.mpq(42)))
283 self.assertEqual(hash_42, hashfn(42))
284
285 def test_time_hashing_rationals_gmpy(self):
286 """
287 Check that hashes of fractions and gmpy mpqs match for some
288 reasonable rational numbers.
289 """
290 if gmpy is None: raise SkipTest
291 pi = "3.141592"
292 hashfn = numbergen.Hash("test", input_count=1)
293 self.assertEqual(hashfn(0.5), hashfn(gmpy.mpq(0.5)))
294 self.assertEqual(hashfn(pi), hashfn(gmpy.mpq(3.141592)))
295
296
297
298
299 if __name__ == "__main__":
300 import nose
301 nose.runmodule()
+0
-711
tests/API1/testwatch.py less more
0 """
1 Unit test for watch mechanism
2 """
3 from . import API1TestCase
4
5 from .utils import MockLoggingHandler
6
7 import param
8
9 from param.parameterized import discard_events
10
11
12 class Accumulator(object):
13
14 def __init__(self):
15 self.args = []
16 self.kwargs = []
17
18 def __call__(self, *args, **kwargs):
19 self.args.append(args)
20 self.kwargs.append(kwargs)
21
22 def call_count(self):
23 return max(len(self.args), len(self.kwargs))
24
25 def args_for_call(self, number):
26 return self.args[number]
27
28 def kwargs_for_call(self, number):
29 return self.kwargs[number]
30
31
32
33 class SimpleWatchExample(param.Parameterized):
34 a = param.Parameter(default=0)
35 b = param.Parameter(default=0)
36 c = param.Parameter(default=0)
37 d = param.Integer(default=0)
38
39
40 class SimpleWatchSubclass(SimpleWatchExample):
41 pass
42
43
44 class WatchMethodExample(SimpleWatchSubclass):
45
46 @param.depends('a', watch='queued')
47 def _clip_a(self):
48 if self.a > 3:
49 self.a = 3
50
51 @param.depends('b', watch=True)
52 def _clip_b(self):
53 if self.b > 10:
54 self.b = 10
55
56 @param.depends('b', watch=True)
57 def _set_c(self):
58 self.c = self.b*2
59
60 @param.depends('c', watch=True)
61 def _set_d_bounds(self):
62 self.param.d.bounds = (self.c, self.c*2)
63
64
65 class WatchSubclassExample(WatchMethodExample):
66
67 pass
68
69
70
71 class TestWatch(API1TestCase):
72
73 @classmethod
74 def setUpClass(cls):
75 super(TestWatch, cls).setUpClass()
76 log = param.parameterized.get_logger()
77 cls.log_handler = MockLoggingHandler(level='DEBUG')
78 log.addHandler(cls.log_handler)
79
80
81 def setUp(self):
82 super(TestWatch, self).setUp()
83 self.accumulator = 0
84
85 def test_triggered_when_changed(self):
86 def accumulator(change):
87 self.accumulator += change.new
88
89 obj = SimpleWatchExample()
90 obj.param.watch(accumulator, 'a')
91 obj.a = 1
92 self.assertEqual(self.accumulator, 1)
93 obj.a = 2
94 self.assertEqual(self.accumulator, 3)
95
96
97 def test_discard_events_decorator(self):
98 def accumulator(change):
99 self.accumulator += change.new
100
101 obj = SimpleWatchExample()
102 obj.param.watch(accumulator, 'a')
103 with discard_events(obj):
104 obj.a = 1
105 self.assertEqual(self.accumulator, 0)
106 obj.a = 2
107 self.assertEqual(self.accumulator, 3)
108
109
110 def test_triggered_when_changed_iterator_type(self):
111 def accumulator(change):
112 self.accumulator = change.new
113
114 obj = SimpleWatchExample()
115 obj.param.watch(accumulator, 'a')
116 obj.a = []
117 self.assertEqual(self.accumulator, [])
118 obj.a = tuple()
119 self.assertEqual(self.accumulator, tuple())
120
121
122 def test_triggered_when_changed_mapping_type(self):
123 def accumulator(change):
124 self.accumulator = change.new
125
126 obj = SimpleWatchExample()
127 obj.param.watch(accumulator, 'a')
128 obj.a = []
129 self.assertEqual(self.accumulator, [])
130 obj.a = {}
131 self.assertEqual(self.accumulator, {})
132
133
134 def test_untriggered_when_unchanged(self):
135 def accumulator(change):
136 self.accumulator += change.new
137
138 obj = SimpleWatchExample()
139 obj.param.watch(accumulator, 'a')
140 obj.a = 1
141 self.assertEqual(self.accumulator, 1)
142 obj.a = 1
143 self.assertEqual(self.accumulator, 1)
144
145
146 def test_triggered_when_unchanged_complex_type(self):
147 def accumulator(change):
148 self.accumulator += 1
149
150 obj = SimpleWatchExample()
151 obj.param.watch(accumulator, 'a')
152 subobj = object()
153 obj.a = subobj
154 self.assertEqual(self.accumulator, 1)
155 obj.a = subobj
156 self.assertEqual(self.accumulator, 2)
157
158
159 def test_triggered_when_unchanged_if_not_onlychanged(self):
160 accumulator = Accumulator()
161 obj = SimpleWatchExample()
162 obj.param.watch(accumulator, 'a', onlychanged=False)
163 obj.a = 1
164
165 self.assertEqual(accumulator.call_count(), 1)
166 args = accumulator.args_for_call(0)
167 self.assertEqual(len(args), 1)
168 self.assertEqual(args[0].name, 'a')
169 self.assertEqual(args[0].old, 0)
170 self.assertEqual(args[0].new, 1)
171 self.assertEqual(args[0].type, 'set')
172
173 obj.a = 1
174 args = accumulator.args_for_call(1)
175 self.assertEqual(len(args), 1)
176 self.assertEqual(args[0].name, 'a')
177 self.assertEqual(args[0].old, 1)
178 self.assertEqual(args[0].new, 1)
179 self.assertEqual(args[0].type, 'set')
180
181
182
183 def test_untriggered_when_unwatched(self):
184 def accumulator(change):
185 self.accumulator += change.new
186
187 obj = SimpleWatchExample()
188 watcher = obj.param.watch(accumulator, 'a')
189 obj.a = 1
190 self.assertEqual(self.accumulator, 1)
191 obj.param.unwatch(watcher)
192 obj.a = 2
193 self.assertEqual(self.accumulator, 1)
194
195
196 def test_warning_unwatching_when_unwatched(self):
197 def accumulator(change):
198 self.accumulator += change.new
199
200 obj = SimpleWatchExample()
201 watcher = obj.param.watch(accumulator, 'a')
202 obj.param.unwatch(watcher)
203 obj.param.unwatch(watcher)
204 self.log_handler.assertEndsWith('WARNING',
205 ' to remove.')
206
207 def test_simple_batched_watch_setattr(self):
208
209 accumulator = Accumulator()
210
211 obj = SimpleWatchExample()
212 obj.param.watch(accumulator, ['a','b'])
213
214 obj.a = 2
215 self.assertEqual(accumulator.call_count(), 1)
216 args = accumulator.args_for_call(0)
217
218 self.assertEqual(len(args), 1)
219 self.assertEqual(args[0].name, 'a')
220 self.assertEqual(args[0].old, 0)
221 self.assertEqual(args[0].new, 2)
222 self.assertEqual(args[0].type, 'changed')
223
224 obj.b = 3
225 self.assertEqual(accumulator.call_count(), 2)
226 args = accumulator.args_for_call(1)
227
228 self.assertEqual(len(args), 1)
229 self.assertEqual(args[0].name, 'b')
230 self.assertEqual(args[0].old, 0)
231 self.assertEqual(args[0].new, 3)
232 self.assertEqual(args[0].type, 'changed')
233
234 def test_batched_watch_context_manager(self):
235
236 accumulator = Accumulator()
237
238 obj = SimpleWatchExample()
239 obj.param.watch(accumulator, ['a','b'])
240
241 with param.batch_watch(obj):
242 obj.a = 2
243 obj.b = 3
244
245 self.assertEqual(accumulator.call_count(), 1)
246 args = accumulator.args_for_call(0)
247
248 self.assertEqual(len(args), 2)
249 self.assertEqual(args[0].name, 'a')
250 self.assertEqual(args[0].old, 0)
251 self.assertEqual(args[0].new, 2)
252 self.assertEqual(args[0].type, 'changed')
253 self.assertEqual(args[1].name, 'b')
254 self.assertEqual(args[1].old, 0)
255 self.assertEqual(args[1].new, 3)
256 self.assertEqual(args[1].type, 'changed')
257
258 def test_nested_batched_watch_setattr(self):
259
260 obj = SimpleWatchExample()
261
262 accumulator = Accumulator()
263 obj.param.watch(accumulator, ['a', 'c'])
264
265 def set_c(*events):
266 obj.c = 3
267
268 obj.param.watch(set_c, ['a', 'b'])
269
270 obj.param.set_param(a=2)
271 self.assertEqual(obj.c, 3)
272
273 # Change inside watch callback should have triggered
274 # second call to accumulator
275 self.assertEqual(accumulator.call_count(), 2)
276
277
278 def test_simple_batched_watch(self):
279
280 accumulator = Accumulator()
281
282 obj = SimpleWatchExample()
283 obj.param.watch(accumulator, ['a','b'])
284 obj.param.set_param(a=23, b=42)
285
286 self.assertEqual(accumulator.call_count(), 1)
287 args = accumulator.args_for_call(0)
288 self.assertEqual(len(args), 2)
289
290 self.assertEqual(args[0].name, 'a')
291 self.assertEqual(args[0].old, 0)
292 self.assertEqual(args[0].new, 23)
293 self.assertEqual(args[0].type, 'changed')
294
295 self.assertEqual(args[1].name, 'b')
296 self.assertEqual(args[1].old, 0)
297 self.assertEqual(args[1].new, 42)
298 self.assertEqual(args[1].type, 'changed')
299
300
301 def test_simple_class_batched_watch(self):
302
303 accumulator = Accumulator()
304
305 obj = SimpleWatchSubclass
306 watcher = obj.param.watch(accumulator, ['a','b'])
307 obj.param.set_param(a=23, b=42)
308
309 self.assertEqual(accumulator.call_count(), 1)
310 args = accumulator.args_for_call(0)
311 self.assertEqual(len(args), 2)
312
313 self.assertEqual(args[0].name, 'a')
314 self.assertEqual(args[0].old, 0)
315 self.assertEqual(args[0].new, 23)
316 self.assertEqual(args[0].type, 'changed')
317
318 self.assertEqual(args[1].name, 'b')
319 self.assertEqual(args[1].old, 0)
320 self.assertEqual(args[1].new, 42)
321 self.assertEqual(args[1].type, 'changed')
322
323 SimpleWatchExample.param.unwatch(watcher)
324 obj.param.set_param(a=0, b=0)
325
326
327 def test_simple_batched_watch_callback_reuse(self):
328
329 accumulator = Accumulator()
330
331 obj = SimpleWatchExample()
332 obj.param.watch(accumulator, ['a','b'])
333 obj.param.watch(accumulator, ['c'])
334
335 obj.param.set_param(a=23, b=42, c=99)
336
337 self.assertEqual(accumulator.call_count(), 2)
338 # Order may be undefined for Python <3.6
339 for args in [accumulator.args_for_call(i) for i in [0,1]]:
340 if len(args) == 1: # ['c']
341 self.assertEqual(args[0].name, 'c')
342 self.assertEqual(args[0].old, 0)
343 self.assertEqual(args[0].new, 99)
344 self.assertEqual(args[0].type, 'changed')
345
346 elif len(args) == 2: # ['a', 'b']
347 self.assertEqual(args[0].name, 'a')
348 self.assertEqual(args[0].old, 0)
349 self.assertEqual(args[0].new, 23)
350 self.assertEqual(args[0].type, 'changed')
351
352 self.assertEqual(args[1].name, 'b')
353 self.assertEqual(args[1].old, 0)
354 self.assertEqual(args[1].new, 42)
355 self.assertEqual(args[0].type, 'changed')
356 else:
357 raise Exception('Invalid number of arguments')
358
359
360 def test_subclass_batched_watch(self):
361
362 accumulator = Accumulator()
363
364 obj = SimpleWatchSubclass()
365
366 obj.param.watch(accumulator, ['b','c'])
367 obj.param.set_param(b=23, c=42)
368
369 self.assertEqual(accumulator.call_count(), 1)
370 args = accumulator.args_for_call(0)
371 self.assertEqual(len(args), 2)
372
373 self.assertEqual(args[0].name, 'b')
374 self.assertEqual(args[0].old, 0)
375 self.assertEqual(args[0].new, 23)
376 self.assertEqual(args[0].type, 'changed')
377
378 self.assertEqual(args[1].name, 'c')
379 self.assertEqual(args[1].old, 0)
380 self.assertEqual(args[1].new, 42)
381 self.assertEqual(args[1].type, 'changed')
382
383
384 def test_nested_batched_watch(self):
385
386 accumulator = Accumulator()
387
388 obj = SimpleWatchExample()
389
390 def set_param(*changes):
391 obj.param.set_param(a=10, d=12)
392
393 obj.param.watch(accumulator, ['a', 'b','c', 'd'])
394 obj.param.watch(set_param, ['b', 'c'])
395 obj.param.set_param(b=23, c=42)
396
397 self.assertEqual(accumulator.call_count(), 2)
398 args = accumulator.args_for_call(0)
399 self.assertEqual(len(args), 2)
400
401 self.assertEqual(args[0].name, 'b')
402 self.assertEqual(args[0].old, 0)
403 self.assertEqual(args[0].new, 23)
404 self.assertEqual(args[0].type, 'changed')
405
406 self.assertEqual(args[1].name, 'c')
407 self.assertEqual(args[1].old, 0)
408 self.assertEqual(args[1].new, 42)
409 self.assertEqual(args[1].type, 'changed')
410
411 args = accumulator.args_for_call(1)
412 self.assertEqual(len(args), 2)
413
414 self.assertEqual(args[0].name, 'a')
415 self.assertEqual(args[0].old, 0)
416 self.assertEqual(args[0].new, 10)
417 self.assertEqual(args[0].type, 'changed')
418
419 self.assertEqual(args[1].name, 'd')
420 self.assertEqual(args[1].old, 0)
421 self.assertEqual(args[1].new, 12)
422 self.assertEqual(args[1].type, 'changed')
423
424
425 def test_nested_batched_watch_not_onlychanged(self):
426 accumulator = Accumulator()
427
428 obj = SimpleWatchSubclass()
429
430 obj.param.watch(accumulator, ['b','c'], onlychanged=False)
431 obj.param.set_param(b=0, c=0)
432
433 self.assertEqual(accumulator.call_count(), 1)
434
435 args = accumulator.args_for_call(0)
436 self.assertEqual(len(args), 2)
437
438 self.assertEqual(args[0].name, 'b')
439 self.assertEqual(args[0].old, 0)
440 self.assertEqual(args[0].new, 0)
441 self.assertEqual(args[0].type, 'set')
442
443 self.assertEqual(args[1].name, 'c')
444 self.assertEqual(args[1].old, 0)
445 self.assertEqual(args[1].new, 0)
446 self.assertEqual(args[1].type, 'set')
447
448
449
450 class TestWatchMethod(API1TestCase):
451
452 def test_dependent_params(self):
453 obj = WatchMethodExample()
454
455 obj.b = 3
456 self.assertEqual(obj.c, 6)
457
458 def test_multiple_watcher_dispatch_queued(self):
459 obj = WatchMethodExample()
460 obj2 = SimpleWatchExample()
461
462 def link(event):
463 obj2.a = event.new
464
465 obj.param.watch(link, 'a', queued=True)
466 obj.a = 4
467 self.assertEqual(obj.a, 3)
468 self.assertEqual(obj2.a, 3)
469
470 def test_multiple_watcher_dispatch(self):
471 obj = WatchMethodExample()
472 obj2 = SimpleWatchExample()
473
474 def link(event):
475 obj2.b = event.new
476
477 obj.param.watch(link, 'b')
478 obj.b = 11
479 self.assertEqual(obj.b, 10)
480 self.assertEqual(obj2.b, 11)
481
482 def test_multiple_watcher_dispatch_on_param_attribute(self):
483 obj = WatchMethodExample()
484 accumulator = Accumulator()
485
486 obj.param.watch(accumulator, 'd', 'bounds')
487 obj.c = 2
488 self.assertEqual(obj.param.d.bounds, (2, 4))
489 self.assertEqual(accumulator.call_count(), 1)
490
491 def test_depends_with_watch_on_subclass(self):
492 obj = WatchSubclassExample()
493
494 obj.b = 3
495 self.assertEqual(obj.c, 6)
496
497
498
499
500 class TestWatchValues(API1TestCase):
501
502 def setUp(self):
503 super(TestWatchValues, self).setUp()
504 self.accumulator = 0
505
506 def test_triggered_when_values_changed(self):
507 def accumulator(a):
508 self.accumulator += a
509
510 obj = SimpleWatchExample()
511 obj.param.watch_values(accumulator, 'a')
512 obj.a = 1
513 self.assertEqual(self.accumulator, 1)
514 obj.a = 2
515 self.assertEqual(self.accumulator, 3)
516
517
518 def test_untriggered_when_values_unchanged(self):
519 def accumulator(a):
520 self.accumulator += a
521
522 obj = SimpleWatchExample()
523 obj.param.watch_values(accumulator, 'a')
524 obj.a = 1
525 self.assertEqual(self.accumulator, 1)
526 obj.a = 1
527 self.assertEqual(self.accumulator, 1)
528
529
530 def test_untriggered_when_values_unwatched(self):
531 def accumulator(a):
532 self.accumulator += a
533
534 obj = SimpleWatchExample()
535 watcher = obj.param.watch_values(accumulator, 'a')
536 obj.a = 1
537 self.assertEqual(self.accumulator, 1)
538 obj.param.unwatch(watcher)
539 obj.a = 2
540 self.assertEqual(self.accumulator, 1)
541
542
543 def test_simple_batched_watch_values_setattr(self):
544
545 accumulator = Accumulator()
546
547 obj = SimpleWatchExample()
548 obj.param.watch_values(accumulator, ['a','b'])
549
550 obj.a = 2
551 self.assertEqual(accumulator.call_count(), 1)
552 kwargs = accumulator.kwargs_for_call(0)
553
554 self.assertEqual(len(kwargs), 1)
555 self.assertEqual(kwargs, {'a':2})
556
557 obj.b = 3
558 self.assertEqual(accumulator.call_count(), 2)
559 kwargs = accumulator.kwargs_for_call(1)
560 self.assertEqual(kwargs, {'b':3})
561
562
563 def test_simple_batched_watch_values(self):
564
565 accumulator = Accumulator()
566
567 obj = SimpleWatchExample()
568 obj.param.watch_values(accumulator, ['a','b'])
569 obj.param.set_param(a=23, b=42)
570
571 self.assertEqual(accumulator.call_count(), 1)
572 kwargs = accumulator.kwargs_for_call(0)
573 self.assertEqual(kwargs, {'a':23, 'b':42})
574
575
576 def test_simple_batched_watch_values_callback_reuse(self):
577
578 accumulator = Accumulator()
579
580 obj = SimpleWatchExample()
581 obj.param.watch_values(accumulator, ['a','b'])
582 obj.param.watch_values(accumulator, ['c'])
583
584 obj.param.set_param(a=23, b=42, c=99)
585
586 self.assertEqual(accumulator.call_count(), 2)
587 # Order may be undefined for Python <3.6
588 for kwargs in [accumulator.kwargs_for_call(i) for i in [0,1]]:
589 if len(kwargs) == 1: # ['c']
590 self.assertEqual(kwargs, {'c':99})
591 elif len(kwargs) == 2: # ['a', 'b']
592 self.assertEqual(kwargs, {'a':23, 'b':42})
593 else:
594 raise Exception('Invalid number of arguments')
595
596
597
598
599
600 class TestWatchAttributes(API1TestCase):
601
602 def setUp(self):
603 super(TestWatchAttributes, self).setUp()
604 self.accumulator = []
605
606 def tearDown(self):
607 SimpleWatchExample.param['d'].bounds = None
608
609 def test_watch_class_param_attribute(self):
610 def accumulator(a):
611 self.accumulator += [a.new]
612
613 SimpleWatchExample.param.watch(accumulator, ['d'], 'bounds')
614 SimpleWatchExample.param['d'].bounds = (0, 3)
615 assert self.accumulator == [(0, 3)]
616
617 def test_watch_instance_param_attribute(self):
618 def accumulator(a):
619 self.accumulator += [a.new]
620
621 obj = SimpleWatchExample()
622 obj.param.watch(accumulator, ['d'], 'bounds')
623
624 # Ensure watching an instance parameter makes copy
625 assert obj.param.objects('current')['d'] is not SimpleWatchExample.param['d']
626
627 obj.param['d'].bounds = (0, 3)
628 assert SimpleWatchExample.param['d'].bounds is None
629 assert self.accumulator == [(0, 3)]
630
631
632
633 class TestTrigger(API1TestCase):
634
635 def setUp(self):
636 super(TestTrigger, self).setUp()
637 self.accumulator = 0
638
639 def test_simple_trigger_one_param(self):
640 accumulator = Accumulator()
641 obj = SimpleWatchExample()
642 obj.param.watch(accumulator, ['a'])
643 obj.param.trigger('a')
644 self.assertEqual(accumulator.call_count(), 1)
645
646 args = accumulator.args_for_call(0)
647 self.assertEqual(args[0].name, 'a')
648 self.assertEqual(args[0].old, 0)
649 self.assertEqual(args[0].new, 0)
650 self.assertEqual(args[0].type, 'triggered')
651
652 def test_simple_trigger_when_batched(self):
653 accumulator = Accumulator()
654 obj = SimpleWatchExample()
655 obj.param.watch(accumulator, ['a'])
656 with param.batch_watch(obj):
657 obj.param.trigger('a')
658 self.assertEqual(accumulator.call_count(), 1)
659
660 args = accumulator.args_for_call(0)
661 self.assertEqual(args[0].name, 'a')
662 self.assertEqual(args[0].old, 0)
663 self.assertEqual(args[0].new, 0)
664 # Note: This is not strictly correct
665 self.assertEqual(args[0].type, 'changed')
666
667 def test_simple_trigger_one_param_change(self):
668 accumulator = Accumulator()
669 obj = SimpleWatchExample()
670 obj.param.watch(accumulator, ['a'])
671 obj.a = 42
672 self.assertEqual(accumulator.call_count(), 1)
673
674 obj.param.trigger('a')
675 self.assertEqual(accumulator.call_count(), 2)
676
677 args = accumulator.args_for_call(0)
678 self.assertEqual(args[0].name, 'a')
679 self.assertEqual(args[0].old, 0)
680 self.assertEqual(args[0].new, 42)
681 self.assertEqual(args[0].type, 'changed')
682
683 args = accumulator.args_for_call(1)
684 self.assertEqual(args[0].name, 'a')
685 self.assertEqual(args[0].old, 42)
686 self.assertEqual(args[0].new, 42)
687 self.assertEqual(args[0].type, 'triggered')
688
689 def test_simple_trigger_two_params(self):
690 accumulator = Accumulator()
691 obj = SimpleWatchExample()
692 obj.param.watch(accumulator, ['a','b'])
693 obj.param.trigger('a','b')
694 self.assertEqual(accumulator.call_count(), 1)
695
696 args = accumulator.args_for_call(0)
697 self.assertEqual(args[0].name, 'a')
698 self.assertEqual(args[0].old, 0)
699 self.assertEqual(args[0].new, 0)
700 self.assertEqual(args[0].type, 'triggered')
701
702 self.assertEqual(args[1].name, 'b')
703 self.assertEqual(args[1].old, 0)
704 self.assertEqual(args[1].new, 0)
705 self.assertEqual(args[1].type, 'triggered')
706
707
708 if __name__ == "__main__":
709 import nose
710 nose.runmodule()
+0
-77
tests/API1/utils.py less more
0 import logging
1
2 class MockLoggingHandler(logging.Handler):
3 """Mock logging handler to check for expected logs.
4
5 Messages are available from an instance's ``messages`` dict, in
6 order, indexed by a lowercase log level string (e.g., 'debug',
7 'info', etc.).
8
9 This is typically used by using a setUpClass classmethod and a setUp
10 method on a test case. The setUpClass classmethod can be configured
11 as follows after calling super (with cls):
12
13 log = param.parameterized.get_logger()
14 cls.log_handler = MockLoggingHandler(level='DEBUG')
15 log.addHandler(cls.log_handler)
16
17 The setUp method then just needs to call self.log_handler.reset()
18 between tests (typically after invoking super). This is necessary to
19 make the tests independent where the tests can use the
20 self.log_handler.tail and self.log_handler.assertEndsWith methods.
21 """
22
23 def __init__(self, *args, **kwargs):
24 self.messages = {'DEBUG': [], 'INFO': [], 'WARNING': [],
25 'ERROR': [], 'CRITICAL': [], 'VERBOSE':[]}
26 self.param_methods = {'WARNING':'param.warning()', 'INFO':'param.message()',
27 'VERBOSE':'param.verbose()', 'DEBUG':'param.debug()'}
28 super(MockLoggingHandler, self).__init__(*args, **kwargs)
29
30 def emit(self, record):
31 "Store a message to the instance's messages dictionary"
32 self.acquire()
33 try:
34 self.messages[record.levelname].append(record.getMessage())
35 finally:
36 self.release()
37
38 def reset(self):
39 self.acquire()
40 self.messages = {'DEBUG': [], 'INFO': [], 'WARNING': [],
41 'ERROR': [], 'CRITICAL': [], 'VERBOSE':[]}
42 self.release()
43
44 def tail(self, level, n=1):
45 "Returns the last n lines captured at the given level"
46 return [str(el) for el in self.messages[level][-n:]]
47
48 def assertEndsWith(self, level, substring):
49 """
50 Assert that the last line captured at the given level ends with
51 a particular substring.
52 """
53 msg='\n\n{method}: {last_line}\ndoes not end with:\n{substring}'
54 last_line = self.tail(level, n=1)
55 if len(last_line) == 0:
56 raise AssertionError('Missing {method} output: {substring}'.format(
57 method=self.param_methods[level], substring=repr(substring)))
58 if not last_line[0].endswith(substring):
59 raise AssertionError(msg.format(method=self.param_methods[level],
60 last_line=repr(last_line[0]),
61 substring=repr(substring)))
62
63 def assertContains(self, level, substring):
64 """
65 Assert that the last line captured at the given level contains a
66 particular substring.
67 """
68 msg='\n\n{method}: {last_line}\ndoes not contain:\n{substring}'
69 last_line = self.tail(level, n=1)
70 if len(last_line) == 0:
71 raise AssertionError('Missing {method} output: {substring}'.format(
72 method=self.param_methods[level], substring=repr(substring)))
73 if substring not in last_line[0]:
74 raise AssertionError(msg.format(method=self.param_methods[level],
75 last_line=repr(last_line[0]),
76 substring=repr(substring)))
+0
-6
tests/__init__.py less more
0 import sys
1 import unittest # noqa
2
3 if sys.version_info[0]==2 and sys.version_info[1]<7:
4 del sys.modules['unittest']
5 sys.modules['unittest'] = __import__('unittest2')
+0
-47
tox.ini less more
0 [tox]
1 envlist =
2 py37,py36,py35,py34,py27,pypy,
3 {py27,py36}-flakes,
4 {py27,py36}-with_numpy,
5 {py27,py36}-with_ipython
6 {py27,py35,py36,py37}-with_pandas
7
8 [testenv]
9 deps = .[tests]
10 commands = nosetests
11
12 [testenv:coverage]
13 # remove develop install if https://github.com/ioam/param/issues/219
14 # implemented
15 setdevelop = True
16 passenv = TRAVIS TRAVIS_*
17 deps = {[testenv]deps}
18 coveralls
19 commands = nosetests --with-coverage --cover-package=param
20 coveralls
21 # TODO missing numbergen
22
23 [testenv:with_numpy]
24 deps = {[testenv]deps}
25 numpy
26 setenv = PARAM_TEST_NUMPY = 1
27
28 [testenv:with_pandas]
29 deps = {[testenv]deps}
30 pandas
31 setenv = PARAM_TEST_PANDAS = 1
32
33
34 [testenv:with_ipython]
35 deps = {[testenv]deps}
36 ipython
37 setenv = PARAM_TEST_IPYTHON = 1
38
39 [testenv:flakes]
40 skip_install = true
41 commands = flake8
42
43 [flake8]
44 ignore = E,W,W605
45 include = *.py
46 exclude = .git,__pycache__,.tox,.eggs,*.egg,doc,dist,build,_build,.ipynb_checkpoints,run_test.py