Ejemplo n.º 1
0
def test_angelapreference():
    # check default args
    pref = angelaPreference(1. / 3, 'docs')
    assert not pref.validator(1)
    assert pref.docs == 'docs'
    assert pref.default == 1. / 3
    assert pref.representor(pref.default) == repr(1. / 3)
Ejemplo n.º 2
0
def test_str_repr():
    # Just test whether str and repr do not throw an error and return something
    gp = angelaGlobalPreferences()
    gp.register_preferences('main',
                            'main category',
                            name=angelaPreference(True, 'some preference'))

    assert len(str(gp))
    assert len(repr(gp))
    assert len(str(gp.main))
    assert len(repr(gp.main))
Ejemplo n.º 3
0
def test_preference_name_checking():
    '''
    Test that you cannot set illegal preference names.
    '''
    gp = angelaGlobalPreferences()

    # Name that starts with an underscore
    with pytest.raises(PreferenceError):
        gp.register_preferences('dummy',
                                'dummy doc',
                                _notalegalname=angelaPreference(
                                    True, 'some preference'))

    # Name that clashes with a method name
    with pytest.raises(PreferenceError):
        gp.register_preferences('dummy',
                                'dummy doc',
                                update=angelaPreference(
                                    True, 'some preference'))

    gp.register_preferences('a',
                            'dummy doc',
                            b=angelaPreference(True, 'some preference'))

    #Trying to register a subcategory that would shadow a preference
    with pytest.raises(PreferenceError):
        gp.register_preferences('a.b',
                                'dummy doc',
                                name=angelaPreference(True, 'some preference'))

    gp.register_preferences('b.c',
                            'dummy doc',
                            name=angelaPreference(True, 'some preference'))

    #Trying to register a preference that clashes with an existing category
    with pytest.raises(PreferenceError):
        gp.register_preferences('b',
                                'dummy doc',
                                c=angelaPreference(True, 'some preference'))
Ejemplo n.º 4
0
              'ERROR': logging.ERROR,
              'WARNING': logging.WARNING,
              'INFO': logging.INFO,
              'DEBUG': logging.DEBUG,
              'DIAGNOSTIC': DIAGNOSTIC}
logging.addLevelName(DIAGNOSTIC, 'DIAGNOSTIC')

if 'logging' not in prefs.pref_register:
    # Duplicate import of this module can happen when the documentation is built
    prefs.register_preferences('logging', 'Logging system preferences',
        delete_log_on_exit=angelaPreference(
            default=True,
            docs='''
            Whether to delete the log and script file on exit.
            
            If set to ``True`` (the default), log files (and the copy of the main
            script) will be deleted after the angela process has exited, unless an
            uncaught exception occurred. If set to ``False``, all log files will be
            kept.
            ''',
            ),
        file_log_level=angelaPreference(
            default='DIAGNOSTIC',
            docs='''
            What log level to use for the log written to the log file.
            
            In case file logging is activated (see `logging.file_log`), which log
            level should be used for logging. Has to be one of CRITICAL, ERROR,
            WARNING, INFO, DEBUG or DIAGNOSTIC.
            ''',
            validator=log_level_validator),
                                            get_numpy_dtype)
from ...targets import codegen_targets
from ...cpp_prefs import get_compiler_and_args
from .extension_manager import cython_extension_manager

__all__ = ['CythonCodeObject']

logger = get_logger(__name__)

