From 2cb91df43d0d758f4c3d9f5ba3bab0b364c81685 Mon Sep 17 00:00:00 2001 From: Marcel Stimberg Date: Wed, 26 Jul 2023 18:29:33 +0200 Subject: [PATCH] =?UTF-8?q?Update=20to=20Python=20=E2=89=A5=203.9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- brian2genn/device.py | 124 ++++++++++----------- brian2genn/genn_generator.py | 30 ++--- brian2genn/insyn.py | 2 +- brian2genn/preferences.py | 2 +- brian2genn/sphinxext/briandoc.py | 8 +- brian2genn/sphinxext/docscrape.py | 38 +++---- brian2genn/sphinxext/docscrape_sphinx.py | 14 +-- brian2genn/sphinxext/examplefinder.py | 6 +- brian2genn/sphinxext/generate_examples.py | 5 +- brian2genn/sphinxext/generate_reference.py | 7 +- 10 files changed, 116 insertions(+), 120 deletions(-) diff --git a/brian2genn/device.py b/brian2genn/device.py index 718bea42..d4dcc737 100644 --- a/brian2genn/device.py +++ b/brian2genn/device.py @@ -11,9 +11,7 @@ from pkg_resources import parse_version from subprocess import call, check_call, CalledProcessError import inspect -from builtins import map, range from collections import defaultdict -from six import iteritems, iterkeys, itervalues import tempfile import itertools import numpy @@ -81,7 +79,7 @@ def freeze(code, ns): Support function for substituting constant values. ''' # this is a bit of a hack, it should be passed to the template somehow - for k, v in iteritems(ns): + for k, v in ns.items(): if (isinstance(v, Variable) and v.scalar and v.constant and v.read_only): @@ -144,7 +142,7 @@ def extract_source_variables(variables, varname, smvariables): that is of instance `Subexpression`. ''' identifiers = get_identifiers(variables[varname].expr) - for vnm, var in iteritems(variables): + for vnm, var in variables.items(): if vnm in identifiers: if var in defaultclock.variables.values(): raise NotImplementedError('Recording an expression that depends on ' @@ -175,7 +173,7 @@ def find_executable(executable): return f return None -class DelayedCodeObject(object): +class DelayedCodeObject: ''' Dummy class used for delaying the CodeObject creation of stateupdater, thresholder, and resetter of a NeuronGroup (which will all be merged into a @@ -197,7 +195,7 @@ def after_run(self): pass -class neuronModel(object): +class neuronModel: ''' Class that contains all relevant information of a neuron model. ''' @@ -219,7 +217,7 @@ def __init__(self): self.support_code_lines = [] -class spikegeneratorModel(object): +class spikegeneratorModel: ''' Class that contains all relevant information of a spike generator group. ''' @@ -229,7 +227,7 @@ def __init__(self): self.N = 0 -class synapseModel(object): +class synapseModel: ''' Class that contains all relevant information about a synapse model. ''' @@ -257,7 +255,7 @@ def __init__(self): self.delay = 0 self.summed_variables= None -class spikeMonitorModel(object): +class spikeMonitorModel: ''' Class the contains all relevant information about a spike monitor. ''' @@ -268,7 +266,7 @@ def __init__(self): self.notSpikeGeneratorGroup = True -class rateMonitorModel(object): +class rateMonitorModel: ''' CLass that contains all relevant information about a rate monitor. ''' @@ -279,7 +277,7 @@ def __init__(self): self.notSpikeGeneratorGroup = True -class stateMonitorModel(object): +class stateMonitorModel: ''' Class that contains all relvant information about a state monitor. ''' @@ -308,7 +306,7 @@ class GeNNDevice(CPPStandaloneDevice): generated code to functional GeNN code, assisted by the "GeNN language". ''' def __init__(self): - super(GeNNDevice, self).__init__() + super().__init__() # Remember whether we have already passed the "run" statement self.run_statement_used = False self.network_schedule = ['start', 'synapses', 'groups', 'thresholds', @@ -369,7 +367,7 @@ def insert_code(self, slot, code): The C++ code that should be inserted. ''' # Only overwritten so that we can have custom documentation - super(GeNNDevice, self).insert_code(slot, code) + super().insert_code(slot, code) def activate(self, build_on_run=True, **kwargs): new_prefs = {'codegen.generators.cpp.restrict_keyword': '__restrict', @@ -378,7 +376,7 @@ def activate(self, build_on_run=True, **kwargs): 'groups', 'thresholds', 'resets', 'end']} changed = [] - for new_pref, new_value in iteritems(new_prefs): + for new_pref, new_value in new_prefs.items(): if prefs[new_pref] != new_value: changed.append(new_pref) prefs[new_pref] = new_value @@ -389,7 +387,7 @@ def activate(self, build_on_run=True, **kwargs): 'different device later in the same script: ' '{}'.format(', '.join(changed)), once=True) prefs._backup() - super(GeNNDevice, self).activate(build_on_run, **kwargs) + super().activate(build_on_run, **kwargs) def code_object_class(self, codeobj_class=None, *args, **kwds): if codeobj_class is None: @@ -408,7 +406,7 @@ def code_object(self, owner, name, abstract_code, variables, template_name, # Add an extra code object that executes the scalar code of # the run_regularly operation (will be directly called from # engine.cpp) - codeobj = super(GeNNDevice, self).code_object(owner, name, + codeobj = super().code_object(owner, name, abstract_code, variables, 'stateupdate', @@ -465,7 +463,7 @@ def code_object(self, owner, name, abstract_code, variables, template_name, elif template_name in ['reset', 'synapses', 'stateupdate', 'threshold']: codeobj_class = GeNNCodeObject - codeobj = super(GeNNDevice, self).code_object(owner, name, + codeobj = super().code_object(owner, name, abstract_code, variables, template_name, @@ -492,7 +490,7 @@ def code_object(self, owner, name, abstract_code, variables, template_name, mrl_template_name= 'max_row_length_generator' else: mrl_template_name='max_row_length_array' - codeobj = super(GeNNDevice, self).code_object(owner, mrl_name, + codeobj = super().code_object(owner, mrl_name, abstract_code, variables, mrl_template_name, @@ -508,7 +506,7 @@ def code_object(self, owner, name, abstract_code, variables, template_name, self.max_row_length_include.append('#include "code_objects/%s.cpp"' % codeobj.name) self.max_row_length_run_calls.append('_run_%s();' % mrl_name) - codeobj = super(GeNNDevice, self).code_object(owner, name, + codeobj = super().code_object(owner, name, abstract_code, variables, template_name, @@ -548,7 +546,7 @@ def fill_with_array(self, var, arr): 'this warning', name_suffix='lastspike_inf', once=True) arr = numpy.array(-1e4) - super(GeNNDevice, self).fill_with_array(var, arr) + super().fill_with_array(var, arr) def variableview_set_with_index_array(self, variableview, item, value, check_units): @@ -559,7 +557,7 @@ def variableview_set_with_index_array(self, variableview, item, 'synapses (heterogeneous delays are not ' 'supported) as an argument to the ' 'Synapses initializer.') - super(GeNNDevice, self).variableview_set_with_index_array(variableview, + super().variableview_set_with_index_array(variableview, item, value, check_units) @@ -691,7 +689,7 @@ def make_main_lines(self): raise TypeError("Unknown main queue function type " + func) # generate the finalisations - for codeobj in itervalues(self.code_objects): + for codeobj in self.code_objects.values(): if hasattr(codeobj.code, 'main_finalise'): main_lines.append(codeobj.code.main_finalise) return main_lines @@ -760,14 +758,14 @@ def build(self, directory='GeNNworkspace', compile=True, run=True, if isinstance(self.arange_arrays, dict): arange_arrays = sorted([(var, start) for var, start in - iteritems(self.arange_arrays)], + self.arange_arrays.items()], key=lambda var_start: var_start[0].name) else: arange_arrays = self.arange_arrays # write the static arrays - for code_object in itervalues(self.code_objects): - for var in itervalues(code_object.variables): + for code_object in self.code_objects.values(): + for var in code_object.variables.values(): if isinstance(var, Function): self._insert_func_namespace(var, code_object, self.static_arrays) @@ -784,7 +782,7 @@ def build(self, directory='GeNNworkspace', compile=True, run=True, main_lines = self.make_main_lines() # assemble the model descriptions: - objects = dict((obj.name, obj) for obj in net_objects) + objects = {obj.name: obj for obj in net_objects} neuron_groups = [obj for obj in net_objects if isinstance(obj, NeuronGroup)] poisson_groups = [obj for obj in net_objects if @@ -841,9 +839,9 @@ def build(self, directory='GeNNworkspace', compile=True, run=True, self.max_row_length_code_objects.values()): cpp_code = getattr(code_object.code, 'cpp_file', code_object.code) if 'namespace {' in cpp_code: - cpp_code = cpp_code.replace('namespace {', 'namespace {} {{'.format(code_object.name)) + cpp_code = cpp_code.replace('namespace {', f'namespace {code_object.name} {{') cpp_code = cpp_code.replace('using namespace brian;', - 'using namespace brian;\nusing namespace {};'.format(code_object.name)) + f'using namespace brian;\nusing namespace {code_object.name};') if hasattr(code_object.code, 'cpp_file'): code_object.code.cpp_file = cpp_code else: @@ -902,9 +900,9 @@ def build(self, directory='GeNNworkspace', compile=True, run=True, def generate_code_objects(self, writer): # Generate data for non-constant values code_object_defs = defaultdict(list) - for codeobj in itervalues(self.code_objects): + for codeobj in self.code_objects.values(): lines = [] - for k, v in iteritems(codeobj.variables): + for k, v in codeobj.variables.items(): if isinstance(v, ArrayVariable): try: if isinstance(v, DynamicArrayVariable): @@ -921,7 +919,7 @@ def generate_code_objects(self, writer): dyn_array_name=dyn_array_name) lines.append(line) else: - lines.append('const int _num%s = %s;' % (k, v.size)) + lines.append(f'const int _num{k} = {v.size};') except TypeError: pass for line in lines: @@ -930,7 +928,7 @@ def generate_code_objects(self, writer): if not line in code_object_defs[codeobj.name]: code_object_defs[codeobj.name].append(line) # Generate the code objects - for codeobj in itervalues(self.code_objects): + for codeobj in self.code_objects.values(): ns = codeobj.variables # TODO: fix these freeze/CONSTANTS hacks somehow - they work but not elegant. if ((codeobj.template_name not in ['stateupdate', 'threshold', @@ -953,8 +951,8 @@ def generate_code_objects(self, writer): def generate_max_row_length_code_objects(self, writer): # Generate data for non-constant values code_object_defs = defaultdict(set) - for codeobj in itervalues(self.max_row_length_code_objects): - for k, v in iteritems(codeobj.variables): + for codeobj in self.max_row_length_code_objects.values(): + for k, v in codeobj.variables.items(): if isinstance(v, ArrayVariable): try: if isinstance(v, DynamicArrayVariable): @@ -977,11 +975,11 @@ def generate_max_row_length_code_objects(self, writer): line = line.format(c_type=c_data_type(v.dtype), array_name=array_name, size=v.size) - code_object_defs[codeobj.name].add('const int _num%s = %s;' % (k, v.size)) + code_object_defs[codeobj.name].add(f'const int _num{k} = {v.size};') except TypeError: pass - for codeobj in itervalues(self.max_row_length_code_objects): + for codeobj in self.max_row_length_code_objects.values(): ns = codeobj.variables # TODO: fix these freeze/CONSTANTS hacks somehow - they work but not elegant. code = freeze(codeobj.code, ns) @@ -1000,8 +998,8 @@ def run(self, directory, use_GPU, with_output): print('executing genn binary %s ...' % where) pref_vars = prefs['devices.cpp_standalone.run_environment_variables'] - for key, value in itertools.chain(iteritems(pref_vars), - iteritems(self.run_environment_variables)): + for key, value in itertools.chain(pref_vars.items(), + self.run_environment_variables.items()): if key in os.environ and os.environ[key] != value: logger.info('Overwriting environment variable ' '"{key}"'.format(key=key), @@ -1019,7 +1017,7 @@ def run(self, directory, use_GPU, with_output): cwd=directory) self.has_been_run = True last_run_info = open( - os.path.join(directory, 'results/last_run_info.txt'), 'r').read() + os.path.join(directory, 'results/last_run_info.txt')).read() self._last_run_time, self._last_run_completed_fraction = map(float, last_run_info.split()) @@ -1076,10 +1074,10 @@ def compile_source(self, debug, directory, use_GPU): version_file = os.path.join(genn_path, 'version.txt') if os.path.exists(version_file): try: - with open(version_file, 'r') as f: + with open(version_file) as f: genn_version = parse_version(f.read().strip()) logger.debug('GeNN version: %s' % genn_version) - except (OSError, IOError) as ex: + except OSError as ex: logger.debug('Getting version from %s/version.txt ' 'failed: %s' % (genn_path, str(ex))) @@ -1105,7 +1103,7 @@ def compile_source(self, debug, directory, use_GPU): with std_silent(debug): if os.sys.platform == 'win32': # Make sure that all environment variables are upper case - env = {k.upper() : v for k, v in iteritems(env)} + env = {k.upper() : v for k, v in env.items()} # If there is vcvars command to call, start cmd with that cmd = '' @@ -1115,7 +1113,7 @@ def compile_source(self, debug, directory, use_GPU): # Otherwise, update environment, again ensuring # that all variables are upper case else: - env.update({k.upper() : v for k, v in iteritems(msvc_env)}) + env.update({k.upper() : v for k, v in msvc_env.items()}) # Add start of call to genn-buildmodel buildmodel_cmd = os.path.join(genn_path, 'bin', @@ -1131,7 +1129,7 @@ def compile_source(self, debug, directory, use_GPU): # **HACK** argument list syntax to check_call doesn't support quoting arguments to batch # files so we have to build argument string manually(https://bugs.python.org/issue23862) wdir = os.getcwd() - cmd += ' -i "%s;%s;%s"' % (wdir, os.path.join(wdir, directory), + cmd += ' -i "{};{};{}"'.format(wdir, os.path.join(wdir, directory), os.path.join(wdir, directory, 'brianlib','randomkit')) cmd += ' magicnetwork_model.cpp' @@ -1180,7 +1178,7 @@ def add_array_variable(self, model, varname, variable): model.variablescope[varname] = 'brian' def add_array_variables(self, model, owner): - for varname, variable in iteritems(owner.variables): + for varname, variable in owner.variables.items(): if varname in ['_spikespace', 't', 'dt']: pass elif getattr(variable.owner, 'name', None) != owner.name: @@ -1191,7 +1189,7 @@ def add_array_variables(self, model, owner): def process_poisson_groups(self, objects, poisson_groups): for obj in poisson_groups: # throw error if events other than spikes are used - event_keys = list(iterkeys(obj.events)) + event_keys = list(obj.events.keys()) if (len(event_keys) > 1 or (len(event_keys) == 1 and event_keys[0] != 'spike')): raise NotImplementedError( @@ -1206,7 +1204,7 @@ def process_poisson_groups(self, objects, poisson_groups): support_lines = [] codeobj = obj.thresholder['spike'].codeobj lines = neuron_model.thresh_cond_lines - for k, v in iteritems(codeobj.variables): + for k, v in codeobj.variables.items(): if k != 'dt' and isinstance(v, Constant): if k not in neuron_model.parameters: self.add_parameter(neuron_model, k, v) @@ -1226,7 +1224,7 @@ def process_poisson_groups(self, objects, poisson_groups): def process_neuron_groups(self, neuron_groups, objects): for obj in neuron_groups: # throw error if events other than spikes are used - event_keys = list(iterkeys(obj.events)) + event_keys = list(obj.events.keys()) if len(event_keys) > 1 or (len(event_keys) == 1 and event_keys[0] != 'spike'): raise NotImplementedError( 'Brian2GeNN does not support events that are not spikes') @@ -1303,7 +1301,7 @@ def process_neuron_groups(self, neuron_groups, objects): 'not_refractory = False'] # Find PoissonInputs targetting this NeuronGroup - poisson_inputs = [o for o in itervalues(objects) + poisson_inputs = [o for o in objects.values() if isinstance(o, PoissonInput) and o.group.name == obj.name] @@ -1317,12 +1315,12 @@ def process_neuron_groups(self, neuron_groups, objects): combined_variables.update(codeobj.variables) combined_variable_indices.update(codeobj.variable_indices) - for code_block in iterkeys(combined_abstract_code): + for code_block in combined_abstract_code.keys(): combined_abstract_code[code_block] = '\n'.join(combined_abstract_code[code_block]) - if any(len(ac) for ac in itervalues(combined_abstract_code)): + if any(len(ac) for ac in combined_abstract_code.values()): assert stateupdater_name, 'No StateUpdater found in object.' - codeobj = super(GeNNDevice, self).code_object(obj, stateupdater_name, + codeobj = super().code_object(obj, stateupdater_name, combined_abstract_code, combined_variables.copy(), 'neuron_code', @@ -1336,7 +1334,7 @@ def process_neuron_groups(self, neuron_groups, objects): # part of `generate_code_objects`. del self.code_objects[codeobj.name] - for k, v in iteritems(codeobj.variables): + for k, v in codeobj.variables.items(): if k != 'dt' and isinstance(v, Constant): if k not in neuron_model.parameters: self.add_parameter(neuron_model, k, v) @@ -1467,7 +1465,7 @@ def process_synapses(self, synapse_groups, objects): addVar = code_generator.translate_expression(addVar) kwds = code_generator.determine_keywords() identifiers = get_identifiers(addVar) - for k, v in iteritems(codeobj.variables): + for k, v in codeobj.variables.items(): if k in ['_spikespace', 't', 'dt'] or k not in identifiers: pass else: @@ -1492,10 +1490,10 @@ def process_synapses(self, synapse_groups, objects): def collect_synapses_variables(self, synapse_model, pathway, codeobj): identifiers = set() - for code in itervalues(codeobj.code): + for code in codeobj.code.values(): identifiers |= get_identifiers(code) indices = codeobj.variable_indices - for k, v in iteritems(codeobj.variables): + for k, v in codeobj.variables.items(): if k in ['_spikespace', 't', 'dt'] or k not in identifiers: pass elif isinstance(v, Constant): @@ -1511,7 +1509,7 @@ def collect_synapses_variables(self, synapse_model, pathway, codeobj): else: index = indices[k] if (pathway in ['pre', 'post'] and - index == '_{}synaptic_idx'.format(pathway)): + index == f'_{pathway}synaptic_idx'): raise NotImplementedError('brian2genn does not support ' 'references to {pathway}-' 'synaptic variables in ' @@ -1620,7 +1618,7 @@ def process_state_monitors(self, directory, state_monitors, writer): sm.isSynaptic = False sm.N = src.variables['N'].get_value() for varname in obj.record_variables: - if src.variables[varname] in itervalues(defaultclock.variables): + if src.variables[varname] in defaultclock.variables.values(): raise NotImplementedError('Recording the time t or the ' 'timestep dt is currently not ' 'supported in Brian2GeNN') @@ -1713,7 +1711,7 @@ def generate_model_source(self, writer, main_lines, use_GPU): if ('_synapses_create_' not in line) and ('monitor' not in line): dry_main_lines.append(line) codeobj_inc= [] - for codeobj in itervalues(self.code_objects): + for codeobj in self.code_objects.values(): if ('group_variable' in codeobj.name): codeobj_inc.append('#include "code_objects/'+codeobj.name+'.cpp"') model_tmp = GeNNCodeObject.templater.model(None, None, @@ -1840,7 +1838,7 @@ def generate_objects_source(self, arange_arrays, net, static_array_specs, synapses, writer): # ------------------------------------------------------------------------------ # create the objects.cpp and objects.h code - the_objects = list(itervalues(self.code_objects)) + the_objects = list(self.code_objects.values()) arr_tmp = GeNNUserCodeObject.templater.objects( None, None, array_specs=self.arrays, @@ -1862,7 +1860,7 @@ def generate_objects_source(self, arange_arrays, net, static_array_specs, def copy_source_files(self, writer, directory): # Copies brianlib, spikequeue and randomkit - super(GeNNDevice, self).copy_source_files(writer, directory) + super().copy_source_files(writer, directory) # Copy the b2glib directory b2glib_dir = os.path.join( @@ -1884,7 +1882,7 @@ def network_run(self, net, duration, report=None, report_period=10 * second, if kwds: logger.warn(('Unsupported keyword argument(s) provided for run: ' - + '%s') % ', '.join(iterkeys(kwds))) + + '%s') % ', '.join(kwds.keys())) if self.run_duration is not None: raise NotImplementedError( @@ -1907,7 +1905,7 @@ def network_run(self, net, duration, report=None, report_period=10 * second, # We need to store all objects, since MagicNetwork.after_run will clear # Network.objects to avoid memory leaks self.net_objects = _get_all_objects(self.net.objects) - super(GeNNDevice, self).network_run(net=net, duration=duration, + super().network_run(net=net, duration=duration, report=report, report_period=report_period, namespace=namespace, diff --git a/brian2genn/genn_generator.py b/brian2genn/genn_generator.py index 52ee9baa..b103503b 100644 --- a/brian2genn/genn_generator.py +++ b/brian2genn/genn_generator.py @@ -104,7 +104,7 @@ class GeNNCodeGenerator(CodeGenerator): _floordiv_support_code + _pow_support_code) def __init__(self, *args, **kwds): - super(GeNNCodeGenerator, self).__init__(*args, **kwds) + super().__init__(*args, **kwds) self.c_data_type = c_data_type @property @@ -126,7 +126,7 @@ def get_array_name(var, access_data=True): return device.get_array_name(var, access_data=False) def translate_expression(self, expr): - for varname, var in iteritems(self.variables): + for varname, var in self.variables.items(): if isinstance(var, Function): try: impl_name = var.implementations[self.codeobj_class].name @@ -179,9 +179,9 @@ def translate_to_write_arrays(self, statements): def translate_one_statement_sequence(self, statements, scalar=False): if len(statements) and self.template_name=='synapses': _, _, _, conditional_write_vars = self.arrays_helper(statements) - vars_pre = [k for k, v in iteritems(self.variable_indices) if v=='_presynaptic_idx'] - vars_syn = [k for k, v in iteritems(self.variable_indices) if v=='_idx'] - vars_post = [k for k, v in iteritems(self.variable_indices) if v=='_postsynaptic_idx'] + vars_pre = [k for k, v in self.variable_indices.items() if v=='_presynaptic_idx'] + vars_syn = [k for k, v in self.variable_indices.items() if v=='_idx'] + vars_post = [k for k, v in self.variable_indices.items() if v=='_postsynaptic_idx'] if '_pre_codeobject' in self.name: post_write_var, statements = check_pre_code(self, statements, vars_pre, vars_syn, vars_post, @@ -213,7 +213,7 @@ def _add_user_function(self, varname, variable): funccode = impl.get_code(self.owner) if isinstance(funccode, str): # Rename references to any dependencies if necessary - for dep_name, dep in iteritems(impl.dependencies): + for dep_name, dep in impl.dependencies.items(): dep_impl = dep.implementations[self.codeobj_class] dep_impl_name = dep_impl.name if dep_impl_name is None: @@ -227,18 +227,18 @@ def _add_user_function(self, varname, variable): # create global variables and assign to them in the main # code func_namespace = impl.get_namespace(self.owner) or {} - for ns_key, ns_value in iteritems(func_namespace): + for ns_key, ns_value in func_namespace.items(): if hasattr(ns_value, 'dtype'): if ns_value.shape == (): - raise NotImplementedError(( + raise NotImplementedError( 'Directly replace scalar values in the function ' - 'instead of providing them via the namespace')) + 'instead of providing them via the namespace') type_str = c_data_type(ns_value.dtype) + '*' else: # e.g. a function type_str = 'py::object' - support_code.append('static {0} _namespace{1};'.format(type_str, + support_code.append('static {} _namespace{};'.format(type_str, ns_key)) - pointers.append('_namespace{0} = {1};'.format(ns_key, ns_key)) + pointers.append(f'_namespace{ns_key} = {ns_key};') support_code.append(deindent(funccode.get('support_code', ''))) hash_defines.append(deindent(funccode.get('hashdefine_code', ''))) @@ -246,7 +246,7 @@ def _add_user_function(self, varname, variable): dep_pointers = [] dep_support_code = [] if impl.dependencies is not None: - for dep_name, dep in iteritems(impl.dependencies): + for dep_name, dep in impl.dependencies.items(): if dep_name not in self.variables: # do not add a dependency twice self.variables[dep_name] = dep dep_impl = dep.implementations[self.codeobj_class] @@ -275,7 +275,7 @@ def determine_keywords(self): # Again, do the import here to avoid a circular dependency. from brian2.devices.device import get_device device = get_device() - for varname, var in iteritems(self.variables): + for varname, var in self.variables.items(): if isinstance(var, ArrayVariable): # This is the "true" array name, not the restricted pointer. array_name = device.get_array_name(var) @@ -284,7 +284,7 @@ def determine_keywords(self): continue if get_var_ndim(var, 1) > 1: continue # multidimensional (dynamic) arrays have to be treated differently - line = '{0}* {1} {2} = {3};'.format(self.c_data_type(var.dtype), + line = '{}* {} {} = {};'.format(self.c_data_type(var.dtype), self.restrict, pointer_name, array_name) @@ -295,7 +295,7 @@ def determine_keywords(self): user_functions = [] support_code = [] hash_defines = [] - for varname, variable in list(iteritems(self.variables)): + for varname, variable in list(self.variables.items()): if isinstance(variable, Function): hd, ps, sc, uf = self._add_user_function(varname, variable) user_functions.extend(uf) diff --git a/brian2genn/insyn.py b/brian2genn/insyn.py index 4dbdbbd7..c7510e56 100644 --- a/brian2genn/insyn.py +++ b/brian2genn/insyn.py @@ -87,7 +87,7 @@ def check_pre_code(codegen, stmts, vars_pre, vars_syn, vars_post, # "write-protect" a variable during refractoriness to match Brian's semantics if stmt.var in conditional_write_vars: assert conditional_write_vars[stmt.var] == 'not_refractory' - accumulation_expr = 'int(not_refractory_post) * ({})'.format(accumulation_expr) + accumulation_expr = f'int(not_refractory_post) * ({accumulation_expr})' else: # TODO: we could support expressions like v = v + expr, but this requires some additional work # namely, for an expression like v = expr we need to check if (expr-v) when simplified reduces to diff --git a/brian2genn/preferences.py b/brian2genn/preferences.py index 876e8d2e..0a90455c 100644 --- a/brian2genn/preferences.py +++ b/brian2genn/preferences.py @@ -5,7 +5,7 @@ from brian2.core.preferences import * -class DeprecatedValidator(object): +class DeprecatedValidator: ''' 'Validator' for deprecated preferences diff --git a/brian2genn/sphinxext/briandoc.py b/brian2genn/sphinxext/briandoc.py index 5a751c00..07a38f12 100644 --- a/brian2genn/sphinxext/briandoc.py +++ b/brian2genn/sphinxext/briandoc.py @@ -86,7 +86,7 @@ def brianobj_role(role, rawtext, text, lineno, inliner, options={}, content=[]): ''' if text in prefs: linktext = text.replace('_', '-').replace('.', '-') - text = '%s ' % (text, linktext) + text = f'{text} ' # Use sphinx's cross-reference role xref = XRefRole(warn_dangling=True) return xref('std:ref', rawtext, text, lineno, inliner, options, content) @@ -221,15 +221,15 @@ def setup(app, get_doc_object_=get_doc_object): from sphinx.domains.c import CDomain from sphinx.domains.python import PythonDomain -class ManglingDomainBase(object): +class ManglingDomainBase: directive_mangling_map = {} def __init__(self, *a, **kw): - super(ManglingDomainBase, self).__init__(*a, **kw) + super().__init__(*a, **kw) self.wrap_mangling_directives() def wrap_mangling_directives(self): - for name, objtype in iteritems(self.directive_mangling_map): + for name, objtype in self.directive_mangling_map.items(): self.directives[name] = wrap_mangling_directive( self.directives[name], objtype) diff --git a/brian2genn/sphinxext/docscrape.py b/brian2genn/sphinxext/docscrape.py index d2ea93c7..60590f51 100644 --- a/brian2genn/sphinxext/docscrape.py +++ b/brian2genn/sphinxext/docscrape.py @@ -11,7 +11,7 @@ from sphinx.pycode import ModuleAnalyzer -class Reader(object): +class Reader: """A line-based string reader. """ @@ -85,7 +85,7 @@ def is_empty(self): return not ''.join(self._str).strip() -class NumpyDocString(object): +class NumpyDocString: def __init__(self, docstring, config={}): docstring = textwrap.dedent(docstring).split('\n') @@ -272,7 +272,7 @@ def _parse_summary(self): summary = self._doc.read_to_next_empty_line() summary_str = " ".join([s.strip() for s in summary]).strip() - if re.compile('^([\w., ]+=)?\s*[\w\.]+\(.*\)$').match(summary_str): + if re.compile(r'^([\w., ]+=)?\s*[\w\.]+\(.*\)$').match(summary_str): self['Signature'] = summary_str if not self._is_at_section(): self['Summary'] = self._doc.read_to_next_empty_line() @@ -312,7 +312,7 @@ def _str_indent(self, doc, indent=4): def _str_signature(self): if self['Signature']: - return [self['Signature'].replace('*','\*')] + [''] + return [self['Signature'].replace('*',r'\*')] + [''] else: return [''] @@ -333,7 +333,7 @@ def _str_param_list(self, name): if self[name]: out += self._str_header(name) for param,param_type,desc in self[name]: - out += ['%s : %s' % (param, param_type)] + out += [f'{param} : {param_type}'] out += self._str_indent(desc) out += [''] return out @@ -354,9 +354,9 @@ def _str_see_also(self, func_role): last_had_desc = True for func, desc, role in self['See Also']: if role: - link = ':%s:`%s`' % (role, func) + link = f':{role}:`{func}`' elif func_role: - link = ':%s:`%s`' % (func_role, func) + link = f':{func_role}:`{func}`' else: link = "`%s`_" % func if desc or last_had_desc: @@ -376,10 +376,10 @@ def _str_index(self): idx = self['index'] out = [] out += ['.. index:: %s' % idx.get('default','')] - for section, references in iteritems(idx): + for section, references in idx.items(): if section == 'default': continue - out += [' :%s: %s' % (section, ', '.join(references))] + out += [' :{}: {}'.format(section, ', '.join(references))] return out def __str__(self, func_role=''): @@ -432,8 +432,8 @@ def __init__(self, func, role='func', doc=None, config={}): # try to read signature argspec = inspect.getargspec(func) argspec = inspect.formatargspec(*argspec) - argspec = argspec.replace('*','\*') - signature = '%s%s' % (func_name, argspec) + argspec = argspec.replace('*',r'\*') + signature = f'{func_name}{argspec}' except TypeError: signature = '%s()' % func_name self['Signature'] = signature @@ -457,10 +457,10 @@ def __str__(self): if self._role: if self._role not in roles: print("Warning: invalid role %s" % self._role) - out += '.. %s:: %s\n \n\n' % (roles.get(self._role,''), + out += '.. {}:: {}\n \n\n'.format(roles.get(self._role,''), func_name) - out += super(FunctionDoc, self).__str__(func_role=self._role) + out += super().__str__(func_role=self._role) return out @@ -496,7 +496,7 @@ def __init__(self, cls, doc=None, modulename='', func_doc=FunctionDoc, def methods(self): if self._cls is None: return [] - methods = [name for name, func in iteritems(getattr(self._cls, '__dict__')) + methods = [name for name, func in getattr(self._cls, '__dict__').items() if ((not name.startswith('_') or name in self.extra_public_methods) and ((callable(func) and not isinstance(func, type)) or @@ -508,11 +508,11 @@ def properties(self): if self._cls is None: return [] analyzer = ModuleAnalyzer.for_module(self._cls.__module__) - instance_members = set([attr_name for (class_name, attr_name) in - iterkeys(analyzer.find_attr_docs()) - if class_name == self._cls.__name__]) - class_members = set([name for name, func in iteritems(getattr(self._cls, '__dict__')) + instance_members = {attr_name for (class_name, attr_name) in + analyzer.find_attr_docs().keys() + if class_name == self._cls.__name__} + class_members = {name for name, func in getattr(self._cls, '__dict__').items() if not name.startswith('_') and (func is None or - inspect.isdatadescriptor(func))]) + inspect.isdatadescriptor(func))} return instance_members | class_members diff --git a/brian2genn/sphinxext/docscrape_sphinx.py b/brian2genn/sphinxext/docscrape_sphinx.py index 8d5746e4..2b5ce0cb 100644 --- a/brian2genn/sphinxext/docscrape_sphinx.py +++ b/brian2genn/sphinxext/docscrape_sphinx.py @@ -36,7 +36,7 @@ def _str_param_list(self, name): out += self._str_field_list(name) out += [''] for param, param_type, desc in self[name]: - out += self._str_indent(['**%s** : %s' % (param.strip(), + out += self._str_indent(['**{}** : {}'.format(param.strip(), param_type)]) out += [''] out += self._str_indent(desc, 8) @@ -91,7 +91,7 @@ def _str_member_list(self): doc='\n'.join(desc))) if len(prefix): - autosum += [" ~%s%s" % (prefix, param)] + autosum += [f" ~{prefix}{param}"] else: autosum += [" %s" % param] @@ -117,9 +117,9 @@ def _str_member_docs(self, name): for param, _, _ in self[name]: if name == 'Methods': - out += ['.. automethod:: %s%s' % (prefix, param)] + out += [f'.. automethod:: {prefix}{param}'] elif name == 'Attributes': - out += ['.. autoattribute:: %s%s' % (prefix, param)] + out += [f'.. autoattribute:: {prefix}{param}'] out += [''] return out @@ -137,7 +137,7 @@ def _str_section(self, name): def _str_see_also(self, func_role): out = [] if self['See Also']: - see_also = super(SphinxDocString, self)._str_see_also(func_role) + see_also = super()._str_see_also(func_role) out = ['.. seealso::', ''] out += self._str_indent(see_also[2:]) return out @@ -168,13 +168,13 @@ def _str_index(self): return out out += ['.. index:: %s' % idx.get('default','')] - for section, references in iteritems(idx): + for section, references in idx.items(): if section == 'default': continue elif section == 'refguide': out += [' single: %s' % (', '.join(references))] else: - out += [' %s: %s' % (section, ','.join(references))] + out += [' {}: {}'.format(section, ','.join(references))] return out def _str_references(self): diff --git a/brian2genn/sphinxext/examplefinder.py b/brian2genn/sphinxext/examplefinder.py index cbdca201..c5b9d313 100644 --- a/brian2genn/sphinxext/examplefinder.py +++ b/brian2genn/sphinxext/examplefinder.py @@ -26,7 +26,7 @@ def get_map(environ_var, relrootdir, pattern, the_map, path_exclusions=[]): shortfnames = [os.path.relpath(fname, rootdir) for fname in fnames] exnames = [fname.replace('/', '.').replace('\\', '.').replace(pattern, '') for fname in shortfnames] for fname, shortfname, exname in zip(fnames, shortfnames, exnames): - ex = open(fname, 'r').read() + ex = open(fname).read() ids = get_identifiers(ex) for id in ids: the_map[id].append((shortfname.replace('\\', '/'), exname)) @@ -60,10 +60,10 @@ def auto_find_examples(obj, headersymbol='='): txt = txt+'\n'+headersymbol*len(txt)+'\n\n' for tutname, tutloc in tutorials: tutname = tutname.replace('.ipynb', '') - txt += '* Tutorial :doc:`%s `\n' % (tutname, tutloc) + txt += f'* Tutorial :doc:`{tutname} `\n' for exname, exloc in examples: exname = exname.replace('.py', '') - txt += '* Example :doc:`%s `\n' % (exname, exloc) + txt += f'* Example :doc:`{exname} `\n' return txt+'\n' diff --git a/brian2genn/sphinxext/generate_examples.py b/brian2genn/sphinxext/generate_examples.py index c35f0b8b..fb05c28c 100644 --- a/brian2genn/sphinxext/generate_examples.py +++ b/brian2genn/sphinxext/generate_examples.py @@ -61,7 +61,7 @@ def main(rootpath, destdir): examplesbasenames.append(filebase) relativepaths.append(relpath) outnames.append(exname) - examplescode = [open(fname, 'rU').read() for fname in examplesfnames] + examplescode = [open(fname).read() for fname in examplesfnames] examplesdocs = [] examplesafterdoccode = [] examplesdocumentablenames = [] @@ -132,7 +132,7 @@ def insert_category(category, mainpage_text): mainpage_text += ' :maxdepth: 1\n\n' curpath = '' for exname, basename in sorted(categories[category]): - mainpage_text += ' %s <%s>\n' % (basename, exname) + mainpage_text += f' {basename} <{exname}>\n' return mainpage_text mainpage_text = insert_category('', mainpage_text) @@ -145,4 +145,3 @@ def insert_category(category, mainpage_text): if __name__=='__main__': main('../../examples', '../../docs_sphinx/examples') - \ No newline at end of file diff --git a/brian2genn/sphinxext/generate_reference.py b/brian2genn/sphinxext/generate_reference.py index ddadceea..421cfa3b 100644 --- a/brian2genn/sphinxext/generate_reference.py +++ b/brian2genn/sphinxext/generate_reference.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ Automatically generate Brian's reference documentation. @@ -30,7 +29,7 @@ def makename(package, module): def write_file(name, text, destdir, suffix): """Write the output file for module/package .""" - fname = path.join(destdir, '%s.%s' % (name, suffix)) + fname = path.join(destdir, f'{name}.{suffix}') print('Creating file %s.' % fname) f = open(fname, 'w') try: @@ -42,7 +41,7 @@ def write_file(name, text, destdir, suffix): def format_heading(level, text): """Create a heading of [1, 2 or 3 supported].""" underlining = ['=', '-', '~', ][level-1] * len(text) - return '%s\n%s\n\n' % (text, underlining) + return f'{text}\n{underlining}\n\n' def format_directive(module, destdir, package=None, basename='brian2genn'): @@ -169,7 +168,7 @@ def create_package_file(root, master_package, subroot, py_files, subs, text += ' :maxdepth: 2\n\n' for sub in subs: if not is_excluded(os.path.join(root, sub), excludes): - text += ' %s.%s\n' % (makename(master_package, subroot), sub) + text += f' {makename(master_package, subroot)}.{sub}\n' text += '\n' write_file(makename(master_package, subroot), text, destdir, suffix)