Repository: pyccel/pyccel
Pull request #2252: Describe multiple compilers in the same JSON file
Author: login: EmilyBourne
Labels: name: Ready_to_merge
description: Approved by senior developer. Ready for final approval and merge
Created: 2025-03-18T11:54:00Z | Merged: 2025-03-25T10:06:01Z

* Describe multiple compilers in the same JSON file. Fixes #2242
* Let a JSON file define a compiler family with the same name as the file
* Rename parameter in `execute_pyccel` function: `compiler` -> `compiler_family`
* Remove `language` and `family` entries from dictionaries describing the default compilers 
* Update documentation about customization of compiler and use of `PYCCEL_DEFAULT_COMPILER` environment variable

By grouping the information by compiler family we remove the need to have 2 Compiler objects, but need to specify the target language in the compile command.

Linked issue #2242: Describe multiple compilers in the same JSON file
### Problem

When calling Pyccel with `--language=fortran`, two different compilers are used: in addition to the Fortran compiler, the C wrapper requires a C compiler.

If the user wants to use two unsupported compilers, or specify custom flags for both compilers, he cannot do that through a JSON file (as described [here](https://github.com/pyccel/pyccel/blob/devel/docs/compiler.md#using-an-unsupported-compiler-or-custom-compiler-flags)) because the JSON file only contains information about one compiler. 

### Example Code

Let's say that we want to accelerate a trivial `hello.py` file:
```python
def hello_world(n : int):
    for i in range(n):
        print("Hello, world!")
```

Currently, when using a JSON file with Fortran compiler specs, we get this warning:

```
$ pyccel --compiler=gnu --language=fortran --export-compile-info custom.json
$ pyccel --compiler=custom.json --language=fortran hello.py
[PATH/TO/PYCCEL]/codegen/compiling/compilers.py:96: UserWarning: Language does not match compiler. Using GNU compiler
  warnings.warn(UserWarning("Language does not match compiler. Using GNU compiler"))
```

### Proposed Solution

We should allow JSON files with information about more than one compiler. The compilers' languages must all be different from each other, and one of these languages must be C.

### Notes

This is also useful when running unit tests, which might be using different target languages, as it allows one to provide a single JSON file and then run, for example:

```
$ export PYCCEL_DEFAULT_COMPILER=custom.json
$ pytest pyccel/tests/
```

Diff:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 96fadd1fcd..902ac54b25 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -155,6 +155,7 @@ All notable changes to this project will be documented in this file.
 -   #2187 : Removed use of pickle.
 -   #2234 : Print all constant C variables with `const` specifier.
 -   #2249 : Improve installation docs and recommend virtual environment.
+-   #2242 : Change format of compiler info files.
 -   \[INTERNALS\] `FunctionDef` is annotated when it is called, or at the end of the `CodeBlock` if it is never called.
 -   \[INTERNALS\] `InlinedFunctionDef` is only annotated if it is called.
 -   \[INTERNALS\] Build `utilities.metaclasses.ArgumentSingleton` on the fly to ensure correct docstrings.
diff --git a/docs/compiler.md b/docs/compiler.md
index d48f60218e..3507d3d27f 100644
--- a/docs/compiler.md
+++ b/docs/compiler.md
@@ -21,14 +21,19 @@ epyccel(my_func, compiler='intel')
 ```
 
 It is also possible to change the default compiler family by setting the environment variable `PYCCEL_DEFAULT_COMPILER`.
+E.g.
+```shell
+export PYCCEL_DEFAULT_COMPILER='intel'
+pyccel example.py
+```
+The `--compiler` flag overrides the default compiler: if this is provided, the environment variable is ignored.
 
 ## Using an unsupported compiler or custom compiler flags
 
-Pyccel's compiler settings are described internally by a dictionary. This makes it easy for a user to define their own compiler settings. This is done via a JSON file. The location of the JSON file is passed to the _compiler_ argument of the Pyccel command line tool or `epyccel`. The JSON file must define the following:
+Pyccel's compiler settings are described internally by a dictionary. This makes it easy for a user to define their own compiler settings. This is done via a JSON file. The location of the JSON file is passed to the _compiler_ argument of the Pyccel command line tool or `epyccel`. The JSON file must define the following parameters for each of the desired languages (we advise always including c in order to compile the wrapper):
 
 -   `exec` : The name of the executable
 -   `mpi_exec` : The name of the MPI executable
--   `language` : The language handled by this compiler
 -   `module_output_flag` : This flag is only required when the language is Fortran. It specifies the flag which indicates where .mod files should be saved (e.g. '-J' for `gfortran`)
 -   `debug_flags` : A list of flags used when compiling in debug mode \[optional\]
 -   `release_flags` : A list of flags used when compiling in release mode \[optional\]
@@ -50,14 +55,25 @@ Python is considered to be an accelerator and must additionally specify `shared_
 The default compilers can provide examples compatible with your system once Pyccel has been executed at least. To export the JSON file describing your setup, use the `--export-compile-info` flag and provide a target file name.
 E.g.
 ```shell
-pyccel --compiler=intel --language=c --export-compile-info=icc.json
+pyccel --compiler=intel --export-compile-info=intel.json
 ```
 once this file has been modified it can then be used with:
 ```shell
-pyccel --compiler=icc.json --language=c <file_to_translate>
+pyccel --compiler=intel.json <file_to_translate>
+```
+Instead of using the `--compiler` flag, the environment variable `PYCCEL_DEFAULT_COMPILER` can be used to specify the path to the JSON file.
+This is especially useful in large projects where the `pyccel` command (or the `epyccel` Python function) is used many times with the same flags.
+E.g.
+```shell
+export PYCCEL_DEFAULT_COMPILER='intel.json'
+pyccel mod1.py
+pyccel mod2.py
+pyccel subdir/mod3.py
+...
 ```
+Passing the `--compiler` flag still allows the user to retrieve the normal behaviour of Pyccel.
 
-## Utilising Pyccel within Anaconda Environment
+## Utilising Pyccel within the Anaconda environment
 While Anaconda is a popular way to install Python as it simplifies package management, it can introduce challenges when working with compilers.
 
 Upon installation Anaconda modifies your shell's environment variables.
diff --git a/pyccel/codegen/compiling/compilers.py b/pyccel/codegen/compiling/compilers.py
index 89ae019e90..4d77e4585b 100644
--- a/pyccel/codegen/compiling/compilers.py
+++ b/pyccel/codegen/compiling/compilers.py
@@ -75,31 +75,25 @@ class Compiler:
     ----------
     vendor : str
                Name of the family of compilers.
-    language : str
-               Language that we are translating to.
     debug : bool
                Indicates whether we are compiling in debug mode.
     """
-    __slots__ = ('_debug','_info')
+    __slots__ = ('_debug','_compiler_info','_language_info')
     acceptable_bin_paths = None
-    def __init__(self, vendor : str, language : str, debug=False):
-        if language=='python':
-            return
+    def __init__(self, vendor : str, debug=False):
         if vendor.endswith('.json') and os.path.exists(vendor):
             with open(vendor, encoding="utf-8") as vendor_file:
-                self._info = json.load(vendor_file)
-            if language != self._info['language']:
-                warnings.warn(UserWarning("Language does not match compiler. Using GNU compiler"))
-                self._info = available_compilers[('GNU',language)]
+                self._compiler_info = json.load(vendor_file)
         else:
             if vendor not in vendors:
                 raise NotImplementedError(f"Unrecognised compiler vendor : {vendor}")
             try:
-                self._info = available_compilers[(vendor,language)]
+                self._compiler_info = available_compilers[vendor]
             except KeyError as e:
                 raise NotImplementedError("Compiler not available") from e
 
         self._debug = debug
+        self._language_info = None
 
     def _get_exec(self, accelerators):
         """
@@ -124,7 +118,7 @@ def _get_exec(self, accelerators):
             If the compiler executable cannot be found.
         """
         # Get executable
-        exec_cmd = self._info['mpi_exec'] if 'mpi' in accelerators else self._info['exec']
+        exec_cmd = self._language_info['mpi_exec'] if 'mpi' in accelerators else self._language_info['exec']
 
         # Clean conda paths out of the PATH variable
         current_path = os.environ['PATH']
@@ -144,55 +138,86 @@ def _get_exec(self, accelerators):
 
     def _get_flags(self, flags = (), accelerators = ()):
         """
-        Collect necessary compile flags
+        Collect necessary compile flags.
+
+        Collect necessary compile flags, e.g. those relevant to the
+        language or compilation mode (debug/release).
 
         Parameters
         ----------
-        flags        : iterable of str
-                       Any additional flags requested by the user
-                       / required by the file
+        flags : iterable of str
+            Any additional flags requested by the user / required by
+            the file.
         accelerators : iterable or str
-                       Accelerators used by the code
+            Accelerators used by the code.
+
+        Returns
+        -------
+        list[str]
+            A list containing the flags.
         """
         flags = list(flags)
 
         if self._debug:
-            flags.extend(self._info.get('debug_flags',()))
+            flags.extend(self._language_info.get('debug_flags',()))
         else:
-            flags.extend(self._info.get('release_flags',()))
+            flags.extend(self._language_info.get('release_flags',()))
 
-        flags.extend(self._info.get('general_flags',()))
+        flags.extend(self._language_info.get('general_flags',()))
         # M_PI is not in the standard
         #if 'python' not in accelerators:
         #    # Python sets its own standard
-        #    flags.extend(self._info.get('standard_flags',()))
+        #    flags.extend(self._language_info.get('standard_flags',()))
 
         for a in accelerators:
-            flags.extend(self._info.get(a,{}).get('flags',()))
+            flags.extend(self._language_info.get(a,{}).get('flags',()))
 
         return flags
 
-    def _get_property(self, key, prop = (), accelerators = ()):
+    def _get_property(self, key, properties = (), accelerators = ()):
         """
-        Collect necessary compile property
+        Collect necessary compile property.
+
+        Collect necessary compile properties such as include folders
+        or library directories.
 
         Parameters
         ----------
-        property     : iterable of str
-                       Any additional values of the property
-                       requested by the user / required by the file
+        key : str
+            A key describing the property of interest.
+        properties : iterable of str
+            Any additional values of the property requested by the
+            user / required by the file.
         accelerators : iterable or str
-                       Accelerators used by the code
+            Accelerators used by the code.
+
+        Returns
+        -------
+        iterable[str]
+            An iterable containing the relevant information from the
+            requested property.
+
+        Examples
+        --------
+        >>> self._get_property("libs", ("-lmy_lib",), ())
+        dict_keys(['-lmy_lib', '-lm'])
+
+        >>> self._get_property("libs", ("-lmy_lib",), ("openmp",))
+        dict_keys(['-lmy_lib', '-lm', 'gomp'])
+
+        >>> self._get_property("includes", ("/home/user/homemade-install-dir/",), ("mpi",))
+        dict_keys(['/home/user/homemade-install-dir/'])
         """
-        # Use dict keys as an ordered set
-        prop = dict.fromkeys(prop)
+        # Use a dictionary instead of a set to ensure properties are ordered by insertion
+        # The keys of the dictionary contain the values for the property of interest.
+        properties = dict.fromkeys(properties)
 
-        prop.update(dict.fromkeys(self._info.get(key,())))
+        properties.update(dict.fromkeys(self._language_info.get(key,())))
 
         for a in accelerators:
-            prop.update(dict.fromkeys(self._info.get(a,{}).get(key,())))
+            properties.update(dict.fromkeys(self._language_info.get(a,{}).get(key,())))
 
-        return prop.keys()
+        return properties.keys()
 
     def _get_includes(self, includes = (), accelerators = ()):
         """
@@ -312,7 +337,7 @@ def _get_compile_components(self, compile_obj, accelerators = ()):
 
         return exec_cmd, inc_flags, libs_flags, libdirs_flags, m_code
 
-    def compile_module(self, compile_obj, output_folder, verbose = False):
+    def compile_module(self, compile_obj, output_folder, language, verbose = False):
         """
         Compile a module.
 
@@ -326,12 +351,17 @@ def compile_module(self, compile_obj, output_folder, verbose = False):
         output_folder : str
             The folder where the result should be saved.
 
+        language : str
+            Language that we are compiling.
+
         verbose : bool
             Indicates whether additional output should be shown.
         """
         if not compile_obj.has_target_file:
             return
 
+        self._language_info = self._compiler_info[language]
+
         accelerators = compile_obj.accelerators
 
         # Get flags
@@ -345,8 +375,8 @@ def compile_module(self, compile_obj, output_folder, verbose = False):
         # Get executable
         exec_cmd = self._get_exec(accelerators)
 
-        if self._info['language'] == 'fortran':
-            j_code = (self._info['module_output_flag'], output_folder)
+        if language == 'fortran':
+            j_code = (self._language_info['module_output_flag'], output_folder)
         else:
             j_code = ()
 
@@ -357,7 +387,9 @@ def compile_module(self, compile_obj, output_folder, verbose = False):
         with compile_obj:
             self.run_command(cmd, verbose)
 
-    def compile_program(self, compile_obj, output_folder, verbose = False):
+        self._language_info = None
+
+    def compile_program(self, compile_obj, output_folder, language, verbose = False):
         """
         Compile a program.
 
@@ -371,6 +403,9 @@ def compile_program(self, compile_obj, output_folder, verbose = False):
         output_folder : str
             The folder where the result should be saved.
 
+        language : str
+            Language that we are compiling.
+
         verbose : bool
             Indicates whether additional output should be shown.
 
@@ -379,6 +414,8 @@ def compile_program(self, compile_obj, output_folder, verbose = False):
         str
             The name of the generated executable.
         """
+        self._language_info = self._compiler_info[language]
+
         accelerators = compile_obj.accelerators
 
         # get flags
@@ -389,8 +426,8 @@ def compile_program(self, compile_obj, output_folder, verbose = False):
                 self._get_compile_components(compile_obj, accelerators)
         linker_libdirs_flags = ['-Wl,-rpath' if l == '-L' else l for l in libdirs_flags]
 
-        if self._info['language'] == 'fortran':
-            j_code = (self._info['module_output_flag'], output_folder)
+        if language == 'fortran':
+            j_code = (self._language_info['module_output_flag'], output_folder)
         else:
             j_code = ()
 
@@ -402,9 +439,11 @@ def compile_program(self, compile_obj, output_folder, verbose = False):
         with compile_obj:
             self.run_command(cmd, verbose)
 
+        self._language_info = None
+
         return compile_obj.program_target
 
-    def compile_shared_library(self, compile_obj, output_folder, verbose = False, sharedlib_modname=None):
+    def compile_shared_library(self, compile_obj, output_folder, language, verbose = False, sharedlib_modname=None):
         """
         Compile a module to a shared library.
 
@@ -419,6 +458,9 @@ def compile_shared_library(self, compile_obj, output_folder, verbose = False, sh
         output_folder : str
             The folder where the result should be saved.
 
+        language : str
+            Language that we are compiling.
+
         verbose : bool
             Indicates whether additional output should be shown.
 
@@ -431,6 +473,8 @@ def compile_shared_library(self, compile_obj, output_folder, verbose = False, sh
         str
             Generated library name.
         """
+        self._language_info = self._compiler_info[language]
+
         # Ensure python options are collected
         accelerators = set(compile_obj.accelerators)
 
@@ -449,7 +493,7 @@ def compile_shared_library(self, compile_obj, output_folder, verbose = False, sh
         flags.insert(0,"-shared")
 
         # Get name of file
-        ext_suffix = self._info['python']['shared_suffix']
+        ext_suffix = self._language_info['python']['shared_suffix']
         sharedlib_modname = sharedlib_modname or compile_obj.python_module
         file_out = os.path.join(compile_obj.source_folder, sharedlib_modname+ext_suffix)
 
@@ -460,6 +504,8 @@ def compile_shared_library(self, compile_obj, output_folder, verbose = False, sh
         with compile_obj:
             self.run_command(cmd, verbose)
 
+        self._language_info = None
+
         return file_out
 
     @staticmethod
@@ -523,5 +569,5 @@ def export_compiler_info(self, compiler_export_file):
             should be printed.
         """
         with open(compiler_export_file,'w', encoding="utf-8") as out_file:
-            print(json.dumps(self._info, indent=4),
+            print(json.dumps(self._compiler_info, indent=4),
                     file=out_file)
diff --git a/pyccel/codegen/pipeline.py b/pyccel/codegen/pipeline.py
index f2e3e27a69..23ee91ad52 100644
--- a/pyccel/codegen/pipeline.py
+++ b/pyccel/codegen/pipeline.py
@@ -40,25 +40,25 @@
 # TODO: change name of variable 'module_name', as it could be a program
 # TODO [YG, 04.02.2020]: check if we should catch BaseException instead of Exception
 def execute_pyccel(fname, *,
-                   syntax_only   = False,
-                   semantic_only = False,
-                   convert_only  = False,
-                   verbose       = False,
-                   show_timings  = False,
-                   folder        = None,
-                   language      = None,
-                   compiler      = None,
-                   fflags        = None,
-                   wrapper_flags = None,
-                   includes      = (),
-                   libdirs       = (),
-                   modules       = (),
-                   libs          = (),
-                   debug         = None,
-                   accelerators  = (),
-                   output_name   = None,
+                   syntax_only     = False,
+                   semantic_only   = False,
+                   convert_only    = False,
+                   verbose         = False,
+                   show_timings    = False,
+                   folder          = None,
+                   language        = None,
+                   compiler_family = None,
+                   fflags          = None,
+                   wrapper_flags   = None,
+                   includes        = (),
+                   libdirs         = (),
+                   modules         = (),
+                   libs            = (),
+                   debug           = None,
+                   accelerators    = (),
+                   output_name     = None,
                    compiler_export_file = None,
-                   conda_warnings = 'basic'):
+                   conda_warnings  = 'basic'):
     """
     Run Pyccel on the provided code.
 
@@ -86,8 +86,9 @@ def execute_pyccel(fname, *,
         Path to the working directory. Default is the folder containing the file to be translated.
     language : str, optional
         The target language Pyccel is translating to. Default is 'fortran'.
-    compiler : str, optional
+    compiler_family : str, optional
         The compiler used to compile the generated files. Default is 'GNU'.
+        This can also contain the name of a json file describing a compiler.
     fflags : str, optional
         The flags passed to the compiler. Default is provided by the Compiler.
     wrapper_flags : str, optional
@@ -183,20 +184,19 @@ def handle_error(stage):
         language = 'fortran'
 
     # Choose Fortran compiler
-    if compiler is None:
-        compiler = os.environ.get('PYCCEL_DEFAULT_COMPILER', 'GNU')
+    if compiler_family is None:
+        compiler_family = os.environ.get('PYCCEL_DEFAULT_COMPILER', 'GNU')
 
     fflags = [] if fflags is None else fflags.split()
     wrapper_flags = [] if wrapper_flags is None else wrapper_flags.split()
 
     # Get compiler object
     Compiler.acceptable_bin_paths = get_condaless_search_path(conda_warnings)
-    src_compiler = Compiler(compiler, language, debug)
-    wrapper_compiler = Compiler(compiler, 'c', debug)
+    compiler = Compiler(compiler_family, debug)
 
     # Export the compiler information if requested
     if compiler_export_file:
-        src_compiler.export_compiler_info(compiler_export_file)
+        compiler.export_compiler_info(compiler_export_file)
         if not fname:
             return
 
@@ -316,7 +316,7 @@ def handle_error(stage):
     #         pass
     #------------------------------------------------------
     try:
-        manage_dependencies(codegen.printer.get_additional_imports(), src_compiler, pyccel_dirpath, mod_obj,
+        manage_dependencies(codegen.printer.get_additional_imports(), compiler, pyccel_dirpath, mod_obj,
                 language, verbose, convert_only)
     except NotImplementedError as error:
         errors.report(f'{error}\n'+PYCCEL_RESTRICTION_TODO,
@@ -369,8 +369,9 @@ def get_module_dependencies(parser, deps):
     start_compile_target_language = time.time()
     # Compile code to modules
     try:
-        src_compiler.compile_module(compile_obj=mod_obj,
+        compiler.compile_module(compile_obj=mod_obj,
                 output_folder=pyccel_dirpath,
+                language=language,
                 verbose=verbose)
     except Exception:
         handle_error('compilation')
@@ -383,8 +384,9 @@ def get_module_dependencies(parser, deps):
                     folder       = pyccel_dirpath,
                     dependencies = (mod_obj,),
                     prog_target  = module_name)
-            generated_program_filepath = src_compiler.compile_program(compile_obj=prog_obj,
+            generated_program_filepath = compiler.compile_program(compile_obj=prog_obj,
                     output_folder=pyccel_dirpath,
+                    language=language,
                     verbose=verbose)
 
         timers["Compilation without wrapper"] = time.time() - start_compile_target_language
@@ -395,8 +397,7 @@ def get_module_dependencies(parser, deps):
                                                language,
                                                wrapper_flags,
                                                pyccel_dirpath,
-                                               src_compiler,
-                                               wrapper_compiler,
+                                               compiler,
                                                output_name,
                                                verbose)
     except NotImplementedError as error:
diff --git a/pyccel/codegen/python_wrapper.py b/pyccel/codegen/python_wrapper.py
index 78ea3f8675..2552047664 100644
--- a/pyccel/codegen/python_wrapper.py
+++ b/pyccel/codegen/python_wrapper.py
@@ -31,8 +31,7 @@ def create_shared_library(codegen,
                           language,
                           wrapper_flags,
                           pyccel_dirpath,
-                          src_compiler,
-                          wrapper_compiler,
+                          compiler,
                           sharedlib_modname=None,
                           verbose = False):
     """
@@ -65,15 +64,9 @@ def create_shared_library(codegen,
     pyccel_dirpath : str
         The path to the directory where the files are created and compiled.
 
-    src_compiler : pyccel.codegen.compiling.compilers.Compiler
+    compiler : pyccel.codegen.compiling.compilers.Compiler
         The compiler which should be used to compile the library.
 
-    wrapper_compiler : pyccel.codegen.compiling.compilers.Compiler
-        The compiler which should be used to compile the wrapper.
-        Often this is the same as src_compiler but it may be different
-        when the language is not C to ensure that src_compiler can link
-        the appropriate language-specific libraries.
-
     sharedlib_modname : str, default: None
         The name of the shared library. The default is the name of the
         module printed by the printer.
@@ -135,8 +128,9 @@ def create_shared_library(codegen,
                 flags  = main_obj.flags,
                 dependencies = (main_obj,))
         wrapper_compile_obj.add_dependencies(bind_c_obj)
-        src_compiler.compile_module(compile_obj=bind_c_obj,
+        compiler.compile_module(compile_obj=bind_c_obj,
                 output_folder=pyccel_dirpath,
+                language=language,
                 verbose=verbose)
         timings['Bind C wrapping'] = time.time() - start_bind_c_compiling
         c_ast = bind_c_mod
@@ -173,7 +167,7 @@ def create_shared_library(codegen,
     #  Compile cwrapper_ndarrays from stdlib (if necessary)
     #--------------------------------------------------------
     start_compile_libs = time.time()
-    manage_dependencies(wrapper_codegen.get_additional_imports(), wrapper_compiler, pyccel_dirpath, wrapper_compile_obj,
+    manage_dependencies(wrapper_codegen.get_additional_imports(), compiler, pyccel_dirpath, wrapper_compile_obj,
             language, verbose)
     timings['Dependency compilation'] = (time.time() - start_compile_libs)
 
@@ -181,13 +175,15 @@ def create_shared_library(codegen,
     #         Compile code
     #---------------------------------------
     start_compile_wrapper = time.time()
-    wrapper_compiler.compile_module(wrapper_compile_obj,
-                                output_folder = pyccel_dirpath,
-                                verbose = verbose)
+    compiler.compile_module(wrapper_compile_obj,
+                            output_folder = pyccel_dirpath,
+                            language='c',
+                            verbose = verbose)
 
-    sharedlib_filepath = src_compiler.compile_shared_library(wrapper_compile_obj,
+    sharedlib_filepath = compiler.compile_shared_library(wrapper_compile_obj,
                                                     output_folder = pyccel_dirpath,
                                                     sharedlib_modname = sharedlib_modname,
+                                                    language = language,
                                                     verbose = verbose)
     timings['Wrapper compilation'] = time.time() - start_compile_wrapper
 
diff --git a/pyccel/codegen/utilities.py b/pyccel/codegen/utilities.py
index 982dc73d3a..750f03dcce 100644
--- a/pyccel/codegen/utilities.py
+++ b/pyccel/codegen/utilities.py
@@ -279,6 +279,7 @@ def generate_extension_modules(import_key, import_node, pyccel_dirpath,
 #==============================================================================
 def recompile_object(compile_obj,
                    compiler,
+                   language,
                    verbose = False):
     """
     Compile the provided file if necessary.
@@ -294,6 +295,9 @@ def recompile_object(compile_obj,
     compiler : str
         The compiler used.
 
+    language : str
+        The language in which code is being printed.
+
     verbose : bool
         Indicates whether additional information should be printed.
     """
@@ -310,6 +314,7 @@ def recompile_object(compile_obj,
     if outdated:
         compiler.compile_module(compile_obj=compile_obj,
                 output_folder=compile_obj.source_folder,
+                language=language,
                 verbose=verbose)
 
 def manage_dependencies(pyccel_imports, compiler, pyccel_dirpath, mod_obj, language, verbose, convert_only = False):
@@ -359,6 +364,7 @@ def manage_dependencies(pyccel_imports, compiler, pyccel_dirpath, mod_obj, langu
             # get the include folder path and library files
             recompile_object(stdlib,
                              compiler = compiler,
+                             language = language,
                              verbose  = verbose)
 
             mod_obj.add_dependencies(stdlib)
@@ -379,6 +385,7 @@ def manage_dependencies(pyccel_imports, compiler, pyccel_dirpath, mod_obj, langu
         for d in deps:
             recompile_object(d,
                              compiler = compiler,
+                             language = language,
                              verbose  = verbose)
             mod_obj.add_dependencies(d)
 
diff --git a/pyccel/commands/console.py b/pyccel/commands/console.py
index b65ef0344e..a75066338b 100644
--- a/pyccel/commands/console.py
+++ b/pyccel/commands/console.py
@@ -270,24 +270,24 @@ def pyccel(files=None, mpi=None, openmp=None, openacc=None, output_dir=None, com
     try:
         # TODO: prune options
         execute_pyccel(filename,
-                       syntax_only   = args.syntax_only,
-                       semantic_only = args.semantic_only,
-                       convert_only  = args.convert_only,
-                       verbose       = args.verbose,
-                       show_timings  = args.time_execution,
-                       language      = args.language,
-                       compiler      = compiler,
-                       fflags        = args.flags,
-                       wrapper_flags = args.wrapper_flags,
-                       includes      = args.includes,
-                       libdirs       = args.libdirs,
-                       modules       = (),
-                       libs          = args.libs,
-                       debug         = args.debug,
-                       accelerators  = accelerators,
-                       folder        = args.output,
+                       syntax_only     = args.syntax_only,
+                       semantic_only   = args.semantic_only,
+                       convert_only    = args.convert_only,
+                       verbose         = args.verbose,
+                       show_timings    = args.time_execution,
+                       language        = args.language,
+                       compiler_family = compiler,
+                       fflags          = args.flags,
+                       wrapper_flags   = args.wrapper_flags,
+                       includes        = args.includes,
+                       libdirs         = args.libdirs,
+                       modules         = (),
+                       libs            = args.libs,
+                       debug           = args.debug,
+                       accelerators    = accelerators,
+                       folder          = args.output,
                        compiler_export_file = compiler_export_file,
-                       conda_warnings = args.conda_warnings)
+                       conda_warnings  = args.conda_warnings)
     except PyccelError:
         sys.exit(1)
     finally:
diff --git a/pyccel/commands/epyccel.py b/pyccel/commands/epyccel.py
index 61a64e0426..f96023d97d 100644
--- a/pyccel/commands/epyccel.py
+++ b/pyccel/commands/epyccel.py
@@ -244,20 +244,20 @@ def epyccel_seq(function_or_module, *,
         try:
             # Generate shared library
             execute_pyccel(pymod_filename,
-                           verbose       = verbose,
-                           show_timings  = time_execution,
-                           language      = language,
-                           compiler      = compiler,
-                           fflags        = fflags,
-                           wrapper_flags = wrapper_flags,
-                           includes      = includes,
-                           libdirs       = libdirs,
-                           modules       = modules,
-                           libs          = libs,
-                           debug         = debug,
-                           accelerators  = accelerators,
-                           output_name   = module_name,
-                           conda_warnings= conda_warnings)
+                           verbose         = verbose,
+                           show_timings    = time_execution,
+                           language        = language,
+                           compiler_family = compiler,
+                           fflags          = fflags,
+                           wrapper_flags   = wrapper_flags,
+                           includes        = includes,
+                           libdirs         = libdirs,
+                           modules         = modules,
+                           libs            = libs,
+                           debug           = debug,
+                           accelerators    = accelerators,
+                           output_name     = module_name,
+                           conda_warnings  = conda_warnings)
         finally:
             # Change working directory back to starting point
             os.chdir(base_dirpath)
diff --git a/pyccel/compilers/default_compilers.py b/pyccel/compilers/default_compilers.py
index 8a05819d0c..7282e95ad5 100644
--- a/pyccel/compilers/default_compilers.py
+++ b/pyccel/compilers/default_compilers.py
@@ -17,7 +17,6 @@
 
 gfort_info = {'exec' : 'gfortran',
               'mpi_exec' : 'mpif90',
-              'language': 'fortran',
               'module_output_flag': '-J',
               'debug_flags': ("-fcheck=bounds","-g","-O0"),
               'release_flags': ("-O3","-funroll-loops",),
@@ -32,7 +31,6 @@
               'openacc': {
                   'flags' : ("-ta=multicore", "-Minfo=accel"),
                   },
-              'family': 'GNU',
               }
 
 if sys.platform == "win32":
@@ -45,7 +43,6 @@
 #------------------------------------------------------------
 ifort_info = {'exec' : 'ifx',
               'mpi_exec' : 'mpiifx',
-              'language': 'fortran',
               'module_output_flag': '-module',
               'debug_flags': ("-check", "bounds","-g","-O0"),
               'release_flags': ("-O3","-funroll-loops",),
@@ -58,13 +55,11 @@
               'openacc': {
                   'flags' : ("-ta=multicore", "-Minfo=accel"),
                   },
-              'family': 'intel',
               }
 
 #------------------------------------------------------------
 pgfortran_info = {'exec' : 'pgfortran',
               'mpi_exec' : 'pgfortran',
-              'language': 'fortran',
               'module_output_flag': '-module',
               'debug_flags': ("-Mbounds","-g","-O0"),
               'release_flags': ("-O3","-Munroll",),
@@ -76,13 +71,11 @@
               'openacc': {
                   'flags' : ("-acc"),
                   },
-              'family': 'PGI',
               }
 
 #------------------------------------------------------------
 nvfort_info = {'exec' : 'nvfort',
               'mpi_exec' : 'mpifort',
-              'language': 'fortran',
               'module_output_flag': '-module',
               'debug_flags': ("-Mbounds","-g","-O0"),
               'release_flags': ("-O3","-Munroll",),
@@ -94,13 +87,11 @@
               'openacc': {
                   'flags' : ("-acc"),
                   },
-              'family': 'nvidia',
               }
 
 #------------------------------------------------------------
 gcc_info = {'exec' : 'gcc',
             'mpi_exec' : 'mpicc',
-            'language': 'c',
             'debug_flags': ("-g","-O0"),
             'release_flags': ("-O3","-funroll-loops",),
             'general_flags' : ('-fPIC',),
@@ -114,7 +105,6 @@
             'openacc': {
                 'flags' : ("-ta=multicore", "-Minfo=accel"),
                 },
-            'family': 'GNU',
             }
 
 if sys.platform == "darwin":
@@ -138,7 +128,6 @@
 #------------------------------------------------------------
 icc_info = {'exec' : 'icx',
             'mpi_exec' : 'mpiicx',
-            'language': 'c',
             'debug_flags': ("-g","-O0"),
             'release_flags': ("-O3","-funroll-loops",),
             'general_flags' : ('-fPIC',),
@@ -149,13 +138,11 @@
             'openacc': {
                 'flags' : ("-ta=multicore", "-Minfo=accel"),
                 },
-            'family': 'intel',
             }
 
 #------------------------------------------------------------
 pgcc_info = {'exec' : 'pgcc',
             'mpi_exec' : 'pgcc',
-            'language': 'c',
             'debug_flags': ("-g","-O0"),
             'release_flags': ("-O3","-Munroll",),
             'general_flags' : ('-fPIC',),
@@ -166,13 +153,11 @@
             'openacc': {
                 'flags' : ("-acc"),
                 },
-            'family': 'PGI',
             }
 
 #------------------------------------------------------------
 nvc_info = {'exec' : 'nvc',
             'mpi_exec' : 'mpicc',
-            'language': 'c',
             'debug_flags': ("-g","-O0"),
             'release_flags': ("-O3","-Munroll",),
             'general_flags' : ('-fPIC',),
@@ -183,7 +168,6 @@
             'openacc': {
                 'flags' : ("-acc"),
                 },
-            'family': 'nvidia',
             }
 
 #------------------------------------------------------------
@@ -290,13 +274,13 @@ def change_to_lib_flag(lib):
 nvc_info.update(python_info)
 nvfort_info.update(python_info)
 
-available_compilers = {('GNU', 'c') : gcc_info,
-                       ('GNU', 'fortran') : gfort_info,
-                       ('intel', 'c') : icc_info,
-                       ('intel', 'fortran') : ifort_info,
-                       ('PGI', 'c') : pgcc_info,
-                       ('PGI', 'fortran') : pgfortran_info,
-                       ('nvidia', 'c') : nvc_info,
-                       ('nvidia', 'fortran') : nvfort_info}
+available_compilers = {'GNU': {'c' : gcc_info,
+                               'fortran' : gfort_info},
+                       'intel': {'c' : icc_info,
+                                 'fortran' : ifort_info},
+                       'PGI': {'c' : pgcc_info,
+                               'fortran' : pgfortran_info},
+                       'nvidia': {'c' : nvc_info,
+                                  'fortran' : nvfort_info}}
 
 vendors = ('GNU','intel','PGI','nvidia')


Reviews:
user: login: pyccel-bot[bot]
body: Good job ! Your PR is using all the code it added/changed.

state: APPROVED
author_association: NONE
submitted_at: 2025-03-20T14:56:30Z
user: login: pyccel-bot[bot]
body: Good job ! Your PR is using all the code it added/changed.

state: APPROVED
author_association: NONE
submitted_at: 2025-03-20T15:39:35Z
user: login: yguclu
body: Looks good. I have a few questions
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-21T15:36:20Z
user: login: yguclu
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-21T15:38:33Z
user: login: EmilyBourne
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-21T15:42:42Z
user: login: EmilyBourne
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-21T15:43:21Z
user: login: yguclu
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-21T15:55:56Z
user: login: EmilyBourne
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-24T10:26:33Z
user: login: EmilyBourne
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-24T10:37:52Z
user: login: EmilyBourne
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-24T10:38:56Z
user: login: yguclu
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-24T13:24:52Z
user: login: yguclu
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-24T13:35:55Z
user: login: yguclu
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-24T13:36:14Z
user: login: EmilyBourne
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-24T13:44:13Z
user: login: yguclu
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-24T13:48:02Z
user: login: EmilyBourne
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-24T13:49:30Z
user: login: yguclu
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-24T13:54:37Z
user: login: yguclu
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-24T14:17:58Z
user: login: EmilyBourne
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-24T14:21:29Z
user: login: yguclu
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-24T14:25:32Z
user: login: EmilyBourne
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-24T17:15:01Z
user: login: yguclu
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-24T18:30:18Z
user: login: yguclu
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-24T19:01:41Z
user: login: yguclu
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-25T07:55:37Z
user: login: EmilyBourne
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-25T07:58:31Z
user: login: EmilyBourne
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-25T08:00:07Z
user: login: yguclu
state: APPROVED
author_association: MEMBER
submitted_at: 2025-03-25T09:31:01Z
user: login: pyccel-bot[bot]
body: Good job ! Your PR is using all the code it added/changed.

state: APPROVED
author_association: NONE
submitted_at: 2025-03-25T09:59:06Z
user: login: pyccel-bot[bot]
body: Good job ! Your PR is using all the code it added/changed.

state: APPROVED
author_association: NONE
submitted_at: 2025-03-25T10:05:00Z

Review comments:
diff_hunk: @@ -290,13 +282,13 @@ def change_to_lib_flag(lib):
 nvc_info.update(python_info)
 nvfort_info.update(python_info)
 
-available_compilers = {('GNU', 'c') : gcc_info,
-                       ('GNU', 'fortran') : gfort_info,
-                       ('intel', 'c') : icc_info,
-                       ('intel', 'fortran') : ifort_info,
-                       ('PGI', 'c') : pgcc_info,
-                       ('PGI', 'fortran') : pgfortran_info,
-                       ('nvidia', 'c') : nvc_info,
-                       ('nvidia', 'fortran') : nvfort_info}
+available_compilers = {'GNU': {'c' : gcc_info,
+                               'fortran' : gfort_info},
path: pyccel/compilers/default_compilers.py
user: login: yguclu
body: Is there a reason to keep the `"family"` entry in the compiler info dictionary? Since you have just removed the `"language"` from it, I would also remove the `"family"`.
created_at: 2025-03-21T11:50:20Z
author_association: MEMBER
diff_hunk: @@ -50,11 +49,11 @@ Python is considered to be an accelerator and must additionally specify `shared_
 The default compilers can provide examples compatible with your system once Pyccel has been executed at least. To export the JSON file describing your setup, use the `--export-compile-info` flag and provide a target file name.
 E.g.
 ```shell
-pyccel --compiler=intel --language=c --export-compile-info=icc.json
+pyccel --compiler=intel --export-compile-info=intel.json
 ```
 once this file has been modified it can then be used with:
 ```shell
-pyccel --compiler=icc.json --language=c <file_to_translate>
+pyccel --compiler=intel.json <file_to_translate>
 ```
 
 ## Utilising Pyccel within Anaconda Environment
path: docs/compiler.md
user: login: yguclu
body: A suggestion not related to this PR:
```suggestion
## Utilising Pyccel within the Anaconda environment
```
created_at: 2025-03-21T14:45:22Z
author_association: MEMBER
diff_hunk: @@ -50,11 +49,11 @@ Python is considered to be an accelerator and must additionally specify `shared_
 The default compilers can provide examples compatible with your system once Pyccel has been executed at least. To export the JSON file describing your setup, use the `--export-compile-info` flag and provide a target file name.
 E.g.
 ```shell
-pyccel --compiler=intel --language=c --export-compile-info=icc.json
+pyccel --compiler=intel --export-compile-info=intel.json
 ```
 once this file has been modified it can then be used with:
 ```shell
-pyccel --compiler=icc.json --language=c <file_to_translate>
+pyccel --compiler=intel.json <file_to_translate>
path: docs/compiler.md
user: login: yguclu
body: We could pass the `--language` flag if we wanted to, right?
created_at: 2025-03-21T14:46:07Z
author_association: MEMBER
diff_hunk: @@ -191,12 +191,11 @@ def handle_error(stage):
 
     # Get compiler object
     Compiler.acceptable_bin_paths = get_condaless_search_path(conda_warnings)
-    src_compiler = Compiler(compiler, language, debug)
-    wrapper_compiler = Compiler(compiler, 'c', debug)
+    compiler = Compiler(compiler, debug)
path: pyccel/codegen/pipeline.py
user: login: yguclu
body: We should change the name of either of the two `compiler` variables. Maybe the string variable could be called `compiler_family`? Or just `family`.
created_at: 2025-03-21T14:54:49Z
author_association: MEMBER
diff_hunk: @@ -144,55 +138,74 @@ def _get_exec(self, accelerators):
 
     def _get_flags(self, flags = (), accelerators = ()):
         """
-        Collect necessary compile flags
+        Collect necessary compile flags.
+
+        Collect necessary compile flags, e.g. those relevant to the
+        language or compilation mode (debug/release).
 
         Parameters
         ----------
-        flags        : iterable of str
-                       Any additional flags requested by the user
-                       / required by the file
+        flags : iterable of str
+            Any additional flags requested by the user / required by
+            the file.
         accelerators : iterable or str
-                       Accelerators used by the code
+            Accelerators used by the code.
+
+        Returns
+        -------
+        list[str]
+            A list containing the flags.
         """
         flags = list(flags)
 
         if self._debug:
-            flags.extend(self._info.get('debug_flags',()))
+            flags.extend(self._language_info.get('debug_flags',()))
         else:
-            flags.extend(self._info.get('release_flags',()))
+            flags.extend(self._language_info.get('release_flags',()))
 
-        flags.extend(self._info.get('general_flags',()))
+        flags.extend(self._language_info.get('general_flags',()))
         # M_PI is not in the standard
         #if 'python' not in accelerators:
         #    # Python sets its own standard
-        #    flags.extend(self._info.get('standard_flags',()))
+        #    flags.extend(self._language_info.get('standard_flags',()))
 
         for a in accelerators:
-            flags.extend(self._info.get(a,{}).get('flags',()))
+            flags.extend(self._language_info.get(a,{}).get('flags',()))
 
         return flags
 
-    def _get_property(self, key, prop = (), accelerators = ()):
+    def _get_property(self, key, properties = (), accelerators = ()):
         """
-        Collect necessary compile property
+        Collect necessary compile property.
+
+        Collect necessary compile properties such as include folders
+        or library directories.
 
         Parameters
         ----------
-        property     : iterable of str
-                       Any additional values of the property
-                       requested by the user / required by the file
+        key : str
+            A key describing the property of interest.
+        properties : iterable of str
+            Any additional values of the property requested by the
+            user / required by the file.
         accelerators : iterable or str
-                       Accelerators used by the code
+            Accelerators used by the code.
+
+        Returns
+        -------
+        iterable[str]
+            An iterable containing the relevant information from the
+            requested property.
         """
         # Use dict keys as an ordered set
-        prop = dict.fromkeys(prop)
+        properties = dict.fromkeys(properties)
path: pyccel/codegen/compiling/compilers.py
user: login: yguclu
body: Are the `properties` keys, or values? The usage of `fromkeys` suggests the former option.
created_at: 2025-03-21T15:09:44Z
author_association: MEMBER
diff_hunk: @@ -290,13 +282,13 @@ def change_to_lib_flag(lib):
 nvc_info.update(python_info)
 nvfort_info.update(python_info)
 
-available_compilers = {('GNU', 'c') : gcc_info,
-                       ('GNU', 'fortran') : gfort_info,
-                       ('intel', 'c') : icc_info,
-                       ('intel', 'fortran') : ifort_info,
-                       ('PGI', 'c') : pgcc_info,
-                       ('PGI', 'fortran') : pgfortran_info,
-                       ('nvidia', 'c') : nvc_info,
-                       ('nvidia', 'fortran') : nvfort_info}
+available_compilers = {'GNU': {'c' : gcc_info,
+                               'fortran' : gfort_info},
path: pyccel/compilers/default_compilers.py
user: login: yguclu
body: Sorry if the placement of my comment is confusing. I could not select the code which was not modified...
created_at: 2025-03-21T15:38:32Z
author_association: MEMBER
diff_hunk: @@ -290,13 +282,13 @@ def change_to_lib_flag(lib):
 nvc_info.update(python_info)
 nvfort_info.update(python_info)
 
-available_compilers = {('GNU', 'c') : gcc_info,
-                       ('GNU', 'fortran') : gfort_info,
-                       ('intel', 'c') : icc_info,
-                       ('intel', 'fortran') : ifort_info,
-                       ('PGI', 'c') : pgcc_info,
-                       ('PGI', 'fortran') : pgfortran_info,
-                       ('nvidia', 'c') : nvc_info,
-                       ('nvidia', 'fortran') : nvfort_info}
+available_compilers = {'GNU': {'c' : gcc_info,
+                               'fortran' : gfort_info},
path: pyccel/compilers/default_compilers.py
user: login: EmilyBourne
body: Hmm, I removed `language` because it was already present in the output. I actually don't think the `"family"` key is used. But in the future we could imagine having a folder, e.g. `.pyccel` that we automatically check for configs. In this case we would need a way to differentiate between them so the "family" key could be useful. That said having it inside the language config is certainly a bit odd
created_at: 2025-03-21T15:42:41Z
author_association: MEMBER
diff_hunk: @@ -50,11 +49,11 @@ Python is considered to be an accelerator and must additionally specify `shared_
 The default compilers can provide examples compatible with your system once Pyccel has been executed at least. To export the JSON file describing your setup, use the `--export-compile-info` flag and provide a target file name.
 E.g.
 ```shell
-pyccel --compiler=intel --language=c --export-compile-info=icc.json
+pyccel --compiler=intel --export-compile-info=intel.json
 ```
 once this file has been modified it can then be used with:
 ```shell
-pyccel --compiler=icc.json --language=c <file_to_translate>
+pyccel --compiler=intel.json <file_to_translate>
path: docs/compiler.md
user: login: EmilyBourne
body: Yes the `--language` flag now behaves as it usually does when using the `pyccel` command
created_at: 2025-03-21T15:43:21Z
author_association: MEMBER
diff_hunk: @@ -50,14 +49,14 @@ Python is considered to be an accelerator and must additionally specify `shared_
 The default compilers can provide examples compatible with your system once Pyccel has been executed at least. To export the JSON file describing your setup, use the `--export-compile-info` flag and provide a target file name.
 E.g.
 ```shell
-pyccel --compiler=intel --language=c --export-compile-info=icc.json
+pyccel --compiler=intel --export-compile-info=intel.json
 ```
 once this file has been modified it can then be used with:
 ```shell
-pyccel --compiler=icc.json --language=c <file_to_translate>
+pyccel --compiler=intel.json <file_to_translate>
path: docs/compiler.md
user: login: yguclu
body: I think we should mention that the environment variable `PYCCEL_DEFAULT_COMPILER` can be used to specify the path to the JSON file. This is not obvious just by reading the section "Specifying a compiler".
created_at: 2025-03-21T15:55:55Z
author_association: MEMBER
diff_hunk: @@ -144,55 +138,74 @@ def _get_exec(self, accelerators):
 
     def _get_flags(self, flags = (), accelerators = ()):
         """
-        Collect necessary compile flags
+        Collect necessary compile flags.
+
+        Collect necessary compile flags, e.g. those relevant to the
+        language or compilation mode (debug/release).
 
         Parameters
         ----------
-        flags        : iterable of str
-                       Any additional flags requested by the user
-                       / required by the file
+        flags : iterable of str
+            Any additional flags requested by the user / required by
+            the file.
         accelerators : iterable or str
-                       Accelerators used by the code
+            Accelerators used by the code.
+
+        Returns
+        -------
+        list[str]
+            A list containing the flags.
         """
         flags = list(flags)
 
         if self._debug:
-            flags.extend(self._info.get('debug_flags',()))
+            flags.extend(self._language_info.get('debug_flags',()))
         else:
-            flags.extend(self._info.get('release_flags',()))
+            flags.extend(self._language_info.get('release_flags',()))
 
-        flags.extend(self._info.get('general_flags',()))
+        flags.extend(self._language_info.get('general_flags',()))
         # M_PI is not in the standard
         #if 'python' not in accelerators:
         #    # Python sets its own standard
-        #    flags.extend(self._info.get('standard_flags',()))
+        #    flags.extend(self._language_info.get('standard_flags',()))
 
         for a in accelerators:
-            flags.extend(self._info.get(a,{}).get('flags',()))
+            flags.extend(self._language_info.get(a,{}).get('flags',()))
 
         return flags
 
-    def _get_property(self, key, prop = (), accelerators = ()):
+    def _get_property(self, key, properties = (), accelerators = ()):
         """
-        Collect necessary compile property
+        Collect necessary compile property.
+
+        Collect necessary compile properties such as include folders
+        or library directories.
 
         Parameters
         ----------
-        property     : iterable of str
-                       Any additional values of the property
-                       requested by the user / required by the file
+        key : str
+            A key describing the property of interest.
+        properties : iterable of str
+            Any additional values of the property requested by the
+            user / required by the file.
         accelerators : iterable or str
-                       Accelerators used by the code
+            Accelerators used by the code.
+
+        Returns
+        -------
+        iterable[str]
+            An iterable containing the relevant information from the
+            requested property.
         """
         # Use dict keys as an ordered set
-        prop = dict.fromkeys(prop)
+        properties = dict.fromkeys(properties)
path: pyccel/codegen/compiling/compilers.py
user: login: EmilyBourne
body: Clearer: ac67023ba ?
created_at: 2025-03-24T10:26:33Z
author_association: MEMBER
diff_hunk: @@ -50,14 +49,14 @@ Python is considered to be an accelerator and must additionally specify `shared_
 The default compilers can provide examples compatible with your system once Pyccel has been executed at least. To export the JSON file describing your setup, use the `--export-compile-info` flag and provide a target file name.
 E.g.
 ```shell
-pyccel --compiler=intel --language=c --export-compile-info=icc.json
+pyccel --compiler=intel --export-compile-info=intel.json
 ```
 once this file has been modified it can then be used with:
 ```shell
-pyccel --compiler=icc.json --language=c <file_to_translate>
+pyccel --compiler=intel.json <file_to_translate>
path: docs/compiler.md
user: login: EmilyBourne
body: Better : 40af93c24 ?
created_at: 2025-03-24T10:37:52Z
author_association: MEMBER
diff_hunk: @@ -290,13 +282,13 @@ def change_to_lib_flag(lib):
 nvc_info.update(python_info)
 nvfort_info.update(python_info)
 
-available_compilers = {('GNU', 'c') : gcc_info,
-                       ('GNU', 'fortran') : gfort_info,
-                       ('intel', 'c') : icc_info,
-                       ('intel', 'fortran') : ifort_info,
-                       ('PGI', 'c') : pgcc_info,
-                       ('PGI', 'fortran') : pgfortran_info,
-                       ('nvidia', 'c') : nvc_info,
-                       ('nvidia', 'fortran') : nvfort_info}
+available_compilers = {'GNU': {'c' : gcc_info,
+                               'fortran' : gfort_info},
path: pyccel/compilers/default_compilers.py
user: login: EmilyBourne
body: I am not sure where to put this instead. Do you have a suggestion? E.g. I could do:
```
{'family': 'GNU',
 'languages': {'c':...,
       'fortran':...}}
```
created_at: 2025-03-24T10:38:55Z
author_association: MEMBER
diff_hunk: @@ -144,55 +138,74 @@ def _get_exec(self, accelerators):
 
     def _get_flags(self, flags = (), accelerators = ()):
         """
-        Collect necessary compile flags
+        Collect necessary compile flags.
+
+        Collect necessary compile flags, e.g. those relevant to the
+        language or compilation mode (debug/release).
 
         Parameters
         ----------
-        flags        : iterable of str
-                       Any additional flags requested by the user
-                       / required by the file
+        flags : iterable of str
+            Any additional flags requested by the user / required by
+            the file.
         accelerators : iterable or str
-                       Accelerators used by the code
+            Accelerators used by the code.
+
+        Returns
+        -------
+        list[str]
+            A list containing the flags.
         """
         flags = list(flags)
 
         if self._debug:
-            flags.extend(self._info.get('debug_flags',()))
+            flags.extend(self._language_info.get('debug_flags',()))
         else:
-            flags.extend(self._info.get('release_flags',()))
+            flags.extend(self._language_info.get('release_flags',()))
 
-        flags.extend(self._info.get('general_flags',()))
+        flags.extend(self._language_info.get('general_flags',()))
         # M_PI is not in the standard
         #if 'python' not in accelerators:
         #    # Python sets its own standard
-        #    flags.extend(self._info.get('standard_flags',()))
+        #    flags.extend(self._language_info.get('standard_flags',()))
 
         for a in accelerators:
-            flags.extend(self._info.get(a,{}).get('flags',()))
+            flags.extend(self._language_info.get(a,{}).get('flags',()))
 
         return flags
 
-    def _get_property(self, key, prop = (), accelerators = ()):
+    def _get_property(self, key, properties = (), accelerators = ()):
         """
-        Collect necessary compile property
+        Collect necessary compile property.
+
+        Collect necessary compile properties such as include folders
+        or library directories.
 
         Parameters
         ----------
-        property     : iterable of str
-                       Any additional values of the property
-                       requested by the user / required by the file
+        key : str
+            A key describing the property of interest.
+        properties : iterable of str
+            Any additional values of the property requested by the
+            user / required by the file.
         accelerators : iterable or str
-                       Accelerators used by the code
+            Accelerators used by the code.
+
+        Returns
+        -------
+        iterable[str]
+            An iterable containing the relevant information from the
+            requested property.
         """
         # Use dict keys as an ordered set
-        prop = dict.fromkeys(prop)
+        properties = dict.fromkeys(properties)
path: pyccel/codegen/compiling/compilers.py
user: login: yguclu
body: The example is very clear, thanks!
created_at: 2025-03-24T13:24:51Z
author_association: MEMBER
diff_hunk: @@ -50,14 +49,14 @@ Python is considered to be an accelerator and must additionally specify `shared_
 The default compilers can provide examples compatible with your system once Pyccel has been executed at least. To export the JSON file describing your setup, use the `--export-compile-info` flag and provide a target file name.
 E.g.
 ```shell
-pyccel --compiler=intel --language=c --export-compile-info=icc.json
+pyccel --compiler=intel --export-compile-info=intel.json
 ```
 once this file has been modified it can then be used with:
 ```shell
-pyccel --compiler=icc.json --language=c <file_to_translate>
+pyccel --compiler=intel.json <file_to_translate>
path: docs/compiler.md
user: login: yguclu
body: What you added is useful, but I meant that this information should be added to the section where I put the comment, which is named "Using an unsupported compiler or custom compiler flags".
created_at: 2025-03-24T13:35:55Z
author_association: MEMBER
diff_hunk: @@ -50,14 +49,14 @@ Python is considered to be an accelerator and must additionally specify `shared_
 The default compilers can provide examples compatible with your system once Pyccel has been executed at least. To export the JSON file describing your setup, use the `--export-compile-info` flag and provide a target file name.
 E.g.
 ```shell
-pyccel --compiler=intel --language=c --export-compile-info=icc.json
+pyccel --compiler=intel --export-compile-info=intel.json
 ```
 once this file has been modified it can then be used with:
 ```shell
-pyccel --compiler=icc.json --language=c <file_to_translate>
+pyccel --compiler=intel.json <file_to_translate>
path: docs/compiler.md
user: login: yguclu
body: Do you want me to do it?
created_at: 2025-03-24T13:36:14Z
author_association: MEMBER
diff_hunk: @@ -50,14 +49,14 @@ Python is considered to be an accelerator and must additionally specify `shared_
 The default compilers can provide examples compatible with your system once Pyccel has been executed at least. To export the JSON file describing your setup, use the `--export-compile-info` flag and provide a target file name.
 E.g.
 ```shell
-pyccel --compiler=intel --language=c --export-compile-info=icc.json
+pyccel --compiler=intel --export-compile-info=intel.json
 ```
 once this file has been modified it can then be used with:
 ```shell
-pyccel --compiler=icc.json --language=c <file_to_translate>
+pyccel --compiler=intel.json <file_to_translate>
path: docs/compiler.md
user: login: EmilyBourne
body: If you have a suggestion then feel free to add it :+1:
created_at: 2025-03-24T13:44:13Z
author_association: MEMBER
diff_hunk: @@ -50,14 +49,14 @@ Python is considered to be an accelerator and must additionally specify `shared_
 The default compilers can provide examples compatible with your system once Pyccel has been executed at least. To export the JSON file describing your setup, use the `--export-compile-info` flag and provide a target file name.
 E.g.
 ```shell
-pyccel --compiler=intel --language=c --export-compile-info=icc.json
+pyccel --compiler=intel --export-compile-info=intel.json
 ```
 once this file has been modified it can then be used with:
 ```shell
-pyccel --compiler=icc.json --language=c <file_to_translate>
+pyccel --compiler=intel.json <file_to_translate>
path: docs/compiler.md
user: login: yguclu
body: Do the flags override the environment variable, or is it the other way around?
created_at: 2025-03-24T13:48:02Z
author_association: MEMBER
diff_hunk: @@ -50,14 +49,14 @@ Python is considered to be an accelerator and must additionally specify `shared_
 The default compilers can provide examples compatible with your system once Pyccel has been executed at least. To export the JSON file describing your setup, use the `--export-compile-info` flag and provide a target file name.
 E.g.
 ```shell
-pyccel --compiler=intel --language=c --export-compile-info=icc.json
+pyccel --compiler=intel --export-compile-info=intel.json
 ```
 once this file has been modified it can then be used with:
 ```shell
-pyccel --compiler=icc.json --language=c <file_to_translate>
+pyccel --compiler=intel.json <file_to_translate>
path: docs/compiler.md
user: login: EmilyBourne
body: The flags should override the environment variable

https://github.com/pyccel/pyccel/blob/bbff872ce78c57d2c91d1895ca154ba8fe3b7d1a/pyccel/codegen/pipeline.py#L186-L187
created_at: 2025-03-24T13:49:30Z
author_association: MEMBER
diff_hunk: @@ -50,14 +49,14 @@ Python is considered to be an accelerator and must additionally specify `shared_
 The default compilers can provide examples compatible with your system once Pyccel has been executed at least. To export the JSON file describing your setup, use the `--export-compile-info` flag and provide a target file name.
 E.g.
 ```shell
-pyccel --compiler=intel --language=c --export-compile-info=icc.json
+pyccel --compiler=intel --export-compile-info=intel.json
 ```
 once this file has been modified it can then be used with:
 ```shell
-pyccel --compiler=icc.json --language=c <file_to_translate>
+pyccel --compiler=intel.json <file_to_translate>
path: docs/compiler.md
user: login: yguclu
body: Thanks, I will mention this
created_at: 2025-03-24T13:54:36Z
author_association: MEMBER
diff_hunk: @@ -50,14 +49,14 @@ Python is considered to be an accelerator and must additionally specify `shared_
 The default compilers can provide examples compatible with your system once Pyccel has been executed at least. To export the JSON file describing your setup, use the `--export-compile-info` flag and provide a target file name.
 E.g.
 ```shell
-pyccel --compiler=intel --language=c --export-compile-info=icc.json
+pyccel --compiler=intel --export-compile-info=intel.json
 ```
 once this file has been modified it can then be used with:
 ```shell
-pyccel --compiler=icc.json --language=c <file_to_translate>
+pyccel --compiler=intel.json <file_to_translate>
path: docs/compiler.md
user: login: yguclu
body: What do you think? [d23bed8](https://github.com/pyccel/pyccel/pull/2252/commits/d23bed8d330b848d8453e6b355f4f034497fbebb)
created_at: 2025-03-24T14:17:58Z
author_association: MEMBER
diff_hunk: @@ -50,14 +49,14 @@ Python is considered to be an accelerator and must additionally specify `shared_
 The default compilers can provide examples compatible with your system once Pyccel has been executed at least. To export the JSON file describing your setup, use the `--export-compile-info` flag and provide a target file name.
 E.g.
 ```shell
-pyccel --compiler=intel --language=c --export-compile-info=icc.json
+pyccel --compiler=intel --export-compile-info=intel.json
 ```
 once this file has been modified it can then be used with:
 ```shell
-pyccel --compiler=icc.json --language=c <file_to_translate>
+pyccel --compiler=intel.json <file_to_translate>
path: docs/compiler.md
user: login: EmilyBourne
body: I think I misunderstood your question about flags. I thought you were talking about `--X` options not the `--flags` option. A compiler definition does not contain a `flags` field. It has `general_flags`, `release_flags` and `debug_flags`. The flags used in the compilations are `general_flags`, one of `release_flags` and `debug_flags`, and any additional flags passed using the `--flags` option.
created_at: 2025-03-24T14:21:29Z
author_association: MEMBER
diff_hunk: @@ -50,14 +49,14 @@ Python is considered to be an accelerator and must additionally specify `shared_
 The default compilers can provide examples compatible with your system once Pyccel has been executed at least. To export the JSON file describing your setup, use the `--export-compile-info` flag and provide a target file name.
 E.g.
 ```shell
-pyccel --compiler=intel --language=c --export-compile-info=icc.json
+pyccel --compiler=intel --export-compile-info=intel.json
 ```
 once this file has been modified it can then be used with:
 ```shell
-pyccel --compiler=icc.json --language=c <file_to_translate>
+pyccel --compiler=intel.json <file_to_translate>
path: docs/compiler.md
user: login: yguclu
body: No, you understood correctly what I meant. I was talking about any option that is also contained in the JSON file. But I was sloppy in my explanation, as you rightly pointed out things are more complicated
created_at: 2025-03-24T14:25:32Z
author_association: MEMBER
diff_hunk: @@ -50,14 +49,14 @@ Python is considered to be an accelerator and must additionally specify `shared_
 The default compilers can provide examples compatible with your system once Pyccel has been executed at least. To export the JSON file describing your setup, use the `--export-compile-info` flag and provide a target file name.
 E.g.
 ```shell
-pyccel --compiler=intel --language=c --export-compile-info=icc.json
+pyccel --compiler=intel --export-compile-info=intel.json
 ```
 once this file has been modified it can then be used with:
 ```shell
-pyccel --compiler=icc.json --language=c <file_to_translate>
+pyccel --compiler=intel.json <file_to_translate>
path: docs/compiler.md
user: login: EmilyBourne
body: Corrected 
[583c6f6](https://github.com/pyccel/pyccel/pull/2252/commits/583c6f6b1f6e39468ed4bab4e8b58331998694b2)
created_at: 2025-03-24T17:15:01Z
author_association: MEMBER
diff_hunk: @@ -50,14 +49,14 @@ Python is considered to be an accelerator and must additionally specify `shared_
 The default compilers can provide examples compatible with your system once Pyccel has been executed at least. To export the JSON file describing your setup, use the `--export-compile-info` flag and provide a target file name.
 E.g.
 ```shell
-pyccel --compiler=intel --language=c --export-compile-info=icc.json
+pyccel --compiler=intel --export-compile-info=intel.json
 ```
 once this file has been modified it can then be used with:
 ```shell
-pyccel --compiler=icc.json --language=c <file_to_translate>
+pyccel --compiler=intel.json <file_to_translate>
path: docs/compiler.md
user: login: yguclu
body: Thanks!
created_at: 2025-03-24T18:30:18Z
author_association: MEMBER
diff_hunk: @@ -290,13 +282,13 @@ def change_to_lib_flag(lib):
 nvc_info.update(python_info)
 nvfort_info.update(python_info)
 
-available_compilers = {('GNU', 'c') : gcc_info,
-                       ('GNU', 'fortran') : gfort_info,
-                       ('intel', 'c') : icc_info,
-                       ('intel', 'fortran') : ifort_info,
-                       ('PGI', 'c') : pgcc_info,
-                       ('PGI', 'fortran') : pgfortran_info,
-                       ('nvidia', 'c') : nvc_info,
-                       ('nvidia', 'fortran') : nvfort_info}
+available_compilers = {'GNU': {'c' : gcc_info,
+                               'fortran' : gfort_info},
path: pyccel/compilers/default_compilers.py
user: login: yguclu
body: Since we are passing either a JSON file or a compiler family with `--compiler`, it would seem appropriate to treat them on an equal footing and let the filename identify the compiler family. Hence if this hypothetical `.pyccel` folder contained the files `amd.json` and `llvm.json`, these would automatically identify the compiler families `amd` and `llvm`.
created_at: 2025-03-24T19:01:41Z
author_association: MEMBER
diff_hunk: @@ -290,13 +282,13 @@ def change_to_lib_flag(lib):
 nvc_info.update(python_info)
 nvfort_info.update(python_info)
 
-available_compilers = {('GNU', 'c') : gcc_info,
-                       ('GNU', 'fortran') : gfort_info,
-                       ('intel', 'c') : icc_info,
-                       ('intel', 'fortran') : ifort_info,
-                       ('PGI', 'c') : pgcc_info,
-                       ('PGI', 'fortran') : pgfortran_info,
-                       ('nvidia', 'c') : nvc_info,
-                       ('nvidia', 'fortran') : nvfort_info}
+available_compilers = {'GNU': {'c' : gcc_info,
+                               'fortran' : gfort_info},
path: pyccel/compilers/default_compilers.py
user: login: yguclu
body: This is similar to GitHub Actions, where `build_docs.yml` corresponds to the action `build_docs`.
created_at: 2025-03-25T07:55:37Z
author_association: MEMBER
diff_hunk: @@ -290,13 +282,13 @@ def change_to_lib_flag(lib):
 nvc_info.update(python_info)
 nvfort_info.update(python_info)
 
-available_compilers = {('GNU', 'c') : gcc_info,
-                       ('GNU', 'fortran') : gfort_info,
-                       ('intel', 'c') : icc_info,
-                       ('intel', 'fortran') : ifort_info,
-                       ('PGI', 'c') : pgcc_info,
-                       ('PGI', 'fortran') : pgfortran_info,
-                       ('nvidia', 'c') : nvc_info,
-                       ('nvidia', 'fortran') : nvfort_info}
+available_compilers = {'GNU': {'c' : gcc_info,
+                               'fortran' : gfort_info},
path: pyccel/compilers/default_compilers.py
user: login: EmilyBourne
body: That sounds like a good idea :+1:
created_at: 2025-03-25T07:58:31Z
author_association: MEMBER
diff_hunk: @@ -290,13 +282,13 @@ def change_to_lib_flag(lib):
 nvc_info.update(python_info)
 nvfort_info.update(python_info)
 
-available_compilers = {('GNU', 'c') : gcc_info,
-                       ('GNU', 'fortran') : gfort_info,
-                       ('intel', 'c') : icc_info,
-                       ('intel', 'fortran') : ifort_info,
-                       ('PGI', 'c') : pgcc_info,
-                       ('PGI', 'fortran') : pgfortran_info,
-                       ('nvidia', 'c') : nvc_info,
-                       ('nvidia', 'fortran') : nvfort_info}
+available_compilers = {'GNU': {'c' : gcc_info,
+                               'fortran' : gfort_info},
path: pyccel/compilers/default_compilers.py
user: login: EmilyBourne
body: Key removed: 8219c023b
created_at: 2025-03-25T08:00:07Z
author_association: MEMBER

PR comments:
user: login: pyccel-bot[bot]
created_at: 2025-03-18T11:54:17Z
body: Hello again! Thank you for this new pull request :star_struck:.

Please begin by requesting your checklist using the command `/bot checklist`

author_association: NONE
user: login: EmilyBourne
created_at: 2025-03-18T11:54:27Z
body: Here is your checklist. Please tick items off when you have completed them or determined that they are not necessary for this pull request:
- [x] Write a clear PR description
- [x] Add tests to check your code works as expected
- [x] Update documentation if necessary
- [x] Update Changelog
- [x] Ensure any relevant issues are linked
- [x] Ensure new tests are passing

author_association: MEMBER
user: login: pyccel-bot[bot]
created_at: 2025-03-20T15:01:18Z
body: Unfortunately your PR is not passing the tests so it is not quite ready for review yet. Let me know when it is fixed with `/bot mark as ready`.

author_association: NONE
user: login: EmilyBourne
created_at: 2025-03-20T15:05:11Z
body: /bot run docs
author_association: MEMBER
user: login: EmilyBourne
created_at: 2025-03-20T15:14:04Z
body: /bot run docs
author_association: MEMBER
user: login: pyccel-bot[bot]
created_at: 2025-03-20T15:56:14Z
body: Hey @pyccel/pyccel-dev ! @EmilyBourne has just created this great new pull request! Check it out and let me know what you think!

author_association: NONE
user: login: EmilyBourne
created_at: 2025-03-25T09:38:40Z
body: /bot run pr_tests
author_association: MEMBER
user: login: pyccel-bot[bot]
created_at: 2025-03-25T09:40:00Z
body: Unfortunately your PR is not passing the tests so it is not quite ready for review yet. Let me know when it is fixed with `/bot mark as ready`.

author_association: NONE