diff --git a/pyccel/parser/base.py b/pyccel/parser/base.py index 54b50bd3f3..c6565a8f81 100644 --- a/pyccel/parser/base.py +++ b/pyccel/parser/base.py @@ -89,8 +89,8 @@ def get_filename_from_import(module, input_folder=''): while filename.startswith('/'): filename = folder_above + filename[1:] - filename_pyh = '{}.pyh'.format(filename) - filename_py = '{}.py'.format(filename) + filename_pyh = f'{filename}.pyh' + filename_py = f'{filename}.py' poss_filename_pyh = os.path.join( input_folder, filename_pyh ) poss_filename_py = os.path.join( input_folder, filename_py ) @@ -106,8 +106,8 @@ def get_filename_from_import(module, input_folder=''): source = """.""".join(i for i in module.split(""".""")[:-1]) _module = module.split(""".""")[-1] - filename_pyh = '{}.pyh'.format(_module) - filename_py = '{}.py'.format(_module) + filename_pyh = f'{_module}.pyh' + filename_py = f'{_module}.py' try: package = importlib.import_module(source) @@ -402,6 +402,8 @@ def exit_loop_scope(self): def create_new_class_scope(self, name, **kwargs): """ + Create a new scope for a Python class. + Create a new Scope object for a Python class with the given name, and attach any decorators' information to the scope. The new scope is a child of the current one, and can be accessed from the dictionary of @@ -416,6 +418,13 @@ def create_new_class_scope(self, name, **kwargs): name : str Function's name, used as a key to retrieve the new scope. + **kwargs : dict + A dictionary containing any additional arguments of the new scope. + + Returns + ------- + Scope + The scope for the class. """ child = self.scope.new_child_scope(name, **kwargs) self._scope = child @@ -431,11 +440,13 @@ def dump(self, filename=None): """ Dump the current ast using Pickle. - Parameters - ---------- - filename: str - output file name. if not given `name.pyccel` will be used and placed - in the Pyccel directory ($HOME/.pyccel) + Dump the current ast using Pickle. + + Parameters + ---------- + filename : str + Output file name. if not given `name.pyccel` will be used and placed + in the Pyccel directory ($HOME/.pyccel). """ if self._created_from_pickle: return @@ -450,7 +461,7 @@ def dump(self, filename=None): if ext != '.pyh': return - name = '{}.pyccel'.format(name) + name = f'{name}.pyccel' filename = os.path.join(path, name) # check extension @@ -460,7 +471,6 @@ def dump(self, filename=None): import pickle import hashlib -# print('>>> home = ', os.environ['HOME']) # ... # we are only exporting the AST. @@ -478,13 +488,15 @@ def dump(self, filename=None): warnings.warn("Can't pickle files on a read-only system. Please run `sudo pyccel-init`") def load(self, filename=None): - """ Load the current ast using Pickle. + """ + Load the current ast using Pickle. - Parameters - ---------- - filename: str - output file name. if not given `name.pyccel` will be used and placed - in the Pyccel directory ($HOME/.pyccel) + Load the current ast using Pickle. + + Parameters + ---------- + filename : str, optional + The name of the pickled file. if not given `name.pyccel` will be used. """ # ... @@ -500,7 +512,7 @@ def load(self, filename=None): if ext != '.pyh': return - name = '{}.pyccel'.format(name) + name = f'{name}.pyccel' filename = os.path.join(path, name) if not filename.split(""".""")[-1] == 'pyccel': diff --git a/pyccel/parser/parser.py b/pyccel/parser/parser.py index 5f5b85a1ca..9317581771 100644 --- a/pyccel/parser/parser.py +++ b/pyccel/parser/parser.py @@ -17,6 +17,19 @@ # TODO [AR, 18.11.2018] to be modified as a function # TODO [YG, 28.01.2020] maybe pass filename to the parse method? class Parser(object): + """ + A wrapper class which handles dependencies between the syntactic and semantic parsers. + + A wrapper class which handles dependencies between the syntactic and semantic parsers. + + Parameters + ---------- + filename : str + The name of the file being translated. + + **kwargs : dict + Any keyword arguments for BasicParser. + """ def __init__(self, filename, **kwargs): @@ -181,24 +194,26 @@ def append_son(self, son): self._sons.append(son) def parse_sons(self, d_parsers_by_filename, verbose=False): - """Recursive algorithm for syntax analysis on a given file and its + """ + Parse the files on which this file is dependent. + + Recursive algorithm for syntax analysis on a given file and its dependencies. This function always terminates with an dict that contains parsers for all involved files. - Parameters - ---------- - d_parsers_by_filename : dict - A dictionary of parsed sons. + Parameters + ---------- + d_parsers_by_filename : dict + A dictionary of parsed sons. - verbose: bool - Determine the verbosity. - - Results - ------- - d_parsers: dict - The updated dictionary of parsed sons. + verbose : bool, default=False + Set the verbosity. + Returns + ------- + dict + The updated dictionary of parsed sons. """ imports = self.imports @@ -207,7 +222,7 @@ def parse_sons(self, d_parsers_by_filename, verbose=False): not_treated = [i for i in source_to_filename.values() if i not in treated] for filename in not_treated: if verbose: - print ('>>> treating :: {}'.format(filename)) + print ('>>> treating :: ', filename) # get the absolute path corresponding to source if filename in d_parsers_by_filename: @@ -228,25 +243,33 @@ def parse_sons(self, d_parsers_by_filename, verbose=False): return d_parsers - def _annotate_sons(self, **settings): + def _annotate_sons(self, verbose = False): + """ + Annotate any dependencies of the file currently being parsed. - verbose = settings.pop('verbose', False) + Annotate any dependencies of the file currently being parsed. + + Parameters + ---------- + verbose : bool, default=False + Indicates if the treatment should be run in verbose mode. + """ # we first treat sons that have no imports for p in self.sons: if not p.sons: if verbose: - print ('>>> treating :: {}'.format(p.filename)) - p.annotate(**settings) + print ('>>> treating :: ', p.filename) + p.annotate() # finally we treat the remaining sons recursively for p in self.sons: if p.sons: if verbose: - print ('>>> treating :: {}'.format(p.filename)) - p.annotate(**settings) + print ('>>> treating :: ', p.filename) + p.annotate() #============================================================================== diff --git a/pyccel/parser/scope.py b/pyccel/parser/scope.py index e14c83b059..497377acb2 100644 --- a/pyccel/parser/scope.py +++ b/pyccel/parser/scope.py @@ -127,7 +127,7 @@ def new_child_scope(self, name, **kwargs): """ ps = kwargs.pop('parent_scope', self) if ps is not self: - raise ValueError("A child of {} cannot have a parent {}".format(self, ps)) + raise ValueError(f"A child of {self} cannot have a parent {ps}") child = Scope(name=name, **kwargs, parent_scope = self) @@ -308,21 +308,17 @@ def create_new_loop_scope(self): return new_scope def insert_variable(self, var, name = None): - """ Add a variable to the current scope + """ + Add a variable to the current scope. + + Add a variable to the current scope. Parameters ---------- - var : Variable - The variable to be inserted into the current scope - name : str - The name of the variable in the python code - Default : var.name - python_scope : bool - If true then we assume that python scoping applies. - In this case variables declared in loops exist beyond - the end of the loop. Otherwise variables may be local - to loops - Default : True + var : Variable + The variable to be inserted into the current scope. + name : str, default=var.name + The name of the variable in the Python code. """ if var.name == '_': raise ValueError("A temporary variable should have a name generated by Scope.get_new_name") @@ -336,7 +332,7 @@ def insert_variable(self, var, name = None): self.parent_scope.insert_variable(var, name) else: if name in self._locals['variables']: - raise RuntimeError('New variable {} already exists in scope'.format(name)) + raise RuntimeError(f'New variable {name} already exists in scope') if name == '_': self._temporary_variables.append(var) else: @@ -645,17 +641,24 @@ def get_new_name(self, current_name = None): def get_temporary_variable(self, dtype_or_var, name = None, **kwargs): """ - Get a temporary variable + Get a temporary variable. + + Get a temporary variable. Parameters ---------- dtype_or_var : str, DataType, Variable In the case of a string of DataType: The type of the Variable to be created - In the case of a Variable: a Variable which will be cloned to set all the Variable properties - name : str - The requested name for the new variable - kwargs : dict - See Variable keyword arguments + In the case of a Variable: a Variable which will be cloned to set all the Variable properties. + name : str, optional + The requested name for the new variable. + **kwargs : dict + See Variable keyword arguments. + + Returns + ------- + Variable + The temporary variable. """ assert isinstance(name, (str, type(None))) name = self.get_new_name(name) @@ -667,8 +670,21 @@ def get_temporary_variable(self, dtype_or_var, name = None, **kwargs): return var def get_expected_name(self, start_name): - """ Get a name with no collisions, ideally the provided name. - The provided name should already exist in the symbols + """ + Get a name with no collisions. + + Get a name with no collisions, ideally the provided name. + The provided name should already exist in the symbols. + + Parameters + ---------- + start_name : str + The name which was used in the Python code. + + Returns + ------- + PyccelSymbol + The name which will be used in the generated code. """ if start_name == '_': return self.get_new_name() @@ -677,7 +693,7 @@ def get_expected_name(self, start_name): elif self.parent_scope: return self.parent_scope.get_expected_name(start_name) else: - raise RuntimeError("{} does not exist in scope".format(start_name)) + raise RuntimeError(f"{start_name} does not exist in scope") def create_product_loop_scope(self, inner_scope, n_loops): """ Create a n_loops loop scopes such that the innermost loop @@ -749,15 +765,28 @@ def add_son(self, name, son): self._sons_scopes[name] = son def get_python_name(self, name): - """ Get the name used in the original python code from the - name used by the variable + """ + Get the name used in the original Python code. + + Get the name used in the original Python code from the name used + by the variable that was created in the parser. + + Parameters + ---------- + name : PyccelSymbol | str + The name of the Variable in the generated code. + + Returns + ------- + str + The name of the Variable in the original code. """ if name in self._original_symbol: return self._original_symbol[name] elif self.parent_scope: return self.parent_scope.get_python_name(name) else: - raise RuntimeError("Can't find {} in scope".format(name)) + raise RuntimeError(f"Can't find {name} in scope") @property def python_names(self): diff --git a/pyccel/parser/syntactic.py b/pyccel/parser/syntactic.py index f1e9bb451f..c39c85ea09 100644 --- a/pyccel/parser/syntactic.py +++ b/pyccel/parser/syntactic.py @@ -541,7 +541,7 @@ def _visit_Constant(self, stmt): return LiteralEllipsis() else: - raise NotImplementedError('Constant type {} not recognised'.format(type(stmt.value))) + raise NotImplementedError(f'Constant type {type(stmt.value)} not recognised') def _visit_Name(self, stmt): name = PyccelSymbol(stmt.id) @@ -1109,7 +1109,7 @@ def _visit_Call(self, stmt): func_attr = FunctionCall(func.name[-1], args) func = DottedName(*func.name[:-1], func_attr) else: - raise NotImplementedError(' Unknown function type {}'.format(str(type(func)))) + raise NotImplementedError(f' Unknown function type {type(func)}') return func