././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1642394556.2245147
pyopencl-2021.2.13/ 0000755 0001750 0001750 00000000000 00000000000 013470 5 ustar 00andreas andreas ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1569969832.0
pyopencl-2021.2.13/LICENSE 0000644 0001750 0001750 00000011645 00000000000 014504 0 ustar 00andreas andreas PyOpenCL is licensed to you under the MIT/X Consortium license:
Copyright (c) 2009-13 Andreas Klöckner and Contributors.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
PyOpenCL includes derivatives of parts of the `Thrust
`_ computing package (in particular the scan
implementation). These parts are licensed as follows:
Copyright 2008-2011 NVIDIA Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
.. note::
If you use Apache-licensed parts, be aware that these may be incompatible
with software licensed exclusively under GPL2. (Most software is licensed
as GPL2 or later, in which case this is not an issue.)
PyOpenCL includes parts of the Random123 suite of random number generators:
Copyright 2010-2012, D. E. Shaw Research.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions, and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions, and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of D. E. Shaw Research nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
PyOpenCL includes the RANLUXCL random number generator:
Copyright (c) 2011 Ivar Ursin Nikolaisen
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be included in all copies
or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1615437819.0
pyopencl-2021.2.13/MANIFEST.in 0000644 0001750 0001750 00000000756 00000000000 015236 0 ustar 00andreas andreas recursive-include pyopencl/cl *.h *.cl
include src/*.h
include src/*.hpp
include src/*.cpp
include test/*.py
include test/*.h
include test/*.spv
include examples/*.py
include examples/*.ipynb
include examples/noisyImage.jpg
include doc/*.rst
include doc/Makefile
include doc/*.py
include doc/conf.py
include configure.py
include Makefile.in
include aksetup_helper.py
include README_SETUP.txt
include README.rst
include LICENSE
include pytest.ini
recursive-include contrib *.vim *.py README
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1569969832.0
pyopencl-2021.2.13/Makefile.in 0000644 0001750 0001750 00000000503 00000000000 015533 0 ustar 00andreas andreas .PHONY : all install clean tags dist userdoc devdoc
all: tags
${PYTHON_EXE} setup.py build
dist:
${PYTHON_EXE} setup.py sdist
install: tags
${PYTHON_EXE} setup.py install
clean:
rm -Rf build
rm -f tags
tags:
ctags -R src || true
tests:
echo "running tests"
find ./test -type f -name "*.py" -exec python {} \;
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1642394556.2245147
pyopencl-2021.2.13/PKG-INFO 0000644 0001750 0001750 00000010567 00000000000 014576 0 ustar 00andreas andreas Metadata-Version: 2.1
Name: pyopencl
Version: 2021.2.13
Summary: Python wrapper for OpenCL
Home-page: http://mathema.tician.de/software/pyopencl
Author: Andreas Kloeckner
Author-email: inform@tiker.net
License: MIT
Description: PyOpenCL: Pythonic Access to OpenCL, with Arrays and Algorithms
===============================================================
.. image:: https://gitlab.tiker.net/inducer/pyopencl/badges/main/pipeline.svg
:alt: Gitlab Build Status
:target: https://gitlab.tiker.net/inducer/pyopencl/commits/main
.. image:: https://github.com/inducer/pyopencl/workflows/CI/badge.svg?branch=main&event=push
:alt: Github Build Status
:target: https://github.com/inducer/pyopencl/actions?query=branch%3Amain+workflow%3ACI+event%3Apush
.. image:: https://badge.fury.io/py/pyopencl.png
:alt: Python Package Index Release Page
:target: https://pypi.org/project/pyopencl/
PyOpenCL lets you access GPUs and other massively parallel compute
devices from Python. It tries to offer computing goodness in the
spirit of its sister project `PyCUDA `_:
* Object cleanup tied to lifetime of objects. This idiom, often
called
`RAII `_
in C++, makes it much easier to write correct, leak- and
crash-free code.
* Completeness. PyOpenCL puts the full power of OpenCL's API at
your disposal, if you wish. Every obscure `get_info()` query and
all CL calls are accessible.
* Automatic Error Checking. All CL errors are automatically
translated into Python exceptions.
* Speed. PyOpenCL's base layer is written in C++, so all the niceties
above are virtually free.
* Helpful and complete `Documentation `__
as well as a `Wiki `_.
* Liberal license. PyOpenCL is open-source under the
`MIT license `_
and free for commercial, academic, and private use.
* Broad support. PyOpenCL was tested and works with Apple's, AMD's, and Nvidia's
CL implementations.
Simple 4-step `install instructions `_
using Conda on Linux and macOS (that also install a working OpenCL implementation!)
can be found in the `documentation `__.
What you'll need if you do *not* want to use the convenient instructions above and
instead build from source:
* gcc/g++ new enough to be compatible with pybind11
(see their `FAQ `_)
* `numpy `_, and
* an OpenCL implementation. (See this `howto `_ for how to get one.)
Links
-----
* `Documentation `__ (read how things work)
* `Conda Forge `_ (download binary packages for Linux, macOS, Windows)
* `Python package index `_ (download releases)
* `C. Gohlke's Windows binaries `_ (download Windows binaries)
* `Github `_ (get latest source code, file bugs)
Platform: UNKNOWN
Classifier: Environment :: Console
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Other Audience
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Natural Language :: English
Classifier: Programming Language :: C++
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Scientific/Engineering
Classifier: Topic :: Scientific/Engineering :: Mathematics
Classifier: Topic :: Scientific/Engineering :: Physics
Requires-Python: ~=3.6
Provides-Extra: oclgrind
Provides-Extra: pocl
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1621189507.0
pyopencl-2021.2.13/README.rst 0000644 0001750 0001750 00000005736 00000000000 015172 0 ustar 00andreas andreas PyOpenCL: Pythonic Access to OpenCL, with Arrays and Algorithms
===============================================================
.. image:: https://gitlab.tiker.net/inducer/pyopencl/badges/main/pipeline.svg
:alt: Gitlab Build Status
:target: https://gitlab.tiker.net/inducer/pyopencl/commits/main
.. image:: https://github.com/inducer/pyopencl/workflows/CI/badge.svg?branch=main&event=push
:alt: Github Build Status
:target: https://github.com/inducer/pyopencl/actions?query=branch%3Amain+workflow%3ACI+event%3Apush
.. image:: https://badge.fury.io/py/pyopencl.png
:alt: Python Package Index Release Page
:target: https://pypi.org/project/pyopencl/
PyOpenCL lets you access GPUs and other massively parallel compute
devices from Python. It tries to offer computing goodness in the
spirit of its sister project `PyCUDA `_:
* Object cleanup tied to lifetime of objects. This idiom, often
called
`RAII `_
in C++, makes it much easier to write correct, leak- and
crash-free code.
* Completeness. PyOpenCL puts the full power of OpenCL's API at
your disposal, if you wish. Every obscure `get_info()` query and
all CL calls are accessible.
* Automatic Error Checking. All CL errors are automatically
translated into Python exceptions.
* Speed. PyOpenCL's base layer is written in C++, so all the niceties
above are virtually free.
* Helpful and complete `Documentation `__
as well as a `Wiki `_.
* Liberal license. PyOpenCL is open-source under the
`MIT license `_
and free for commercial, academic, and private use.
* Broad support. PyOpenCL was tested and works with Apple's, AMD's, and Nvidia's
CL implementations.
Simple 4-step `install instructions `_
using Conda on Linux and macOS (that also install a working OpenCL implementation!)
can be found in the `documentation `__.
What you'll need if you do *not* want to use the convenient instructions above and
instead build from source:
* gcc/g++ new enough to be compatible with pybind11
(see their `FAQ `_)
* `numpy `_, and
* an OpenCL implementation. (See this `howto `_ for how to get one.)
Links
-----
* `Documentation `__ (read how things work)
* `Conda Forge `_ (download binary packages for Linux, macOS, Windows)
* `Python package index `_ (download releases)
* `C. Gohlke's Windows binaries `_ (download Windows binaries)
* `Github `_ (get latest source code, file bugs)
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1601404046.0
pyopencl-2021.2.13/README_SETUP.txt 0000644 0001750 0001750 00000002102 00000000000 016141 0 ustar 00andreas andreas Hi, welcome.
This Python package uses aksetup for installation, which means that
installation should be easy and quick.
If you don't want to continue reading, just try the regular
./configure.py --help
./configure.py --some-options
make
sudo make install
That should do the trick. (By the way: If a config option says "several ok",
then you may specify several values, separated by commas.)
aksetup also supports regular distutils installation, without using
configure:
python setup.py build
sudo python setup.py install
In this case, configuration is obtained from files in this order:
/etc/aksetup-defaults.py
$HOME/.aksetup-defaults.py
$PACKAGEDIR/siteconf.py
Once you've run configure, you can copy options from your siteconf.py file to
one of these files, and you won't ever have to configure them again manually.
In fact, you may pass the options "--update-user" and "--update-global" to
configure, and it will automatically update these files for you.
This is particularly handy if you want to perform an unattended or automatic
installation via easy_install.
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1625636073.0
pyopencl-2021.2.13/aksetup_helper.py 0000644 0001750 0001750 00000076320 00000000000 017065 0 ustar 00andreas andreas import sys
try:
from setuptools import Extension
from setuptools.command.build_ext import ( # noqa: N812
build_ext as BaseBuildExtCommand)
except ImportError:
class Extension:
pass
class BaseBuildExtCommand:
pass
def count_down_delay(delay):
from time import sleep
while delay:
sys.stdout.write("Continuing in %d seconds... \r" % delay)
sys.stdout.flush()
delay -= 1
sleep(1)
print("")
DASH_SEPARATOR = 75 * "-"
def setup(*args, **kwargs):
from setuptools import setup
try:
setup(*args, **kwargs)
except KeyboardInterrupt:
raise
except SystemExit:
raise
except Exception:
print(DASH_SEPARATOR)
print("Sorry, your build failed. Try rerunning configure.py with "
"different options.")
print(DASH_SEPARATOR)
raise
def get_numpy_incpath():
from imp import find_module
# avoid actually importing numpy, it screws up distutils
file, pathname, descr = find_module("numpy")
from os.path import join
return join(pathname, "core", "include")
class NumpyExtension(Extension):
# nicked from
# http://mail.python.org/pipermail/distutils-sig/2007-September/008253.html
# solution by Michael Hoffmann
def __init__(self, *args, **kwargs):
Extension.__init__(self, *args, **kwargs)
self._include_dirs = self.include_dirs
del self.include_dirs # restore overwritten property
def get_additional_include_dirs(self):
return [get_numpy_incpath()]
def get_include_dirs(self):
return self._include_dirs + self.get_additional_include_dirs()
def set_include_dirs(self, value):
self._include_dirs = value
def del_include_dirs(self):
pass
include_dirs = property(get_include_dirs, set_include_dirs, del_include_dirs)
class ExtensionUsingNumpy(Extension):
"""Unlike :class:`NumpyExtension`, this class does not require numpy to be
importable upon extension module creation, allowing ``setup_requires=["numpy"]``
to work. On the other hand, it requires the use of::
setup(...,
cmdclass={'build_ext': NumpyBuildExtCommand})
or
setup(...,
cmdclass={'build_ext': PybindBuildExtCommand})
"""
class NumpyBuildExtCommand(BaseBuildExtCommand):
def build_extension(self, extension):
# We add the numpy include dir right before building the
# extension, in order to avoid having to import numpy when
# the setup script is imported, which would prevent
# installation before manual installation of numpy.
if isinstance(extension, ExtensionUsingNumpy):
numpy_incpath = get_numpy_incpath()
if numpy_incpath not in extension.include_dirs:
extension.include_dirs.append(numpy_incpath)
BaseBuildExtCommand.build_extension(self, extension)
# {{{ tools
def flatten(lst):
"""For an iterable of sub-iterables, generate each member of each
sub-iterable in turn, i.e. a flattened version of that super-iterable.
Example: Turn [[a,b,c],[d,e,f]] into [a,b,c,d,e,f].
"""
for sublist in lst:
for j in sublist:
yield j
def humanize(sym_str):
words = sym_str.lower().replace("_", " ").split(" ")
return " ".join([word.capitalize() for word in words])
# }}}
# {{{ siteconf handling
def get_config(schema=None, warn_about_no_config=True):
if schema is None:
from setup import get_config_schema
schema = get_config_schema()
if (not schema.have_config() and not schema.have_global_config()
and warn_about_no_config):
print("*************************************************************")
print("*** I have detected that you have not run configure.py.")
print("*************************************************************")
print("*** Additionally, no global config files were found.")
print("*** I will go ahead with the default configuration.")
print("*** In all likelihood, this will not work out.")
print("*** ")
print("*** See README_SETUP.txt for more information.")
print("*** ")
print("*** If the build does fail, just re-run configure.py with the")
print("*** correct arguments, and then retry. Good luck!")
print("*************************************************************")
print("*** HIT Ctrl-C NOW IF THIS IS NOT WHAT YOU WANT")
print("*************************************************************")
count_down_delay(delay=10)
config = expand_options(schema.read_config())
schema.update_config_from_and_modify_command_line(config, sys.argv)
return config
def hack_distutils(debug=False, fast_link=True, what_opt=3):
# hack distutils.sysconfig to eliminate debug flags
# stolen from mpi4py
def remove_prefixes(optlist, bad_prefixes):
for bad_prefix in bad_prefixes:
for i, flag in enumerate(optlist):
if flag.startswith(bad_prefix):
optlist.pop(i)
break
return optlist
if not sys.platform.lower().startswith("win"):
from distutils import sysconfig
cvars = sysconfig.get_config_vars()
bad_prefixes = ["-g", "-O", "-Wstrict-prototypes", "-DNDEBUG"]
cflags = cvars.get("OPT")
if cflags:
cflags = remove_prefixes(cflags.split(), bad_prefixes)
if debug:
cflags.append("-g")
else:
if what_opt is None:
pass
else:
cflags.append("-O%s" % what_opt)
cflags.append("-DNDEBUG")
cvars["OPT"] = str.join(" ", cflags)
cflags = cvars.get("CONFIGURE_CFLAGS")
if cflags:
cflags = remove_prefixes(cflags.split(), bad_prefixes)
cvars["CONFIGURE_CFLAGS"] = str.join(" ", cflags)
if "BASECFLAGS" in cvars:
cvars["CFLAGS"] = cvars["BASECFLAGS"] + " " + cvars.get("OPT", "")
else:
assert "CFLAGS" in cvars
if fast_link:
for varname in ["LDSHARED", "BLDSHARED"]:
ldsharedflags = cvars.get(varname)
if ldsharedflags:
ldsharedflags = remove_prefixes(ldsharedflags.split(),
["-Wl,-O"])
cvars[varname] = str.join(" ", ldsharedflags)
# }}}
# {{{ configure guts
def default_or(a, b):
if a is None:
return b
else:
return a
def expand_str(s, options):
import re
def my_repl(match):
sym = match.group(1)
try:
repl = options[sym]
except KeyError:
from os import environ
repl = environ[sym]
return expand_str(repl, options)
return re.subn(r"\$\{([a-zA-Z0-9_]+)\}", my_repl, s)[0]
def expand_value(v, options):
if isinstance(v, str):
return expand_str(v, options)
elif isinstance(v, list):
result = []
for i in v:
try:
exp_i = expand_value(i, options)
except Exception:
pass
else:
result.append(exp_i)
return result
else:
return v
def expand_options(options):
return dict(
(k, expand_value(v, options)) for k, v in options.items())
class ConfigSchema:
def __init__(self, options, conf_file="siteconf.py", conf_dir="."):
self.optdict = dict((opt.name, opt) for opt in options)
self.options = options
self.conf_dir = conf_dir
self.conf_file = conf_file
from os.path import expanduser
self.user_conf_file = expanduser("~/.aksetup-defaults.py")
if not sys.platform.lower().startswith("win"):
self.global_conf_file = "/etc/aksetup-defaults.py"
else:
self.global_conf_file = None
def get_conf_file(self):
import os
return os.path.join(self.conf_dir, self.conf_file)
def set_conf_dir(self, conf_dir):
self.conf_dir = conf_dir
def get_default_config(self):
return dict((opt.name, opt.default) for opt in self.options)
def read_config_from_pyfile(self, filename):
result = {}
filevars = {}
infile = open(filename, "r")
try:
contents = infile.read()
finally:
infile.close()
exec(compile(contents, filename, "exec"), filevars)
for key, value in filevars.items():
if key in self.optdict:
result[key] = value
return result
def update_conf_file(self, filename, config):
result = {}
filevars = {}
try:
exec(compile(open(filename, "r").read(), filename, "exec"), filevars)
except IOError:
pass
if "__builtins__" in filevars:
del filevars["__builtins__"]
for key, value in config.items():
if value is not None:
filevars[key] = value
keys = list(filevars.keys())
keys.sort()
outf = open(filename, "w")
for key in keys:
outf.write("%s = %s\n" % (key, repr(filevars[key])))
outf.close()
return result
def update_user_config(self, config):
self.update_conf_file(self.user_conf_file, config)
def update_global_config(self, config):
if self.global_conf_file is not None:
self.update_conf_file(self.global_conf_file, config)
def get_default_config_with_files(self):
result = self.get_default_config()
import os
confignames = []
if self.global_conf_file is not None:
confignames.append(self.global_conf_file)
confignames.append(self.user_conf_file)
for fn in confignames:
if os.access(fn, os.R_OK):
result.update(self.read_config_from_pyfile(fn))
return result
def have_global_config(self):
import os
result = os.access(self.user_conf_file, os.R_OK)
if self.global_conf_file is not None:
result = result or os.access(self.global_conf_file, os.R_OK)
return result
def have_config(self):
import os
return os.access(self.get_conf_file(), os.R_OK)
def update_from_python_snippet(self, config, py_snippet, filename):
filevars = {}
exec(compile(py_snippet, filename, "exec"), filevars)
for key, value in filevars.items():
if key in self.optdict:
config[key] = value
elif key == "__builtins__":
pass
else:
raise KeyError("invalid config key in %s: %s" % (
filename, key))
def update_config_from_and_modify_command_line(self, config, argv):
cfg_prefix = "--conf:"
i = 0
while i < len(argv):
arg = argv[i]
if arg.startswith(cfg_prefix):
del argv[i]
self.update_from_python_snippet(
config, arg[len(cfg_prefix):], "")
else:
i += 1
return config
def read_config(self):
import os
cfile = self.get_conf_file()
result = self.get_default_config_with_files()
if os.access(cfile, os.R_OK):
with open(cfile, "r") as inf:
py_snippet = inf.read()
self.update_from_python_snippet(result, py_snippet, cfile)
return result
def add_to_configparser(self, parser, def_config=None):
if def_config is None:
def_config = self.get_default_config_with_files()
for opt in self.options:
default = default_or(def_config.get(opt.name), opt.default)
opt.add_to_configparser(parser, default)
def get_from_configparser(self, options):
result = {}
for opt in self.options:
result[opt.name] = opt.take_from_configparser(options)
return result
def write_config(self, config):
outf = open(self.get_conf_file(), "w")
for opt in self.options:
value = config[opt.name]
if value is not None:
outf.write("%s = %s\n" % (opt.name, repr(config[opt.name])))
outf.close()
def make_substitutions(self, config):
return dict((opt.name, opt.value_to_str(config[opt.name]))
for opt in self.options)
class Option(object):
def __init__(self, name, default=None, help=None):
self.name = name
self.default = default
self.help = help
def as_option(self):
return self.name.lower().replace("_", "-")
def metavar(self):
last_underscore = self.name.rfind("_")
return self.name[last_underscore+1:]
def get_help(self, default):
result = self.help
if self.default:
result += " (default: %s)" % self.value_to_str(
default_or(default, self.default))
return result
def value_to_str(self, default):
return default
def add_to_configparser(self, parser, default=None):
default = default_or(default, self.default)
default_str = self.value_to_str(default)
parser.add_option(
"--" + self.as_option(), dest=self.name,
default=default_str,
metavar=self.metavar(), help=self.get_help(default))
def take_from_configparser(self, options):
return getattr(options, self.name)
class Switch(Option):
def add_to_configparser(self, parser, default=None):
if not isinstance(self.default, bool):
raise ValueError("Switch options must have a default")
if default is None:
default = self.default
option_name = self.as_option()
if default:
option_name = "no-" + option_name
action = "store_false"
else:
action = "store_true"
parser.add_option(
"--" + option_name,
dest=self.name,
help=self.get_help(default),
default=default,
action=action)
class StringListOption(Option):
def value_to_str(self, default):
if default is None:
return None
return ",".join([str(el).replace(",", r"\,") for el in default])
def get_help(self, default):
return Option.get_help(self, default) + " (several ok)"
def take_from_configparser(self, options):
opt = getattr(options, self.name)
if opt is None:
return None
else:
if opt:
import re
sep = re.compile(r"(?