# Preferences
prefs.register_preferences(
    'codegen.runtime.cython',
    'Cython runtime codegen preferences',
    multiprocess_safe=angelaPreference(default=True,
                                       docs='''
        Whether to use a lock file to prevent simultaneous write access
        to cython .pyx and .so files.
        '''),
    cache_dir=angelaPreference(
        default=None,
        validator=lambda x: x is None or isinstance(x, str),
        docs='''
        Location of the cache directory for Cython files. By default,
        will be stored in a ``angela_extensions`` subdirectory
        where Cython inline stores its temporary files
        (the result of ``get_cython_cache_dir()``).
        '''),
    delete_source_files=angelaPreference(default=True,
                                         docs='''
        Whether to delete source files after compiling. The Cython
        source files can take a significant amount of disk space, and
Ejemplo n.º 6
0
def test_angelaglobalpreferences():
    # test that pre-setting a nonexistent preference in a subsequently
    # existing base name raises an error at the correct point
    gp = angelaGlobalPreferences()

    # This shouldn't work, in user code only registered preferences can be set
    with pytest.raises(PreferenceError):
        gp.__setitem__('a.b', 5)

    # This uses the method that is used when reading preferences from a file
    gp._set_preference('a.b', 5)
    gp._set_preference('a.c', 5)
    with pytest.raises(PreferenceError):
        gp.register_preferences('a',
                                'docs for a',
                                b=angelaPreference(5, 'docs for b'))
    # test that post-setting a nonexistent preference in an existing base
    # name raises an error
    gp = angelaGlobalPreferences()
    gp.register_preferences('a',
                            'docs for a',
                            b=angelaPreference(5, 'docs for b'))
    with pytest.raises(PreferenceError):
        gp.__setitem__('a.c', 5)
    # Test pre and post-setting some correct names but valid and invalid values
    gp = angelaGlobalPreferences()
    gp._set_preference('a.b', 5)
    gp.register_preferences(
        'a',
        'docs for a',
        b=angelaPreference(5, 'docs for b'),
        c=angelaPreference(1 * volt, 'docs for c'),
        d=angelaPreference(0, 'docs for d', validator=lambda x: x >= 0),
        e=angelaPreference(float64,
                           'docs for e',
                           representor=lambda x: x.__name__),
    )
    assert gp['a.c'] == 1 * volt
    gp['a.c'] = 2 * volt
    with pytest.raises(PreferenceError):
        gp.__setitem__('a.c', 3 * amp)
    gp['a.d'] = 2.0
    with pytest.raises(PreferenceError):
        gp.__setitem__('a.d', -1)
    gp['a.e'] = float32
    with pytest.raises(PreferenceError):
        gp.__setitem__('a.e', 0)
    # test backup and restore
    gp._backup()
    gp['a.d'] = 10
    assert gp['a.d'] == 10
    gp._restore()
    assert gp['a.d'] == 2.0
    # test that documentation and as_file generation runs without error, but
    # don't test for values because we might change the organisation of it
    assert len(gp.get_documentation())
    gp.as_file
    gp.defaults_as_file
    # test that reading a preference file works as expected
    pref_file = StringIO('''
        # a comment
        a.b = 10
        [a]
        c = 5*volt
        d = 1
        e = float64
        ''')
    gp.read_preference_file(pref_file)
    assert gp['a.b'] == 10
    assert gp['a.c'] == 5 * volt
    assert gp['a.d'] == 1
    assert gp['a.e'] == float64
    # test that reading a badly formatted prefs file fails
    pref_file = StringIO('''
        [a
        b = 10
        ''')
    with pytest.raises(PreferenceError):
        gp.read_preference_file(pref_file)
    # test that reading a well formatted prefs file with an invalid value fails
    pref_file = StringIO('''
        a.b = 'oh no, not a string'
        ''')
    with pytest.raises(PreferenceError):
        gp.read_preference_file(pref_file)
    # assert that writing the prefs to a file and loading them gives the
    # same values
    gp = angelaGlobalPreferences()
    gp.register_preferences(
        'a',
        'docs for a',
        b=angelaPreference(5, 'docs for b'),
    )
    gp._backup()
    gp['a.b'] = 10
    str_modified = gp.as_file
    str_defaults = gp.defaults_as_file
    gp['a.b'] = 15
    gp.read_preference_file(StringIO(str_modified))
    assert gp['a.b'] == 10
    gp.read_preference_file(StringIO(str_defaults))
    assert gp['a.b'] == 5
    # check that load_preferences works, but nothing about its values
    gp = angelaGlobalPreferences()
    gp.load_preferences()
from angela2.core.functions import Function

from ...codeobject import CodeObject, constant_or_scalar, check_compiler_kwds

from ...templates import Templater
from ...generators.numpy_generator import NumpyCodeGenerator
from ...targets import codegen_targets

__all__ = ['NumpyCodeObject']

# Preferences
prefs.register_preferences('codegen.runtime.numpy',
                           'Numpy runtime codegen preferences',
                           discard_units=angelaPreference(default=False,
                                                          docs='''
        Whether to change the namespace of user-specifed functions to remove
        units.
        '''))


class LazyArange(Iterable):
    '''
    A class that can be used as a `~numpy.arange` replacement (with an implied
    step size of 1) but does not actually create an array of values until
    necessary. It is somewhat similar to the ``range()`` function in Python 3,
    but does not use a generator. It is tailored to a special use case, the
    ``_vectorisation_idx`` variable in numpy templates, and not meant for
    general use. The ``_vectorisation_idx`` is used for stateless function
    calls such as ``rand()`` and for the numpy codegen target determines the
    number of values produced by such a call. This will often be the number of
    neurons or synapses, and this class avoids creating a new array of that size
Ejemplo n.º 8
0
def test_preference_name_access():
    '''
    Test various ways of accessing preferences
    '''

    gp = angelaGlobalPreferences()

    gp.register_preferences('main',
                            'main category',
                            name=angelaPreference(True, 'some preference'))
    gp.register_preferences('main.sub',
                            'subcategory',
                            name2=angelaPreference(True, 'some preference'))

    gp.register_preferences('main.sub_no_pref',
                            'subcategory without preference')
    gp.register_preferences('main.sub_no_pref.sub',
                            'deep subcategory',
                            name=angelaPreference(True, 'some preference'))

    # Keyword based access
    assert gp['main.name']
    assert gp['main.sub.name2']
    assert gp['main.sub_no_pref.sub.name']
    gp['main.name'] = False
    gp['main.sub.name2'] = False
    gp['main.sub_no_pref.sub.name'] = False

    # Attribute based access
    assert not gp.main.name  # we set it to False above
    assert not gp.main.sub.name2
    assert not gp.main.sub_no_pref.sub.name
    gp.main.name = True
    gp.main.sub.name2 = True
    gp.main.sub_no_pref.sub.name = True

    # Mixed access
    assert gp.main['name']
    assert gp['main'].name
    assert gp.main['sub'].name2
    assert gp['main'].sub['name2']

    # Accessing categories
    assert isinstance(gp['main'], angelaGlobalPreferencesView)
    assert isinstance(gp['main.sub'], angelaGlobalPreferencesView)
    assert isinstance(gp.main, angelaGlobalPreferencesView)
    assert isinstance(gp.main.sub, angelaGlobalPreferencesView)

    # Setting categories shouldn't work
    with pytest.raises(PreferenceError):
        gp.__setitem__('main', None)
    with pytest.raises(PreferenceError):
        gp.__setattr__('main', None)
    with pytest.raises(PreferenceError):
        gp.main.__setitem__('sub', None)
    with pytest.raises(PreferenceError):
        gp.main.__setattr__('sub', None)

    # Neither should deleting categories or preferences
    with pytest.raises(PreferenceError):
        gp.__delitem__('main')
    with pytest.raises(PreferenceError):
        gp.__delattr__('main')
    with pytest.raises(PreferenceError):
        gp.main.__delitem__('name')
    with pytest.raises(PreferenceError):
        gp.main.__delattr__('name')
    with pytest.raises(PreferenceError):
        gp.main.__delitem__('sub')
    with pytest.raises(PreferenceError):
        gp.main.__delattr__('sub')

    #Errors for accessing non-existing preferences
    with pytest.raises(KeyError):
        gp['main.doesnotexist']
    with pytest.raises(KeyError):
        gp['nonexisting.name']
    with pytest.raises(KeyError):
        gp.main.doesnotexist
    with pytest.raises(KeyError):
        gp.nonexisting.name

    # Check dictionary functionality
    for name, value in gp.items():
        assert gp[name] == value

    for name, value in gp.main.items():
        assert gp.main[name] == value

    assert len(gp) == 3  # three preferences in total
    assert len(gp['main']) == 3  # all preferences are in the main category
    assert len(gp['main.sub']) == 1  # one preference in main.sub

    assert 'main.name' in gp
    assert 'name' in gp['main']
    assert 'name2' in gp['main.sub']
    assert not 'name' in gp['main.sub']

    gp['main.name'] = True
    gp.update({'main.name': False})
    assert not gp['main.name']

    gp.main.update({'name': True})
    assert gp['main.name']

    # Class based functionality
    assert 'main' in dir(gp)
    assert 'sub' in dir(gp.main)
    assert 'name' in dir(gp.main)

    # Check that the fiddling with getattr and setattr did not destroy the
    # access to standard attributes
    assert len(gp.prefs)
    assert gp.main._basename == 'main'
Ejemplo n.º 9
0
                               'has to be existing directory' % (val)))
    if any(not os.path.isfile(os.path.join(val, 'gsl', filename))
           for filename in ['gsl_odeiv2.h', 'gsl_errno.h', 'gsl_matrix.h']):
        raise PreferenceError(('Illegal value for GSL directory: %s, '
                               'has to contain gsl_odeiv2.h, gsl_errno.h '
                               'and gsl_matrix.h' % (val)))
    return True


prefs.register_preferences(
    'GSL',
    'Directory containing GSL code',
    directory=angelaPreference(
        validator=valid_gsl_dir,
        docs=
        ("Set path to directory containing GSL header files (gsl_odeiv2.h etc.)"
         "\nIf this directory is already in Python's include (e.g. because of "
         "conda installation), this path can be set to None."),
        default=None))


class GSLCodeGenerator(object):
    '''
    GSL code generator.

    Notes
    -----
    Approach is to first let the already existing code generator for a target
    language do the bulk of the translating from abstract_code to actual code.
    This generated code is slightly adapted to render it GSL compatible.
    The most critical part here is that the vector_code that is normally
    elif dtype == numpy.bool_ or dtype is bool:
        dtype = 'char'
    else:
        raise ValueError("dtype " + str(dtype) + " not known.")
    return dtype


# Preferences
prefs.register_preferences(
    'codegen.generators.cpp',
    'C++ codegen preferences',
    restrict_keyword=angelaPreference(
        default='__restrict',
        docs='''
        The keyword used for the given compiler to declare pointers as restricted.
        
        This keyword is different on different compilers, the default works for
        gcc and MSVS.
        ''',
    ),
    flush_denormals=angelaPreference(
        default=False,
        docs='''
        Adds code to flush denormals to zero.
        
        The code is gcc and architecture specific, so may not compile on all
        platforms. The code, for reference is::

            #define CSR_FLUSH_TO_ZERO         (1 << 15)
            unsigned csr = __builtin_ia32_stmxcsr();
            csr |= CSR_FLUSH_TO_ZERO;
            msvc_arch_flag = '/arch:SSE'
        if 'sse2' in flags:
            msvc_arch_flag = '/arch:SSE2'
        if 'avx' in flags:
            msvc_arch_flag = '/arch:AVX'
        if 'avx2' in flags:
            msvc_arch_flag = '/arch:AVX2'

# Preferences
prefs.register_preferences(
    'codegen.cpp',
    'C++ compilation preferences',
    compiler = angelaPreference(
        default='',
        docs='''
        Compiler to use (uses default if empty)
        
        Should be gcc or msvc.
        '''
        ),
    extra_compile_args=angelaPreference(
        default=None,
        validator=lambda v: True,
        docs='''
        Extra arguments to pass to compiler (if None, use either
        ``extra_compile_args_gcc`` or ``extra_compile_args_msvc``).
        '''
        ),
    extra_compile_args_gcc=angelaPreference(
        default=['-w', '-O3', '-ffast-math', '-fno-finite-math-only', '-march=native', '-std=c++11'],
        docs='''
        Extra compile arguments to pass to GCC compiler
__all__ = []


def dtype_repr(dtype):
    return dtype.__name__


def default_float_dtype_validator(dtype):
    return dtype in [float32, float64]


prefs.register_preferences('core', 'Core angela preferences',
    default_float_dtype=angelaPreference(
        default=float64,
        docs='''
        Default dtype for all arrays of scalars (state variables, weights, etc.).
        ''',
        representor=dtype_repr,
        validator=default_float_dtype_validator,
        ),
    default_integer_dtype=angelaPreference(
        default=int32,
        docs='''
        Default dtype for all arrays of integer scalars.
        ''',
        representor=dtype_repr,
        ),
    outdated_dependency_error=angelaPreference(
        default=True,
        docs='''
        Whether to raise an error for outdated dependencies (``True``) or just
        a warning (``False``).
from .codeobject import CodeObject

# Preferences
prefs.register_preferences(
    'codegen',
    'Code generation preferences',
    target=angelaPreference(
        default='auto',
        docs='''
        Default target for code generation.
        
        Can be a string, in which case it should be one of:
        
        * ``'auto'`` the default, automatically chose the best code generation
          target available.
        * ``'cython'``, uses the Cython package to generate C++ code. Needs a
          working installation of Cython and a C++ compiler.
        * ``'numpy'`` works on all platforms and doesn't need a C compiler but
          is often less efficient.
        
        Or it can be a ``CodeObject`` class.
        ''',
        validator=lambda target: isinstance(target, str) or issubclass(
            target, CodeObject),
    ),
    string_expression_target=angelaPreference(
        default='numpy',
        docs='''
        Default target for the evaluation of string expressions (e.g. when
        indexing state variables). Should normally not be changed from the
        default numpy target, because the overhead of compiling code is not