Repository: pyccel/pyccel (language: python)

Issue:
Code



Discussion / hints:

Fix patch:
diff --git a/.dict_custom.txt b/.dict_custom.txt
index 817a703f48..1ebc17fd6f 100644
--- a/.dict_custom.txt
+++ b/.dict_custom.txt
@@ -80,4 +80,6 @@ inhomogeneous
 natively
 PSYDAC
 prepend
+uniformise
+incrementation
 Pylint
diff --git a/.github/workflows/anaconda_linux.yml b/.github/workflows/anaconda_linux.yml
new file mode 100644
index 0000000000..ef94560ea2
--- /dev/null
+++ b/.github/workflows/anaconda_linux.yml
@@ -0,0 +1,44 @@
+name: Anaconda-Linux
+
+on:
+  workflow_call:
+    inputs:
+      python_version:
+        required: true
+        type: string
+      ref:
+        required: false
+        type: string
+
+jobs:
+  Anaconda-Linux:
+    runs-on: ubuntu-latest
+    name: Unit tests
+
+    steps:
+      - uses: actions/checkout@v3
+        with:
+          ref: ${{ inputs.ref }}
+      - name: Install dependencies
+        uses: ./.github/actions/linux_install
+      - uses: conda-incubator/setup-miniconda@v2
+        with:
+          auto-update-conda: true
+          auto-activate-base: true
+          python-version: ${{ inputs.python_version }}
+      - name: Install python dependencies
+        uses: ./.github/actions/conda_installation
+        with:
+          mpi_type: openmpi
+      - name: Fortran/C tests with pytest
+        uses: ./.github/actions/pytest_run
+        with:
+          shell_cmd: "bash -l {0}"
+      - name: Python tests with pytest
+        uses: ./.github/actions/pytest_run_python
+        with:
+          shell_cmd: "bash -l {0}"
+      - name: Parallel tests with pytest
+        uses: ./.github/actions/pytest_parallel
+        with:
+          shell_cmd: "bash -l {0}"
diff --git a/.github/workflows/anaconda_windows.yml b/.github/workflows/anaconda_windows.yml
new file mode 100644
index 0000000000..2e72f2d01f
--- /dev/null
+++ b/.github/workflows/anaconda_windows.yml
@@ -0,0 +1,42 @@
+name: Anaconda-Windows
+
+on:
+  workflow_call:
+    inputs:
+      python_version:
+        required: true
+        type: string
+      ref:
+        required: false
+        type: string
+
+jobs:
+  Anaconda-Windows:
+    runs-on: windows-latest
+    name: Unit tests
+
+    steps:
+      - uses: actions/checkout@v3
+        with:
+          ref: ${{ inputs.ref }}
+      - uses: conda-incubator/setup-miniconda@v2
+        with:
+          auto-update-conda: true
+          activate-environment: test
+          python-version: ${{ inputs.python_version }}
+      - name: Install dependencies
+        uses: ./.github/actions/windows_install
+      - name: Install python dependencies
+        uses: ./.github/actions/conda_installation
+        with:
+          mpi_type: msmpi
+      - name: Fortran/C tests with pytest
+        uses: ./.github/actions/pytest_run
+        with:
+          shell_cmd: 'bash -l -eo pipefail {0}'
+          pytest_mark: 'and not external'
+      - name: Python tests with pytest
+        uses: ./.github/actions/pytest_run_python
+        with:
+          shell_cmd: 'bash -l -eo pipefail {0}'
+
diff --git a/.github/workflows/bench.yml b/.github/workflows/bench.yml
index 72b927ff70..014c78fc59 100644
--- a/.github/workflows/bench.yml
+++ b/.github/workflows/bench.yml
@@ -2,7 +2,7 @@ name: Benchmarks
 
 on:
   push:
-    branches: [ master ]
+    branches: [ pyccel/master ]
 
 jobs:
 
diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml
new file mode 100644
index 0000000000..cc2c84247c
--- /dev/null
+++ b/.github/workflows/coverage.yml
@@ -0,0 +1,46 @@
+name: Unit test coverage
+
+on:
+  workflow_call:
+    inputs:
+      python_version:
+        required: true
+        type: string
+      ref:
+        required: false
+        type: string
+
+jobs:
+  CoverageChecker:
+
+    runs-on: ubuntu-latest
+    name: Unit tests
+
+    steps:
+      - uses: actions/checkout@v3
+        with:
+          ref: ${{ inputs.ref }}
+      - name: Set up Python 3.7
+        uses: actions/setup-python@v4
+        with:
+          python-version: 3.7
+      - name: Install Python dependencies
+        run: |
+          python -m pip install --upgrade pip
+          python -m pip install defusedxml
+        shell: bash
+      - name: Collect coverage information
+        uses: actions/download-artifact@v3
+        with:
+          name: coverage-artifact
+      - name: Collect diff information
+        run: |
+          BASE_BRANCH=$GITHUB_BASE_REF
+          git fetch
+          git diff origin/${BASE_BRANCH}..HEAD --no-indent-heuristic --unified=0 --output=pull_diff.txt --no-color
+          ls
+        shell: bash
+      - name: Check coverage
+        run: |
+          python ci_tools/check_new_coverage.py pull_diff.txt cobertura.xml $GITHUB_EVENT_PATH $GITHUB_STEP_SUMMARY
+        shell: bash
diff --git a/.github/workflows/doc_coverage.yml b/.github/workflows/doc_coverage.yml
index ef63106271..f417b40841 100644
--- a/.github/workflows/doc_coverage.yml
+++ b/.github/workflows/doc_coverage.yml
@@ -1,27 +1,38 @@
 name: Doc Coverage Action
 
 on:
-  pull_request:
-    branches: [ master ]
+  workflow_call:
+    inputs:
+      python_version:
+        required: true
+        type: string
+      ref:
+        required: false
+        type: string
+      base:
+        required: true
+        type: string
 
 jobs:
 
   DocumentationChecker:
 
     runs-on: ubuntu-latest
+    name: Documentation Format
 
     steps:
       - uses: actions/checkout@v3
         with:
-          ref: ${{ github.event.pull_request.base.sha }}
+          ref: ${{ inputs.base }}
           path: base
       - uses: actions/checkout@v3
         with:
           path: compare
-      - name: Set up Python 3.8
+          ref: ${{ inputs.ref }}
+      - name: Set up Python ${{ inputs.python_version }}
         uses: actions/setup-python@v4
         with:
-          python-version: 3.8
+          python-version: ${{ inputs.python_version }}
       - name: Install python dependencies
         run: |
           python -m pip install --upgrade pip
@@ -30,19 +41,20 @@ jobs:
         shell: bash
       - name: Show report
         run: |
+          echo "${{ github.event.pull_request.base.sha }}"
           docstr-coverage base/pyccel 2>base_cov || true
           docstr-coverage compare/pyccel 2>compare_cov || true
           python compare/ci_tools/summarise_doccoverage.py compare_cov base_cov $GITHUB_STEP_SUMMARY
           cd compare
           pip install .
-          BASE_BRANCH=$GITHUB_BASE_REF
-          git fetch &>/dev/null
-          git diff origin/${BASE_BRANCH}..HEAD --no-indent-heuristic --unified=0 --output=pull_diff.txt --no-color &>/dev/null
+          git fetch
+          git diff origin/${{ inputs.base }}..HEAD --no-indent-heuristic --unified=0 --output=pull_diff.txt --no-color &>/dev/null
           touch objects.txt
           touch report.txt
           python ci_tools/list_docs_tovalidate.py pull_diff.txt objects.txt
           while read line; do    
-            python3 -m numpydoc --validate $line >> report.txt 2>&1 || true 
+            python -m numpydoc --validate $line >> report.txt 2>&1 || true 
           done < objects.txt
           cat report.txt
-          python3 ci_tools/process_results.py report.txt $GITHUB_STEP_SUMMARY
+          python ci_tools/process_results.py report.txt $GITHUB_STEP_SUMMARY
+        shell: bash
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index 21e5676b93..3cda29c4e2 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -1,18 +1,32 @@
 name: Python Linting
+
 on:
-  pull_request:
-    branches: [ master ]
+  workflow_call:
+    inputs:
+      python_version:
+        required: true
+        type: string
+      ref:
+        required: false
+        type: string
 
 jobs:
   Linter:
     runs-on: ubuntu-latest
+    name: Python best practices
 
     steps:
       - uses: actions/checkout@v3
-      - name: Set up Python 3.7
+        with:
+          ref: ${{ inputs.ref }}
+      - name: Set up Python ${{ inputs.python_version }}
         uses: actions/setup-python@v4
         with:
-          python-version: 3.7
+          python-version: ${{ inputs.python_version }}
+      - name: Check branch
+        run: |
+          git branch
+          git status
       - name: Install python dependencies
         run: |
           python -m pip install --upgrade pip
diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml
new file mode 100644
index 0000000000..fe9598e436
--- /dev/null
+++ b/.github/workflows/linux.yml
@@ -0,0 +1,58 @@
+name: Linux unit tests
+
+on:
+  workflow_call:
+    inputs:
+      python_version:
+        required: true
+        type: string
+      ref:
+        required: false
+        type: string
+
+jobs:
+  Linux:
+
+    runs-on: ubuntu-latest
+    name: Unit tests
+
+    steps:
+      - uses: actions/checkout@v3
+        with:
+          ref: ${{ inputs.ref }}
+      - name: Set up Python ${{ inputs.python_version }}
+        uses: actions/setup-python@v4
+        with:
+          python-version: ${{ inputs.python_version }}
+      - name: Install dependencies
+        uses: ./.github/actions/linux_install
+      - name: Install Pyccel with tests
+        run: |
+            python -m pip install --upgrade pip
+            python -m pip install .[test]
+        shell: bash
+      - name: Coverage install
+        uses: ./.github/actions/coverage_install
+      - name: Fortran/C tests with pytest
+        uses: ./.github/actions/pytest_run
+      - name: Python tests with pytest
+        uses: ./.github/actions/pytest_run_python
+      - name: Parallel tests with pytest
+        uses: ./.github/actions/pytest_parallel
+      - name: Test with valgrind for memory leaks
+        uses: ./.github/actions/valgrind_run
+      - name: Collect coverage information
+        continue-on-error: True
+        uses: ./.github/actions/coverage_collection
+      - name: Run codacy-coverage-reporter
+        uses: codacy/codacy-coverage-reporter-action@master
+        continue-on-error: True
+        with:
+          project-token: ${{ secrets.CODACY_PROJECT_TOKEN }}
+          coverage-reports: cobertura.xml
+      - name: Save code coverage report
+        uses: actions/upload-artifact@v3
+        with:
+          name: coverage-artifact
+          path: cobertura.xml
+          retention-days: 1
diff --git a/.github/workflows/macosx.yml b/.github/workflows/macosx.yml
new file mode 100644
index 0000000000..c2e97f85e7
--- /dev/null
+++ b/.github/workflows/macosx.yml
@@ -0,0 +1,39 @@
+name: MacOSX unit tests
+
+on:
+  workflow_call:
+    inputs:
+      python_version:
+        required: true
+        type: string
+      ref:
+        required: false
+        type: string
+
+jobs:
+  MacOSX:
+
+    runs-on: macos-latest
+    name: Unit tests
+
+    steps:
+      - uses: actions/checkout@v3
+        with:
+          ref: ${{ inputs.ref }}
+      - name: Set up Python ${{ inputs.python_version }}
+        uses: actions/setup-python@v4
+        with:
+          python-version: ${{ inputs.python_version }}
+      - name: Install dependencies
+        uses: ./.github/actions/macos_install
+      - name: Install Pyccel with tests
+        run: |
+            python -m pip install --upgrade pip
+            python -m pip install .[test]
+        shell: bash
+      - name: Fortran/C tests with pytest
+        uses: ./.github/actions/pytest_run
+      - name: Python tests with pytest
+        uses: ./.github/actions/pytest_run_python
+      - name: Parallel tests with pytest
+        uses: ./.github/actions/pytest_parallel
diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml
index 0a3ec6354d..e5750290af 100644
--- a/.github/workflows/master.yml
+++ b/.github/workflows/master.yml
@@ -8,215 +8,61 @@ jobs:
 
   Linux-Master:
 
-    runs-on: ubuntu-latest
     strategy:
       fail-fast: false
       matrix:
         python-version: [3.7, 3.8, 3.9, '3.10', 3.11]
-
-    steps:
-      - uses: actions/checkout@v3
-      - name: Set up Python ${{ matrix.python-version }}
-        uses: actions/setup-python@v4
-        with:
-          python-version: ${{ matrix.python-version }}
-      - name: Install dependencies
-        uses: ./.github/actions/linux_install
-      - name: Install Pyccel with tests
-        run: |
-            python -m pip install --upgrade pip
-            python -m pip install .[test]
-        shell: bash
-      - name: Coverage install
-        uses: ./.github/actions/coverage_install
-      - name: Fortran/C tests with pytest
-        uses: ./.github/actions/pytest_run
-      - name: Python tests with pytest
-        uses: ./.github/actions/pytest_run_python
-      - name: Parallel tests with pytest
-        uses: ./.github/actions/pytest_parallel
-      - name: Collect coverage information
-        continue-on-error: True
-        uses: ./.github/actions/coverage_collection
-      - name: Run codacy-coverage-reporter
-        uses: codacy/codacy-coverage-reporter-action@master
-        continue-on-error: True
-        with:
-          project-token: ${{ secrets.CODACY_PROJECT_TOKEN }}
-          coverage-reports: cobertura.xml
+    uses:
+      ./.github/workflows/linux.yml
+    with:
+      python_version: ${{ matrix.python-version }}
 
   Windows:
 
-    runs-on: windows-latest
-
-    steps:
-      - uses: actions/checkout@v3
-      - name: Setup Python 3.7
-        uses: actions/setup-python@v4
-        with:
-            # The second most recent version is used as
-            # setup-python installs the most recent patch
-            # which leads to linking problems as there are
-            # 2 versions of python3X.a and the wrong one
-            # is chosen
-            python-version: 3.7
-      - name: Install dependencies
-        uses: ./.github/actions/windows_install
-      - name: Install Pyccel with tests
-        run: |
-            python -m pip install --upgrade pip
-            python -m pip install .[test]
-        shell: bash
-      - name: Fortran/C tests with pytest
-        uses: ./.github/actions/pytest_run
-      - name: Python tests with pytest
-        uses: ./.github/actions/pytest_run_python
-      - name: Parallel tests with pytest
-        uses: ./.github/actions/pytest_parallel
+    uses:
+      ./.github/workflows/windows.yml
+    with:
+      python_version: 3.7
 
   MacOSX:
 
-    runs-on: macos-latest
-
-    steps:
-      - uses: actions/checkout@v3
-      - name: Set up Python 3.9
-        uses: actions/setup-python@v4
-        with:
-          python-version: 3.9
-      - name: Install dependencies
-        uses: ./.github/actions/macos_install
-      - name: Install Pyccel with tests
-        run: |
-            python -m pip install --upgrade pip
-            python -m pip install .[test]
-        shell: bash
-      - name: Fortran/C tests with pytest
-        uses: ./.github/actions/pytest_run
-      - name: Python tests with pytest
-        uses: ./.github/actions/pytest_run_python
-      - name: Parallel tests with pytest
-        uses: ./.github/actions/pytest_parallel
+    uses:
+      ./.github/workflows/macosx.yml
+    with:
+      python_version: '3.9'
 
   Pickled-installation:
 
-    runs-on: ubuntu-latest
-
-    steps:
-      - uses: actions/checkout@v3
-      - name: Set up Python 3.7
-        uses: actions/setup-python@v4
-        with:
-          python-version: 3.7
-      - name: Install dependencies
-        uses: ./.github/actions/linux_install
-      - name: Install Pyccel
-        run: |
-          python -m pip install --upgrade pip
-          python -m pip install .
-        shell: bash
-      - name: Check for existence of pickled files
-        uses: ./.github/actions/check_for_pickled
+    uses:
+      ./.github/workflows/pickle.yml
+    with:
+      python_version: '3.7'
 
   Editable-pickled-installation:
 
-    runs-on: ubuntu-latest
-
-    steps:
-      - uses: actions/checkout@v3
-      - name: Set up Python 3.7
-        uses: actions/setup-python@v4
-        with:
-          python-version: 3.7
-      - name: Install dependencies
-        uses: ./.github/actions/linux_install
-      - name: Install Pyccel in editable mode
-        run: |
-          python -m pip install --upgrade pip
-          python -m pip install -e .
-        shell: bash
-      - name: Check for existence of pickled files
-        uses: ./.github/actions/check_for_pickled
+    uses:
+      ./.github/workflows/pickle.yml
+    with:
+      python_version: '3.7'
+      editable_string: '-e'
 
   Wheel-pickled-installation:
 
-    runs-on: ubuntu-latest
-
-    steps:
-      - uses: actions/checkout@v3
-      - name: Set up Python 3.7
-        uses: actions/setup-python@v4
-        with:
-          python-version: 3.7
-      - name: Install dependencies
-        uses: ./.github/actions/linux_install
-      - name: Install Pyccel from wheel
-        run: |
-          python -m pip install --upgrade pip
-          python -m pip install --upgrade build
-          python -m build
-          python -m pip install dist/*.whl
-        shell: bash
-      - name: Check for existence of pickled files
-        uses: ./.github/actions/check_for_pickled
+    uses:
+      ./.github/workflows/pickle_wheel.yml
+    with:
+      python_version: '3.7'
+
 
   Anaconda-Linux:
-    runs-on: ubuntu-latest
-
-    steps:
-      - uses: actions/checkout@v3
-      - name: Install dependencies
-        uses: ./.github/actions/linux_install
-      - uses: conda-incubator/setup-miniconda@v2
-        with:
-          auto-update-conda: true
-          auto-activate-base: true
-      - name: Install python dependencies
-        uses: ./.github/actions/conda_installation
-        with:
-          mpi_type: openmpi
-      - name: Fortran/C tests with pytest
-        uses: ./.github/actions/pytest_run
-        with:
-          shell_cmd: "bash -l {0}"
-      - name: Python tests with pytest
-        uses: ./.github/actions/pytest_run_python
-        with:
-          shell_cmd: "bash -l {0}"
-      - name: Parallel tests with pytest
-        uses: ./.github/actions/pytest_parallel
-        with:
-          shell_cmd: "bash -l {0}"
+    uses:
+      ./.github/workflows/anaconda_linux.yml
+    with:
+      python_version: '3.10'
 
   Anaconda-Windows:
-    runs-on: windows-latest
-
-    steps:
-      - uses: actions/checkout@v3
-      - uses: conda-incubator/setup-miniconda@v2
-        with:
-          auto-update-conda: true
-          activate-environment: test
-          python-version: "3.10"
-      - name: Install dependencies
-        uses: ./.github/actions/windows_install
-      - name: Install python dependencies
-        uses: ./.github/actions/conda_installation
-        with:
-          mpi_type: msmpi
-      - name: Fortran/C tests with pytest
-        run: |
-          python -m pytest -n auto -rX -m "not (parallel or xdist_incompatible or external) and c" --ignore=symbolic --ignore=ndarrays
-          python -m pytest -rX -m "xdist_incompatible and not parallel and c and not external" --ignore=symbolic --ignore=ndarrays
-          pyccel-clean
-          python -m pytest -n auto -rX -m "not (parallel or xdist_incompatible or external) and not (c or python)" --ignore=symbolic --ignore=ndarrays
-          python -m pytest -rX -m "xdist_incompatible and not parallel and not (c or python) and not external" --ignore=symbolic --ignore=ndarrays
-          pyccel-clean
-          python -m pytest ndarrays/ -rX
-          pyccel-clean
-        working-directory: ./tests
-        shell: bash -l -eo pipefail {0}
-      - name: Python tests with pytest
-        uses: ./.github/actions/pytest_run_python
-        with:
-          shell_cmd: 'bash -l -eo pipefail {0}'
+
+    uses:
+      ./.github/workflows/anaconda_windows.yml
+    with:
+      python_version: '3.10'
diff --git a/.github/workflows/pickle.yml b/.github/workflows/pickle.yml
new file mode 100644
index 0000000000..156a8c8666
--- /dev/null
+++ b/.github/workflows/pickle.yml
@@ -0,0 +1,37 @@
+name: Pickled-installation
+
+on:
+  workflow_call:
+    inputs:
+      python_version:
+        required: true
+        type: string
+      ref:
+        required: false
+        type: string
+      editable_string:
+        required: false
+        type: string
+
+jobs:
+  Pickled-installation:
+    runs-on: ubuntu-latest
+    name: Deploy tests
+
+    steps:
+      - uses: actions/checkout@v3
+        with:
+          ref: ${{ inputs.ref }}
+      - name: Set up Python ${{ matrix.python-version }}
+        uses: actions/setup-python@v4
+        with:
+          python-version: ${{ matrix.python-version }}
+      - name: Install dependencies
+        uses: ./.github/actions/linux_install
+      - name: Install Pyccel
+        run: |
+          python -m pip install --upgrade pip
+          python -m pip install ${{ inputs.editable_string }} .
+        shell: bash
+      - name: Check for existence of pickled files
+        uses: ./.github/actions/check_for_pickled
diff --git a/.github/workflows/pickle_wheel.yml b/.github/workflows/pickle_wheel.yml
new file mode 100644
index 0000000000..efaefa207b
--- /dev/null
+++ b/.github/workflows/pickle_wheel.yml
@@ -0,0 +1,36 @@
+name: Wheel-pickled-installation
+
+on:
+  workflow_call:
+    inputs:
+      python_version:
+        required: true
+        type: string
+      ref:
+        required: false
+        type: string
+
+jobs:
+  Wheel-pickled-installation:
+    runs-on: ubuntu-latest
+    name: Deploy tests
+
+    steps:
+      - uses: actions/checkout@v3
+        with:
+          ref: ${{ inputs.ref }}
+      - name: Set up Python ${{ inputs.python_version }}
+        uses: actions/setup-python@v4
+        with:
+          python-version: ${{ inputs.python_version }}
+      - name: Install dependencies
+        uses: ./.github/actions/linux_install
+      - name: Install Pyccel from wheel
+        run: |
+          python -m pip install --upgrade pip
+          python -m pip install --upgrade build
+          python -m build
+          python -m pip install dist/*.whl
+        shell: bash
+      - name: Check for existence of pickled files
+        uses: ./.github/actions/check_for_pickled
diff --git a/.github/workflows/pyccel_lint.yml b/.github/workflows/pyccel_lint.yml
index 31dde62ec0..bb550a3621 100644
--- a/.github/workflows/pyccel_lint.yml
+++ b/.github/workflows/pyccel_lint.yml
@@ -1,18 +1,28 @@
 name: Pyccel Linting
+
 on:
-  pull_request:
-    branches: [ master ]
+  workflow_call:
+    inputs:
+      python_version:
+        required: true
+        type: string
+      ref:
+        required: false
+        type: string
 
 jobs:
   Pyccel-Linter:
     runs-on: ubuntu-latest
+    name: Best practices
 
     steps:
       - uses: actions/checkout@v3
-      - name: Set up Python 3.7
+        with:
+          ref: ${{ inputs.ref }}
+      - name: Set up Python ${{ inputs.python_version }}
         uses: actions/setup-python@v4
         with:
-          python-version: 3.7
+          python-version: ${{ inputs.python_version }}
       - name: Install dependencies
         uses: ./.github/actions/linux_install
       - name: Install Pyccel
diff --git a/.github/workflows/spelling.yml b/.github/workflows/spelling.yml
index 9b3e891074..03575cb5c6 100644
--- a/.github/workflows/spelling.yml
+++ b/.github/workflows/spelling.yml
@@ -1,29 +1,40 @@
 name: Spellcheck Action
+
 on:
-  pull_request:
-    branches: [ master ]
+  workflow_call:
+    inputs:
+      python_version:
+        required: true
+        type: string
+      ref:
+        required: false
+        type: string
 
 jobs:
   Spelling:
     runs-on: ubuntu-latest
+    name: Documentation spellcheck
+
     steps:
-    - uses: actions/checkout@v3
-    - name: Set up Python 3.7
-      uses: actions/setup-python@v4
-      with:
-        python-version: 3.7
-    - name: Install dependencies
-      run: |
-        python -m pip install --upgrade pip setuptools
-        python -m pip install pyspelling
-        python -m pip install pymdown-extensions
-        # Install any additional libraries required: additional plugins, documentation building libraries, etc.
-    - name: Install Aspell
-      run: |
-        sudo apt-get install aspell aspell-en
-    - name: Spell check
-      run: |
-         python -m pyspelling > misspellings.txt || true
-         cat misspellings.txt
-         python ci_tools/summarise_pyspelling.py misspellings.txt $GITHUB_STEP_SUMMARY
+      - uses: actions/checkout@v3
+        with:
+          ref: ${{ inputs.ref }}
+      - name: Set up Python ${{ inputs.python_version }}
+        uses: actions/setup-python@v4
+        with:
+          python-version: ${{ inputs.python_version }}
+      - name: Install dependencies
+        run: |
+          python -m pip install --upgrade pip setuptools
+          python -m pip install pyspelling
+          python -m pip install pymdown-extensions
+          # Install any additional libraries required: additional plugins, documentation building libraries, etc.
+      - name: Install Aspell
+        run: |
+          sudo apt-get install aspell aspell-en
+      - name: Spell check
+        run: |
+           python -m pyspelling > misspellings.txt || true
+           cat misspellings.txt
+           python ci_tools/summarise_pyspelling.py misspellings.txt $GITHUB_STEP_SUMMARY
 
diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml
new file mode 100644
index 0000000000..062a45b7e1
--- /dev/null
+++ b/.github/workflows/windows.yml
@@ -0,0 +1,47 @@
+name: Windows unit tests
+
+on:
+  workflow_call:
+    inputs:
+      python_version:
+        required: true
+        type: string
+      ref:
+        required: false
+        type: string
+
+jobs:
+  Windows:
+
+    runs-on: windows-latest
+    name: Unit tests
+
+    steps:
+      - uses: actions/checkout@v3
+        with:
+          ref: ${{ inputs.ref }}
+      - name: Setup Python ${{ inputs.python_version }}
+        uses: actions/setup-python@v4
+        with:
+            # The second most recent version is used as
+            # setup-python installs the most recent patch
+            # which leads to linking problems as there are
+            # 2 versions of python3X.a and the wrong one
+            # is chosen
+            python-version: ${{ inputs.python_version }}
+      # Uncomment to examine DLL requirements with 'objdump -x FILE'
+      #- name: Install mingw tools
+      #  uses: msys2/setup-msys2@v2
+      - name: Install dependencies
+        uses: ./.github/actions/windows_install
+      - name: Install Pyccel with tests
+        run: |
+            python -m pip install --upgrade pip
+            python -m pip install .[test]
+        shell: bash
+      - name: Fortran/C tests with pytest
+        uses: ./.github/actions/pytest_run
+      - name: Python tests with pytest
+        uses: ./.github/actions/pytest_run_python
+      - name: Parallel tests with pytest
+        uses: ./.github/actions/pytest_parallel
diff --git a/.pylintrc b/.pylintrc
index 008ea14dd2..9a0e3a09f0 100644
--- a/.pylintrc
+++ b/.pylintrc
@@ -99,8 +99,7 @@ disable=invalid-name,
         redundant-keyword-arg,
         duplicate-code,
         unused-wildcard-import, # Raised by everything not used in pyccel.errors.messages when using 'from pyccel.errors.messages import *'
-        isinstance-second-argument-not-valid-type, # prevents doing isinstance(a, acceptable_iterable_types)
-        django-not-configured
+        isinstance-second-argument-not-valid-type # prevents doing isinstance(a, acceptable_iterable_types)
         
 
 # Enable the message, report, category or checker with the given id(s). You can
diff --git a/.pyspelling.yml b/.pyspelling.yml
index 50acd593cf..e6038c2c72 100644
--- a/.pyspelling.yml
+++ b/.pyspelling.yml
@@ -4,6 +4,7 @@ matrix:
   - README.md
   - tutorial/*.md
   - developer_docs/*.md
+  - CHANGELOG.md
   aspell:
     lang: en
     d: en_GB
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000000..e8e0c003e7
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,77 @@
+# Change Log
+All notable changes to this project will be documented in this file.
+
+## \[Unreleased\]
+
+### Added
+
+-   #1352 : Added a change log.
+
+### Fixed
+
+### Changed
+
+-   \[INTERNALS\] Use `FunctionDefArgument` to store all argument specific properties.
+-   \[INTERNALS\] Reduce carbon footprint by avoiding unnecessary CI testing.
+-   \[INTERNALS\] Automatise PR labelling and review progress prompts.
+
+### Deprecated
+
+## \[1.7.3\] - 2023-03-07
+
+### Added
+
+-   Improved developer docs (code generation stage).
+
+### Fixed
+
+-   #1337 : Bug causing overflow errors when templates are used in functions with a large number of arguments.
+-   #892 : Bug in the wrapper preventing an argument from using templates to have both a scalar and an array type.
+
+### Changed
+
+-   \[INTERNALS\] Add validation of docstrings to CI.
+
+### Deprecated
+
+## \[1.7.2\] - 2023-02-02
+
+### Added
+
+### Fixed
+
+-   #1288 : Bug in slice indexing in C code.
+-   #1318 : Bug preventing use of `np.linspace` more than once in a given function.
+
+### Changed
+
+-   \[INTERNALS\] Uniformise line endings and enforce the convention through the use of a `.gitattributes` file.
+-   \[INTERNALS\] Add human-readable summaries to tests.
+-   \[INTERNALS\] Add tests to ensure Pyccel conventions are followed.
+-   \[INTERNALS\] Add tests to check spelling.
+
+### Deprecated
+
+## \[1.7.1\] - 2023-01-26
+
+### Added
+
+-   #1309 : Support for `np.sum` in C code.
+-   Improved [developer docs](./developer_docs) (ordering, syntactic stage, semantic stage).
+-   Added [community guidelines](./github/CONTRIBUTING.md).
+
+### Fixed
+
+-   #1184 : Bug preventing compilation on systems where there is no static library available for Python.
+-   #1281 : Bug causing assignment to pointer instead of incrementation.
+-   #1282 : Imported constants cannot be returned from functions.
+-   \[INTERNALS\] Bug in CI coverage for forks.
+
+### Changed
+
+-   #1315 : Installation process modified to make test requirements a pip optional dependency.
+-   #1245 : Reduce false negative test results by using a tolerance to compare floats.
+-   #1272 : Remove use of deprecated NumPy syntax in tests.
+-   #1253 : Provide minimum requirements.
+
+### Deprecated
diff --git a/CHANGES b/CHANGES
deleted file mode 100644
index 1333ed77b7..0000000000
--- a/CHANGES
+++ /dev/null
@@ -1,1 +0,0 @@
-TODO
diff --git a/ci_tools/bot_interaction.py b/ci_tools/bot_interaction.py
new file mode 100644
index 0000000000..e3de344ac0
--- /dev/null
+++ b/ci_tools/bot_interaction.py
@@ -0,0 +1,508 @@
+"""
+This module contains all function and logic responsible for controlling the bot which reacts to PR creation and progress.
+"""
+import argparse
+import json
+import os
+import sys
+from git_evaluation_tools import leave_comment, get_status_json, get_job_information
+from git_evaluation_tools import check_previous_comments, set_ready, set_draft, get_review_status
+from git_evaluation_tools import check_previous_contributions, add_labels, remove_labels, get_labels
+from git_evaluation_tools import get_previous_pr_comments
+
+senior_reviewer = ['yguclu', 'EmilyBourne']
+trusted_reviewers = ['yguclu', 'EmilyBourne', 'ratnania', 'saidctb', 'bauom']
+
+pr_test_keys = ['linux', 'windows', 'macosx', 'coverage', 'docs', 'pylint',
+             'lint', 'spelling']
+
+review_labels = ('needs_initial_review', 'Ready_for_review', 'Ready_to_merge')
+
+comment_folder = os.path.join(os.path.dirname(__file__), 'bot_messages')
+
+def get_run_url(event):
+    """
+    Get the URL of the workflow run.
+
+    Use the event information to calculated the URL
+    where the results of the workflow can be viewed.
+
+    Parameters
+    ----------
+    event : dict
+        The event payload of the GitHub workflow.
+
+    Results
+    -------
+    str : The URL.
+    """
+    url = event['repository']['html_url']
+    run_id = event['run_number']
+    return f"{url}/actions/runs/{run_id}"
+
+def run_tests(pr_id, tests, outputs, event):
+    """
+    Run the requested tests and leave a comment on the PR.
+
+    Update the outputs to ensure that the requested tests are run.
+    Leave a comment on the PR using the GitHub CLI to indicate the relevant
+    commit, action and the test status.
+
+    Parameters
+    ----------
+    pr_id : int
+        The number of the PR.
+
+    tests : list of strs
+        The tests requested.
+
+    outputs : dict
+        The dictionary containing the output of the bot.
+
+    event : dict
+        The event payload of the GitHub workflow.
+    """
+    # Leave a comment to link to the run page
+    ref_sha = get_status_json(pr_id, 'headRefOid')
+    url = get_run_url(event)
+    comment = f"Running tests on commit {ref_sha}, for more details see [here]({url})\n"
+    leave_comment(pr_id, comment)
+
+    # Modify the flags to trigger the tests
+    if tests == ['pr_tests']:
+        tests = pr_test_keys
+    for t in tests:
+        outputs[f'run_{t}'] = True
+
+    if outputs['run_coverage']:
+        outputs['run_linux'] = True
+
+    outputs['status_url'] = event['repository']['statuses_url'].format(sha=ref_sha)
+
+def check_review_stage(pr_id):
+    """
+    Find the review stage.
+
+    Use the GitHub CLI to examine the reviews left on the pull request
+    and determine the current stage of the review process.
+
+    Parameters
+    ----------
+    pr_id : int
+        The number of the PR.
+
+    Results
+    -------
+    bool : Indicates if the PR is ready to merge.
+
+    bool : Assuming the PR is not ready to merge, indicates if the PR is
+            ready for a review from a senior reviewer.
+
+    requested_changes : List of authors who requested changes.
+
+    reviews : Summary of all reviews left on the PR.
+    """
+    reviews, _ = get_review_status(pr_id)
+    senior_review = [r for a,r in reviews.items() if a in senior_reviewer]
+
+    other_review = [r for a,r in reviews.items() if a not in senior_reviewer]
+
+    ready_to_merge = any(r.state == 'APPROVED' for r in senior_review) and not any(r.state == 'CHANGES_REQUESTED' for r in senior_review)
+
+    ready_for_senior_review = any(r.state == 'APPROVED' for r in other_review) and not any(r.state == 'CHANGES_REQUESTED' for r in other_review)
+
+    requested_changes = [a for a,r in reviews.items() if r.state == 'CHANGES_REQUESTED']
+
+    return ready_to_merge, ready_for_senior_review, requested_changes, reviews
+
+def set_review_stage(pr_id):
+    """
+    Set the flags for the review stage.
+
+    Determine the current stage of the review process from the state
+    of the reviews left on the pull request. Leave the flag indicating
+    that stage and a message encouraging reviews.
+
+    Parameters
+    ----------
+    pr_id : int
+        The number of the PR.
+    """
+    ready_to_merge, ready_for_senior_review, requested_changes, reviews = check_review_stage(pr_id)
+    author = get_status_json(pr_id, 'author')['login']
+    labels = get_labels(pr_id)
+    if ready_to_merge:
+        add_labels(pr_id, ['Ready_to_merge'])
+    elif ready_for_senior_review:
+        if 'Ready_for_review' not in labels:
+            add_labels(pr_id, ['Ready_for_review'])
+            if any(r in requested_changes for r in senior_reviewer):
+                if all(l not in review_labels for l in labels):
+                    requested = ', '.join(f'@{r}' for r in requested_changes)
+                    message = message_from_file('rerequest_review.txt').format(
+                                                    reviewers=requested, author=author)
+                    leave_comment(pr_id, message)
+            else:
+                names = ', '.join(f'@{r}' for r in senior_reviewer)
+                approved = ', '.join(f'@{r}' for r in reviews.values() if r.state == 'APPROVED')
+                message = message_from_file('senior_review.txt').format(
+                                reviewers=names, author=author, approved=approved)
+                leave_comment(pr_id, message)
+    else:
+        if all(l not in review_labels for l in labels):
+            add_labels(pr_id, ['needs_initial_review'])
+            if requested_changes:
+                if all(l not in review_labels for l in labels):
+                    requested = ', '.join(f'@{r}' for r in requested_changes)
+                    message = message_from_file('rerequest_review.txt').format(
+                                                    reviewers=requested, author=author)
+                    leave_comment(pr_id, message)
+            else:
+                message = message_from_file('new_pr.txt').format(author=author)
+                leave_comment(pr_id, message)
+
+def mark_as_ready(pr_id):
+    """
+    Mark the pull request as ready for review.
+
+    Use the GitHub CLI to check if the PR is really ready for review.
+    If this is the case then the correct flag is added and the draft
+    status is removed.
+
+    In order to be considered ready for review the PR must:
+    - Have all tests passing
+    - Have a non-trivial description
+
+    Parameters
+    ----------
+    pr_id : int
+        The number of the PR.
+    """
+    job_data = get_status_json(pr_id, 'statusCheckRollup')
+
+    job_data = [j for j in job_data if j.get('name', None) not in ('Bot', 'CleanUpBot') and j.get('context',None) != 'Tests on Draft']
+
+    failures = [j['name'] for j in job_data if j['conclusion'] in ('FAILURE', 'ACTION_REQUIRED')]
+
+    if failures:
+        set_draft(pr_id)
+        message = message_from_file('set_draft_failing.txt')
+        for f in failures:
+            message += f'- {f}\n'
+        leave_comment(pr_id, message)
+    else:
+        set_ready(pr_id)
+
+        set_review_stage(pr_id)
+
+    return 'failure' if failures else 'success'
+
+def message_from_file(filename):
+    """
+    Get the message saved in the file.
+
+    Reads the contents of the file `filename`, located in the
+    folder ./bot_messages/. The extracted string is returned for
+    use as a comment on a PR.
+
+    Parameters
+    ----------
+    filename : str
+        The name of the file to be read
+
+    Results
+    -------
+    str : The message to be printed.
+    """
+    with open(os.path.join(comment_folder, filename), encoding="utf-8") as msg_file:
+        comment = msg_file.read()
+    return comment
+
+def update_test_information(pr_id, event):
+    """
+    Update the PR with the information about the tests.
+
+    Use the GitHub CLI to check the results of the tests. If the last
+    comment made by the bot was for this set of tests then this comment
+    is updated to include the test results. Otherwise a new comment is
+    added with the results.
+
+    Parameters
+    ----------
+    pr_id : int
+        The number of the PR.
+
+    event : dict
+        The event payload of the GitHub workflow.
+    """
+    messages, last_message, _ = check_previous_comments(pr_id)
+
+    data = get_job_information(event['run_number'])
+
+    url = get_run_url(event)
+    relevant_messages = [m for m in messages if url in m]
+    ref_sha = relevant_messages[0].split()[4]
+    comment = f"Ran tests on commit {ref_sha} for more details see [here]({url})\n"
+    passed = True
+    for job in data:
+        conclusion = job['conclusion']
+        name = job['name']
+        if conclusion == 'skipped' or name in ('Bot', 'CleanUpBot'):
+            continue
+        job_passed = (conclusion == 'success')
+        icon = ':heavy_check_mark:' if job_passed else ':x:'
+        comment += f"- {icon} {name}\n"
+        passed &= job_passed
+
+    leave_comment(pr_id, comment, url in last_message)
+
+    return 'success' if passed else 'failure'
+
+def start_review_check(pr_id, event, outputs):
+    """
+    Check if the review is as ready as the author thinks.
+
+    Use the GitHub CLI to check if the PR has a meaningful
+    description (at least 3 words). If this is the case then the
+    tests are triggered to determine the final draft status.
+
+    Parameters
+    ----------
+    pr_id : int
+        The number of the PR.
+
+    event : dict
+        The event payload of the GitHub workflow.
+
+    outputs : dict
+        The dictionary containing the output of the bot.
+    """
+
+    description = get_status_json(pr_id, 'body')
+    words = description.split()
+
+    if len(words) < 3:
+        leave_comment(pr_id, message_from_file('set_draft_no_description.txt'))
+        set_draft(pr_id)
+    else:
+        outputs['cleanup_trigger'] = 'request_review_status'
+        run_tests(pr_id, ['pr_tests'], outputs, event)
+
+def flagged_as_trusted(pr_id, user):
+    """
+    Check if the user has been flagged as trusted.
+
+    Look through the previous comments on the PR to check if a trusted
+    user has flagged this user as trusted using the `/bot trust user X`
+    command.
+
+    Parameters
+    ----------
+    pr_id : int
+        The number of the PR.
+
+    user : str
+        The username of the user who may be untrustworthy.
+
+    Results
+    -------
+    bool : True if trustworthy, false otherwise.
+    """
+    trusted_comments = [c for c in get_previous_pr_comments(pr_id) if c.author in trusted_reviewers]
+    print(trusted_comments)
+    for c in trusted_comments:
+        words = c.body.strip().split()
+        print(words)
+        if words == ['/bot', 'trust', 'user', user]:
+            return True
+
+    return False
+
+if __name__ == '__main__':
+    parser = argparse.ArgumentParser(description='Call the function to activate the bot')
+    parser.add_argument('gitEvent', type=str,
+                        help='File containing the json description of the triggering event')
+    parser.add_argument('output', type=str,
+                        help='File where the variables should be saved')
+    parser.add_argument('run_id', type=int,
+                        help='The id of the runner (used to identify the action page)')
+    parser.add_argument('cleanup_trigger', type=str, nargs='?', default='',
+                        help='A key to be passed when the bot is used to clean up after tests have run [request_review_status,update_test_information]')
+
+    args = parser.parse_args()
+
+    # Parse event payload from $GITHUB_EVENT_PATH variable
+    # (documented here : https://docs.github.com/en/actions/learn-github-actions/variables#default-environment-variables)
+    # The contents of this json file depend on the triggering event and are
+    # described here :  https://docs.github.com/en/webhooks-and-events/webhooks/webhook-events-and-payloads
+    with open(args.gitEvent, encoding="utf-8") as event_file:
+        event = json.load(event_file)
+
+    # Save run number into dictionary with event information
+    event['run_number'] = args.run_id
+
+    cleanup_trigger = args.cleanup_trigger
+
+    # Initialise outputs
+    outputs = {'run_linux': False,
+               'run_windows': False,
+               'run_macosx': False,
+               'run_coverage': False,
+               'run_docs': False,
+               'run_pylint': False,
+               'run_lint': False,
+               'run_spelling': False,
+               'run_pickle': False,
+               'run_editable_pickle': False,
+               'run_pickle_wheel': False,
+               'run_linux_anaconda': False,
+               'run_windows_anaconda': False,
+               'cleanup_trigger': '',
+               'python_version': '',
+               'BASE': '',
+               'REF': '',
+               'SHA': ''}
+
+    if cleanup_trigger == 'request_review_status':
+        # Collect id from an issue_comment event with a created action
+        # or from a pull_request event with a synchronize action
+        if 'number' in event:
+            pr_id = event['number']
+        else:
+            pr_id = event['issue']['number']
+        update_test_information(pr_id, event)
+        result = mark_as_ready(pr_id)
+        with open(args.output, encoding="utf-8", mode='a') as out_file:
+            print(f"global_state={result}", file=out_file)
+        sys.exit()
+
+    elif cleanup_trigger == 'update_test_information':
+        # If reporting after run
+
+        # Collect id from a comment event
+        pr_id = event['issue']['number']
+
+        result = update_test_information(pr_id, event)
+        with open(args.output, encoding="utf-8", mode='a') as out_file:
+            print(f"global_state={result}", file=out_file)
+        sys.exit()
+
+    elif 'comment' in event and 'pull_request' in event['issue'] and event['comment']['body'].startswith('/bot'):
+        # If bot called explicitly (comment event)
+
+        # Collect id from an issue_comment event with a created action
+        pr_id = event['issue']['number']
+
+        trusted_user = event['comment']['author_association'] in ('COLLABORATOR', 'CONTRIBUTOR', 'MEMBER', 'OWNER')
+        if not trusted_user:
+            trusted_user = flagged_as_trusted(pr_id, event['comment']['user']['login'])
+
+        comment = event['comment']['body']
+        command = comment.split('/bot')[1].strip()
+        command_words = command.split()
+        print(command_words)
+
+        if command_words[0] == 'run':
+            if trusted_user:
+                outputs['cleanup_trigger'] = 'update_test_information'
+                run_tests(pr_id, command_words[1:], outputs, event)
+
+        elif command_words[0] == 'try':
+            if trusted_user:
+                outputs['python_version'] = command_words[1]
+                outputs['cleanup_trigger'] = 'update_test_information'
+                run_tests(pr_id, command_words[2:], outputs, event)
+
+        elif command == 'mark as ready':
+            if trusted_user:
+                start_review_check(pr_id, event, outputs)
+
+        elif command == 'show tests':
+            leave_comment(pr_id, message_from_file('show_tests.txt'))
+
+        elif command_words[:2] == ['trust', 'user'] and len(command_words)==3:
+            user = command_words[2]
+            leave_comment(pr_id, message_from_file('trusting_user.txt').format(user=user))
+            pr_author = get_status_json(pr_id, 'author')
+            draft = get_status_json(pr_id, 'isDraft')
+            if not draft and user == pr_author:
+                outputs['cleanup_trigger'] = 'request_review_status'
+                run_tests(pr_id, ['pr_tests'], outputs, event)
+
+        else:
+            leave_comment(pr_id, message_from_file('bot_commands.txt'))
+
+    elif event['action'] == 'opened':
+        # If new PR (opened trigger)
+
+        # Collect id from a pull request event with an opened action
+        pr_id = event['number']
+
+        # Check whether user is new and/or trusted
+        trusted_user = event['pull_request']['author_association'] in ('COLLABORATOR', 'CONTRIBUTOR', 'MEMBER', 'OWNER')
+        print(event['pull_request']['author_association'])
+        if trusted_user:
+            prs = check_previous_contributions(event['repository']['full_name'], event['pull_request']['user']['login'])
+            print(prs)
+            new_user = (len(prs) == 0)
+        else:
+            new_user = True
+
+        # Choose appropriate message to welcome author
+        file = 'welcome_newcomer.txt' if new_user else 'welcome_friend.txt'
+
+        leave_comment(pr_id, message_from_file(file) + message_from_file('checklist.txt'))
+
+        # Ensure PR is draft
+        if not event['pull_request']['draft']:
+            set_draft(pr_id)
+
+        # If unknown user ask for trust approval
+        if not trusted_user:
+            leave_comment(pr_id, ", ".join(senior_reviewer)+", please can you check if I can trust this user. If you are happy, let me know with `/bot trust user`")
+
+    elif event['action'] == 'converted_to_draft':
+        # Collect id from a pull_request event with a converted_to_draft action
+        pr_id = event['number']
+
+        remove_labels(pr_id, ['Ready_to_merge', 'Ready_for_review', 'needs_initial_review'])
+
+    elif 'review' in event:
+        pr_id = event['pull_request']['number']
+        state = event['review']['state']
+        if state == 'approved':
+            labels = get_status_json(pr_id, 'labels')
+            remove_labels(pr_id, ['Ready_to_merge', 'Ready_for_review', 'needs_initial_review'])
+            set_review_stage(pr_id)
+        elif state == 'changes_requested':
+            labels = get_status_json(pr_id, 'labels')
+            remove_labels(pr_id, ['Ready_to_merge', 'Ready_for_review', 'needs_initial_review'])
+            set_draft(pr_id)
+            author = get_status_json(pr_id, 'author')['login']
+            reviewer = event['review']['user']['login']
+            leave_comment(pr_id, message_from_file('set_draft_changes.txt').format(author=author, reviewer=reviewer))
+
+    elif 'pull_request' in event and not event['pull_request']['draft']:
+        # If PR is ready for review
+
+        # Collect id from a pull_request event
+        pr_id = event['number']
+        trusted_user = event['pull_request']['author_association'] in ('COLLABORATOR', 'CONTRIBUTOR', 'MEMBER', 'OWNER')
+        if not trusted_user:
+            trusted_user = flagged_as_trusted(pr_id, event['comment']['user']['login'])
+
+        if trusted_user:
+            start_review_check(pr_id, event, outputs)
+
+    else:
+        pr_id = None
+
+    if pr_id is not None:
+        outputs['BASE'] = get_status_json(pr_id, 'baseRefName')
+        outputs['REF'] = f'refs/pull/{pr_id}/merge'
+
+    # Print the output to the file described by $GITHUB_OUTPUT to create outputs
+    # as described here : https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-an-output-parameter
+    with open(args.output, encoding="utf-8", mode='a') as out_file:
+        for o,v in outputs.items():
+            print(f"{o}={v}", file=out_file)
diff --git a/ci_tools/bot_messages/bot_commands.txt b/ci_tools/bot_messages/bot_commands.txt
new file mode 100644
index 0000000000..b5ab3c19db
--- /dev/null
+++ b/ci_tools/bot_messages/bot_commands.txt
@@ -0,0 +1,9 @@
+This bot reacts to all comments which begin with `/bot`. This phrase can be followed by any of these commands:
+- `show tests` : Lists the tests which can be triggered
+- `run X` : Triggers the test X (acceptable values for X can be seen using `show tests`). Multiple tests can be specified separated by spaces.
+- `try V X` : Triggers the test X (acceptable values for X can be seen using `show tests`) using python version V. Only one test can be run at a time.
+- `mark as ready` : Adds the appropriate review flag and requests reviews. This command should be used when the PR is first ready for review, or when a review has been answered.
+- `commands` : Shows this list detailing all the commands which are understood.
+- `trust user X` : Tells the bot that a new user X is trusted to run workflows (prevents misuse of GitHub actions for mining etc). This command can only be used by a trusted reviewer.
+
+Beware: if you have never contributed to this repository and you are not a member of the Pyccel organisation, the bot will ignore all requests to run tests until permitted by a trusted reviewer.
diff --git a/ci_tools/bot_messages/checklist.txt b/ci_tools/bot_messages/checklist.txt
new file mode 100644
index 0000000000..d36e3a3e50
--- /dev/null
+++ b/ci_tools/bot_messages/checklist.txt
@@ -0,0 +1,6 @@
+- [ ] Write a clear PR description
+- [ ] Add tests to check your code works as expected
+- [ ] Update documentation if necessary
+- [ ] Update Changelog
+- [ ] Ensure any relevant issues are linked
+- [ ] Ensure tests are passing
diff --git a/ci_tools/bot_messages/new_pr.txt b/ci_tools/bot_messages/new_pr.txt
new file mode 100644
index 0000000000..b47a4a1e41
--- /dev/null
+++ b/ci_tools/bot_messages/new_pr.txt
@@ -0,0 +1,1 @@
+Hey @pyccel/pyccel-dev ! @{author} has just created this great new pull request! Check it out and let me know what you think!
diff --git a/ci_tools/bot_messages/rerequest_review.txt b/ci_tools/bot_messages/rerequest_review.txt
new file mode 100644
index 0000000000..205c4a42d4
--- /dev/null
+++ b/ci_tools/bot_messages/rerequest_review.txt
@@ -0,0 +1,1 @@
+{reviewers}, @{author} has been working hard and thinks that they have now replied to or fixed all your comments. Could you take another look at the PR and see if you can approve now?
diff --git a/ci_tools/bot_messages/senior_review.txt b/ci_tools/bot_messages/senior_review.txt
new file mode 100644
index 0000000000..53ca2b9eed
--- /dev/null
+++ b/ci_tools/bot_messages/senior_review.txt
@@ -0,0 +1,1 @@
+Hey {reviewers}, this PR is looking pretty good. @{author} and {approved} think it is ready to merge. Could you add your expertise to confirm that this follows all the coding conventions and fits in Pyccel's future plans? Thanks :smile:
diff --git a/ci_tools/bot_messages/set_draft_changes.txt b/ci_tools/bot_messages/set_draft_changes.txt
new file mode 100644
index 0000000000..28a4155b00
--- /dev/null
+++ b/ci_tools/bot_messages/set_draft_changes.txt
@@ -0,0 +1,1 @@
+@{author}, @{reviewer} has a few questions/comments about your code. Can you go through and see if you agree with them. If not go ahead and explain why. Once you've adressed all the comments let me know with `/bot mark as ready` and we will see if we can get approval.
diff --git a/ci_tools/bot_messages/set_draft_failing.txt b/ci_tools/bot_messages/set_draft_failing.txt
new file mode 100644
index 0000000000..a42110555b
--- /dev/null
+++ b/ci_tools/bot_messages/set_draft_failing.txt
@@ -0,0 +1,4 @@
+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`.
+
+The failing tests are:
+
diff --git a/ci_tools/bot_messages/set_draft_no_description.txt b/ci_tools/bot_messages/set_draft_no_description.txt
new file mode 100644
index 0000000000..56b4cac9d7
--- /dev/null
+++ b/ci_tools/bot_messages/set_draft_no_description.txt
@@ -0,0 +1,1 @@
+It seems like you may have forgotten to write a detailed description for this pull request. Please could you fix that and anything else missing from your checklist. Let me know when this is fixed with `/bot mark as ready`.
diff --git a/ci_tools/bot_messages/trusting_user.txt b/ci_tools/bot_messages/trusting_user.txt
new file mode 100644
index 0000000000..6147bde159
--- /dev/null
+++ b/ci_tools/bot_messages/trusting_user.txt
@@ -0,0 +1,1 @@
+@{user} It looks like the Pyccel maintainers trust you :rocket:. I will now start running tests when you request them.
diff --git a/ci_tools/bot_messages/welcome_friend.txt b/ci_tools/bot_messages/welcome_friend.txt
new file mode 100644
index 0000000000..1c084cc6f8
--- /dev/null
+++ b/ci_tools/bot_messages/welcome_friend.txt
@@ -0,0 +1,5 @@
+Hello again! Thank you for this new pull request :star_struck:.
+
+Don't forget to let me know when it is complete with the command `/bot mark as ready`.
+
+Here is your checklist:
diff --git a/ci_tools/bot_messages/welcome_newcomer.txt b/ci_tools/bot_messages/welcome_newcomer.txt
new file mode 100644
index 0000000000..db1a79312c
--- /dev/null
+++ b/ci_tools/bot_messages/welcome_newcomer.txt
@@ -0,0 +1,8 @@
+Hello! Welcome to Pyccel! Thank you very much for your contribution :heart:.
+
+I am the GitHub bot. I will help guide you through the different stages necessary to validate a review in Pyccel. If you haven't yet seen our developer docs make sure you check them out [here](https://github.com/pyccel/pyccel/tree/master/developer_docs). Amongst other things they describe the [review process](https://github.com/pyccel/pyccel/blob/master/developer_docs/review_process.md) that we have just started. You can also get in touch with our other developers on our [Pyccel Discord Server](https://discord.gg/2Q6hwjfFVb).
+
+To begin with I will give you a short checklist to make sure your pull request is complete. If you want me to run the tests you can request this using the command `/bot run pr_tests`. Once you have finished preparing your pull request and are ready to request reviews just let me know with the command `/bot mark as ready`. You can get a full list of commands that I understand using `/bot commands`.
+
+Here is your checklist:
+- [ ] Update AUTHORS file
diff --git a/ci_tools/git_evaluation_tools.py b/ci_tools/git_evaluation_tools.py
index 4290ab4e9d..28da37a8da 100644
--- a/ci_tools/git_evaluation_tools.py
+++ b/ci_tools/git_evaluation_tools.py
@@ -1,26 +1,92 @@
-""" Tools to help examine git information
+""" Tools to help examine git information and interact with git
 """
+from collections import namedtuple
+from datetime import datetime
+import json
+import shutil
+import subprocess
+
+__all__ = ('github_cli',
+           'ReviewComment',
+           'get_diff_as_json',
+           'get_previous_pr_comments',
+           'check_previous_comments',
+           'get_labels',
+           'get_review_status',
+           'leave_comment',
+           'add_labels',
+           'remove_labels',
+           'set_draft',
+           'set_ready',
+           'get_job_information',
+           'check_previous_contributions'
+           )
+
+github_cli = shutil.which('gh')
+
+ReviewComment = namedtuple('ReviewComment', ['state', 'date', 'author'])
+Comment = namedtuple('Comment', ['body', 'date', 'author'])
+
+def get_status_json(pr_id, tags):
+    """
+    Get the tagged status of a PR in json format.
+
+    Use the GitHub CLI to investigate a certain property,
+    passed as a tag, of a PR. Multiple tags can also be
+    provided. In this case the result is a dictionary with
+    the tags appearing as keys.
+    Otherwise the value is provided directly (but this may itself
+    be a dictionary for certain tags). See the [GitHub CLI docs](https://cli.github.com/manual/gh_pr_view)
+    for more details.
+
+    Parameters
+    ----------
+    pr_id : int
+        The number of the PR.
+
+    tags : str
+        The tag of the information we are enquiring about.
+        Multiple tags must be separated by a comma.
+
+    Results
+    -------
+    dict/str : The output of the request.
+    """
+    # Check status of PR
+    cmds = [github_cli, 'pr', 'view', str(pr_id), '--json', tags]
+    with subprocess.Popen(cmds, stdout=subprocess.PIPE) as p:
+        result, _ = p.communicate()
+
+    data = json.loads(result)
+
+    if ',' in tags:
+        return data
+    else:
+        return data[tags]
 
 def get_diff_as_json(filename):
     """
+    Get a dictionary describing the changes.
+
     A function which converts the output of a reduced git diff call
     to a dictionary that can be exported using json.
     The diff call should use the argument `--unified=0`
+    The result is a dictionary whose keys are files which have been
+    changed in this branch and whose values are a dictionary.
+    The dictionary is itself a dictionary with the keys 'addition'
+    and 'deletion' whose values are lists containing the line
+    numbers of lines which have been changed/added (addition) or
+    changed/deleted (deletion).
 
     Parameters
     ----------
     filename : str
-            The file where the diff was printed
+        The file where the diff was printed.
 
     Returns
     -------
     changes : dict
-            A dictionary whose keys are files which have been
-            changed in this branch and whose values are a dictionary.
-            The dictionary is itself a dictionary with the keys 'addition'
-            and 'deletion' whose values are lists containing the line
-            numbers of lines which have been changed/added (addition) or
-            changed/deleted (deletion)
+        Dictionary describing changes to the files.
     """
     with open(filename, encoding="utf-8") as f:
         lines = f.readlines()
@@ -86,3 +152,269 @@ def get_diff_as_json(filename):
         changes[current_file_name]['deletion'] = current_file_deletions
 
     return changes
+
+def get_previous_pr_comments(pr_id):
+    """
+    Get all previous comments left on the PR.
+
+    Get a list of all comments left on the PR as reported by the GitHub
+    CLI.
+
+    Parameters
+    ----------
+    pr_id : int
+        The number of the PR.
+
+    Results
+    -------
+    list : A list of all the messages left on the PR.
+    """
+    relevant_comments = get_status_json(pr_id, 'comments')
+
+    comments = [Comment(c["body"], datetime.fromisoformat(c['createdAt'].strip('Z')), c['author']['login'])
+                        for c in relevant_comments]
+    return comments
+
+def check_previous_comments(pr_id):
+    """
+    Get information about previous comments made by the bot.
+
+    Get a list of all comments left by the bot as well as its most recent comment
+    to avoid it repeating itself unnecessarily
+
+    Parameters
+    ----------
+    pr_id : int
+        The number of the PR.
+
+    Results
+    -------
+    list : A list of all messages left by the bot on this PR.
+
+    str : The last message left by the bot.
+
+    datetime : The last time the bot commented.
+    """
+    comments = get_previous_pr_comments(pr_id)
+    my_comments = [c for c in comments if c.author == 'github-actions']
+
+    if len(my_comments) == 0:
+        return [], '', None
+    else:
+        last_messages = {}
+        final_message = my_comments[0].body
+        final_date = my_comments[0].date
+
+        for c in my_comments:
+            if c.body not in last_messages:
+                last_messages[c.body] = c.date
+            elif last_messages[c.body] < c.date:
+                last_messages[c.body] = c.date
+
+            if final_date < c.date:
+                final_message = c.body
+                final_date = c.date
+
+        return last_messages, final_message, final_date
+
+
+def get_labels(pr_id):
+    """
+    Get the labels associated with the PR.
+
+    Use GitHub's command-line tool to get all labels for
+    all PRs related to this branch.
+
+    Results
+    -------
+    list : A list of the names of all the labels.
+    """
+    label_json = get_status_json(pr_id, 'labels')
+    current_labels = [l['name'] for l in label_json]
+    return current_labels
+
+
+
+def get_review_status(pr_id):
+    """
+    Get the reviews left on the PR.
+
+    Get a dictionary describing the current state of the reviews
+    on the PR. 
+
+    Results
+    -------
+    dict : Keys are authors of reviews, values are the state of their review.
+    """
+    reviews = get_status_json(pr_id, 'reviews')
+    requests = get_status_json(pr_id, 'reviewRequests')
+
+    requested_authors = [r["login"] for r in requests]
+
+    review_status = {}
+    for r in reviews:
+        author = r['author']['login']
+        date = datetime.fromisoformat(r['submittedAt'].strip('Z'))
+        state = r['state']
+        if author not in review_status:
+            review_status[author] = ReviewComment(state, date, author)
+        elif state != 'COMMENTED' and review_status[author].date < date:
+            review_status[author] = ReviewComment(state, date, author)
+    for a in review_status:
+        if a in requested_authors:
+            review_status[a] = ReviewComment('REVIEW_REQUESTED', review_status[a].date, a)
+    for a in requested_authors:
+        if a not in review_status:
+            review_status[a] = ReviewComment('UNRESPONSIVE', None, a)
+    return review_status, requested_authors
+
+
+def get_job_information(run_id):
+    """
+    Get information about the jobs run.
+
+    Use the GitHub CLI to check all information about the jobs
+    related to a workflow.
+
+    Results
+    -------
+    bool : Indicates if tests are passed
+    """
+    cmd = [github_cli, 'run', 'view', str(run_id), '--json', 'jobs']
+    with subprocess.Popen(cmd, stdout=subprocess.PIPE) as p:
+        result, _ = p.communicate()
+    return json.loads(result)['jobs']
+
+
+def leave_comment(number, comment, edit = False):
+    """
+    Leave a comment on the PR.
+
+    Use GitHub's command-line interface to leave a comment
+    on the request PR related to this branch.
+
+    Parameters
+    ----------
+    number : int
+        The number of the PR.
+
+    comment : str
+        The comment which should be left on the PR.
+
+    edit : bool, default: False
+        Indicates whether the bot should edit the last comment
+        or just write a new comment.
+    """
+    cmds = [github_cli, 'pr', 'comment', str(number), '-b', comment]
+
+    if edit:
+        cmds.append('--edit-last')
+
+    with subprocess.Popen(cmds, stdout=subprocess.PIPE) as p:
+        p.communicate()
+
+
+
+def add_labels(number, labels):
+    """
+    Add the specified labels to the PR.
+
+    Use GitHub's command-line interface to add all the specified
+    labels from a PR.
+
+    Parameters
+    ----------
+    number : int
+        The number of the PR.
+
+    labels : list
+        A list of the labels to be added.
+    """
+
+    cmds = [github_cli, 'pr', 'edit', str(number)]
+    for lab in labels:
+        cmds += ['--add-label', lab]
+
+    with subprocess.Popen(cmds) as p:
+        p.communicate()
+
+
+def remove_labels(number, labels):
+    """
+    Remove the specified labels from the PR.
+
+    Use GitHub's command-line interface to remove all the specified
+    labels from a PR.
+
+    Parameters
+    ----------
+    number : int
+        The number of the PR.
+
+    labels : list
+        A list of the labels to be removed.
+    """
+
+    cmds = [github_cli, 'pr', 'edit', str(number)]
+    for lab in labels:
+        cmds += ['--remove-label', lab]
+
+    with subprocess.Popen(cmds) as p:
+        p.communicate()
+
+
+def set_ready(number):
+    """
+    Remove draft status from PR.
+
+    Use GitHub's command-line interface to remove the draft status of
+    the PR.
+
+    Parameters
+    ----------
+    number : int
+        The number of the PR.
+    """
+    cmds = [github_cli, 'pr', 'ready', str(number)]
+
+    with subprocess.Popen(cmds) as p:
+        p.communicate()
+
+
+def set_draft(number):
+    """
+    Set PR to draft.
+
+    Use GitHub's command-line interface to set the PR to a draft.
+
+    Parameters
+    ----------
+    number : int
+        The number of the PR.
+    """
+    cmds = [github_cli, 'pr', 'ready', str(number), '--undo']
+
+    with subprocess.Popen(cmds) as p:
+        p.communicate()
+
+def check_previous_contributions(repo, author):
+    """
+    Get a list of previous PRs made on this repository by the author.
+
+    Use the GitHub CLI to get a dictionary listing the number and state
+    of all the PRs previously opened by this author on the repository.
+
+    Parameters
+    ----------
+    repo : str
+        The name of the repository (e.g. 'pyccel/pyccel')
+
+    author : str
+        The username of the author
+    """
+    cmds = [github_cli, 'search', 'prs', '--author', author, '--repo', repo, '--json', 'number,state']
+
+    with subprocess.Popen(cmds, stdout=subprocess.PIPE) as p:
+        result, _ = p.communicate()
+
+    return json.loads(result)


Test patch:
diff --git a/.github/actions/pytest_run/action.yml b/.github/actions/pytest_run/action.yml
index a37b15d589..13f20d7c04 100644
--- a/.github/actions/pytest_run/action.yml
+++ b/.github/actions/pytest_run/action.yml
@@ -3,7 +3,11 @@ inputs:
   shell_cmd:
     description: 'Specifies the shell command (different for anaconda)'
     required: false
-    default: "bash"
+    default: 'bash'
+  pytest_mark:
+    description: 'Mark expression to exclude additional tests'
+    required: false
+    default: ''
 
 
 runs:
@@ -12,17 +16,17 @@ runs:
     - name: Test with pytest
       run: |
         which python
-        python -m pytest -n auto -rXx -v -m "not (parallel or xdist_incompatible) and c" --ignore=symbolic --ignore=ndarrays
+        python -m pytest -n auto -rXx -v -m "not (parallel or xdist_incompatible) and c ${{ inputs.pytest_mark }}" --ignore=symbolic --ignore=ndarrays
         if [ -n "${SITE_DIR}" ]; then
             echo "Touching"
             # Test ndarray folder update (requires parallel tests to avoid clean)
             touch ${SITE_DIR}/pyccel/stdlib/cwrapper/cwrapper.h
             python -m pytest -n auto -rXx -v -m c -k test_array_int32_1d_scalar epyccel/test_arrays.py
         fi
-        python -m pytest -rXx -m "xdist_incompatible and not parallel and c" --ignore=symbolic --ignore=ndarrays
+        python -m pytest -rXx -m "xdist_incompatible and not parallel and c ${{ inputs.pytest_mark }}" --ignore=symbolic --ignore=ndarrays
         pyccel-clean
-        python -m pytest -n auto -rXx -m "not (parallel or xdist_incompatible) and not (c or python)" --ignore=symbolic --ignore=ndarrays
-        python -m pytest -rXx -m "xdist_incompatible and not parallel and not (c or python)" --ignore=symbolic --ignore=ndarrays
+        python -m pytest -n auto -rXx -m "not (parallel or xdist_incompatible) and not (c or python) ${{ inputs.pytest_mark }}" --ignore=symbolic --ignore=ndarrays
+        python -m pytest -rXx -m "xdist_incompatible and not parallel and not (c or python) ${{ inputs.pytest_mark }}" --ignore=symbolic --ignore=ndarrays
         pyccel-clean
         python -m pytest ndarrays/ -rXx
         pyccel-clean
diff --git a/.github/workflows/Github_pytest.yml b/.github/workflows/Github_pytest.yml
index 66bd2da398..2cacdb2d47 100644
--- a/.github/workflows/Github_pytest.yml
+++ b/.github/workflows/Github_pytest.yml
@@ -1,137 +1,213 @@
-name: Pyccel tests
+name: Pull Request
 
 on:
   pull_request:
     branches: [ master ]
+    types: [ opened, ready_for_review, synchronize, converted_to_draft ]
+  issue_comment:
+    types: [ created ]
+  pull_request_review:
+    types: [ submitted ]
 
 jobs:
-  Linux:
-
+  Bot:
+    if: ${{ ( github.event_name == 'pull_request' ) || (github.event_name == 'issue_comment' && github.event.issue.pull_request ) || github.event_name == 'pull_request_review' }}
     runs-on: ubuntu-latest
-
+    outputs:
+      run_linux: ${{ steps.run_bot.outputs.run_linux }}
+      run_windows: ${{ steps.run_bot.outputs.run_windows }}
+      run_macosx: ${{ steps.run_bot.outputs.run_macosx }}
+      run_coverage: ${{ steps.run_bot.outputs.run_coverage }}
+      run_docs: ${{ steps.run_bot.outputs.run_docs }}
+      run_pylint: ${{ steps.run_bot.outputs.run_pylint }}
+      run_lint: ${{ steps.run_bot.outputs.run_lint }}
+      run_spelling: ${{ steps.run_bot.outputs.run_spelling }}
+      run_pickle: ${{ steps.run_bot.outputs.run_pickle }}
+      run_editable_pickle: ${{ steps.run_bot.outputs.run_editable_pickle }}
+      run_pickle_wheel: ${{ steps.run_bot.outputs.run_pickle_wheel }}
+      run_linux_anaconda: ${{ steps.run_bot.outputs.run_linux_anaconda }}
+      run_windows_anaconda: ${{ steps.run_bot.outputs.run_windows_anaconda }}
+      BASE: ${{ steps.run_bot.outputs.BASE }}
+      REF: ${{ steps.run_bot.outputs.REF }}
+      status_url: ${{ steps.run_bot.outputs.status_url }}
+      cleanup_trigger: ${{ steps.run_bot.outputs.cleanup_trigger }}
+      python_version: ${{ steps.run_bot.outputs.python_version }}
     steps:
       - uses: actions/checkout@v3
-      - name: Set up Python 3.7
+      - name: Set up Python ${{ inputs.python_version }}
         uses: actions/setup-python@v4
         with:
-          python-version: 3.7
-      - name: Install dependencies
-        uses: ./.github/actions/linux_install
-      - name: Install Pyccel with tests
+          python-version: 3.9
+      - id: run_bot
         run: |
-            python -m pip install --upgrade pip
-            python -m pip install .[test]
-        shell: bash
-      - name: Coverage install
-        uses: ./.github/actions/coverage_install
-      - name: Fortran/C tests with pytest
-        uses: ./.github/actions/pytest_run
-      - name: Python tests with pytest
-        uses: ./.github/actions/pytest_run_python
-      - name: Parallel tests with pytest
-        uses: ./.github/actions/pytest_parallel
-      - name: Test with valgrind for memory leaks
-        uses: ./.github/actions/valgrind_run
-      - name: Collect coverage information
-        continue-on-error: True
-        uses: ./.github/actions/coverage_collection
-      - name: Run codacy-coverage-reporter
-        uses: codacy/codacy-coverage-reporter-action@master
-        continue-on-error: True
-        with:
-          project-token: ${{ secrets.CODACY_PROJECT_TOKEN }}
-          coverage-reports: cobertura.xml
-      - name: Save code coverage report
-        uses: actions/upload-artifact@v3
-        with:
-          name: coverage-artifact
-          path: cobertura.xml
-          retention-days: 1
+          python ci_tools/bot_interaction.py $GITHUB_EVENT_PATH $GITHUB_OUTPUT ${{ github.run_id }}
+        env:
+          GH_TOKEN: ${{ github.token }}
+      - name: Post status
+        if: ${{ steps.run_bot.outputs.cleanup_trigger != '' && github.event_name != 'pull_request' }}
+        run: |
+          gh api --method POST -H "Accept: application/vnd.github+json" \
+            ${{ steps.run_bot.outputs.status_url }} \
+            -f state='pending' -f target_url="${{ github.event.repository.html_url }}/actions/runs/${{ github.run_id }}" \
+            -f description="${{ github.event.comment.body }}" -f context="Tests on Draft"
+        env:
+          GH_TOKEN: ${{ github.token }}
 
-  Windows:
+  linux:
+    needs: Bot
+    if: ${{ needs.Bot.outputs.run_linux == 'True' }}
+    uses:
+      ./.github/workflows/linux.yml
+    with:
+      python_version: ${{ (needs.Bot.outputs.python_version == '') && '3.7' || needs.Bot.outputs.python_version  }}
+      ref: ${{ needs.Bot.outputs.REF}}
 
-    runs-on: windows-latest
+  windows:
+    needs: Bot
+    if: ${{ needs.Bot.outputs.run_windows == 'True' }}
+    uses:
+      ./.github/workflows/windows.yml
+    with:
+      python_version: ${{ (needs.Bot.outputs.python_version == '') && '3.7' || needs.Bot.outputs.python_version  }}
+      ref: ${{ needs.Bot.outputs.REF }}
 
-    steps:
-      - uses: actions/checkout@v3
-      - name: Setup Python 3.9
-        uses: actions/setup-python@v4
-        with:
-            # The second most recent version is used as
-            # setup-python installs the most recent patch
-            # which leads to linking problems as there are
-            # 2 versions of python3X.a and the wrong one
-            # is chosen
-            python-version: 3.9
-      # Uncomment to examine DLL requirements with 'objdump -x FILE'
-      #- name: Install mingw tools
-      #  uses: msys2/setup-msys2@v2
-      - name: Install dependencies
-        uses: ./.github/actions/windows_install
-      - name: Install Pyccel with tests
-        run: |
-            python -m pip install --upgrade pip
-            python -m pip install .[test]
-        shell: bash
-      - name: Fortran/C tests with pytest
-        uses: ./.github/actions/pytest_run
-      - name: Python tests with pytest
-        uses: ./.github/actions/pytest_run_python
-      - name: Parallel tests with pytest
-        uses: ./.github/actions/pytest_parallel
+  macosx:
+    needs: Bot
+    if: ${{ needs.Bot.outputs.run_macosx == 'True' }}
+    uses:
+      ./.github/workflows/macosx.yml
+    with:
+      python_version: ${{ (needs.Bot.outputs.python_version == '') && '3.10' || needs.Bot.outputs.python_version  }}
+      ref: ${{ needs.Bot.outputs.REF }}
 
-  MacOSX:
+  coverage:
+    needs: [Bot, Linux]
+    if: ${{ needs.Bot.outputs.run_coverage == 'True' }}
+    uses:
+      ./.github/workflows/coverage.yml
+    with:
+      python_version: ${{ (needs.Bot.outputs.python_version == '') && '3.7' || needs.Bot.outputs.python_version  }}
+      ref: ${{ needs.Bot.outputs.REF }}
 
-    runs-on: macos-latest
+  docs:
+    needs: Bot
+    if: ${{ needs.Bot.outputs.run_docs == 'True' }}
+    uses:
+      ./.github/workflows/doc_coverage.yml
+    with:
+      python_version: ${{ (needs.Bot.outputs.python_version == '') && '3.8' || needs.Bot.outputs.python_version  }}
+      base: ${{ needs.Bot.outputs.BASE }}
+      ref: ${{ needs.Bot.outputs.REF }}
 
-    steps:
-      - uses: actions/checkout@v3
-      - name: Set up Python 3.10
-        uses: actions/setup-python@v4
-        with:
-          python-version: '3.10'
-      - name: Install dependencies
-        uses: ./.github/actions/macos_install
-      - name: Install Pyccel with tests
-        run: |
-            python -m pip install --upgrade pip
-            python -m pip install .[test]
-        shell: bash
-      - name: Fortran/C tests with pytest
-        uses: ./.github/actions/pytest_run
-      - name: Python tests with pytest
-        uses: ./.github/actions/pytest_run_python
-      - name: Parallel tests with pytest
-        uses: ./.github/actions/pytest_parallel
-
-  CoverageChecker:
+  pylint:
+    needs: Bot
+    if: ${{ needs.Bot.outputs.run_pylint == 'True' }}
+    uses:
+      ./.github/workflows/lint.yml
+    with:
+      python_version: ${{ (needs.Bot.outputs.python_version == '') && '3.8' || needs.Bot.outputs.python_version  }}
+      ref: ${{ needs.Bot.outputs.REF }}
 
-    runs-on: ubuntu-latest
-    needs: Linux
+  lint:
+    needs: Bot
+    if: ${{ needs.Bot.outputs.run_lint == 'True' }}
+    uses:
+      ./.github/workflows/pyccel_lint.yml
+    with:
+      python_version: ${{ (needs.Bot.outputs.python_version == '') && '3.8' || needs.Bot.outputs.python_version  }}
+      ref: ${{ needs.Bot.outputs.REF }}
+
+  spelling:
+    needs: Bot
+    if: ${{ needs.Bot.outputs.run_spelling == 'True' }}
+    uses:
+      ./.github/workflows/spelling.yml
+    with:
+      python_version: ${{ (needs.Bot.outputs.python_version == '') && '3.8' || needs.Bot.outputs.python_version  }}
+      ref: ${{ needs.Bot.outputs.REF }}
+
+  pickle:
+    needs: Bot
+    if: ${{ needs.Bot.outputs.run_pickle == 'True' }}
+    uses:
+      ./.github/workflows/pickle.yml
+    with:
+      python_version: ${{ (needs.Bot.outputs.python_version == '') && '3.7' || needs.Bot.outputs.python_version  }}
+      ref: ${{ needs.Bot.outputs.REF }}
+
+  editable_pickle:
+    needs: Bot
+    if: ${{ needs.Bot.outputs.run_editable_pickle == 'True' }}
+    uses:
+      ./.github/workflows/pickle.yml
+    with:
+      python_version: ${{ (needs.Bot.outputs.python_version == '') && '3.7' || needs.Bot.outputs.python_version  }}
+      editable_string: '-e'
+      ref: ${{ needs.Bot.outputs.REF }}
+
+  pickle_wheel:
+    needs: Bot
+    if: ${{ needs.Bot.outputs.run_pickle_wheel == 'True' }}
+    uses:
+      ./.github/workflows/pickle_wheel.yml
+    with:
+      python_version: ${{ (needs.Bot.outputs.python_version == '') && '3.7' || needs.Bot.outputs.python_version  }}
+      ref: ${{ needs.Bot.outputs.REF }}
 
+
+  linux_anaconda:
+    needs: Bot
+    if: ${{ needs.Bot.outputs.run_linux_anaconda == 'True' }}
+    uses:
+      ./.github/workflows/anaconda_linux.yml
+    with:
+      python_version: ${{ (needs.Bot.outputs.python_version == '') && '3.10' || needs.Bot.outputs.python_version  }}
+      ref: ${{ needs.Bot.outputs.REF }}
+
+  windows_anaconda:
+    needs: Bot
+    if: ${{ needs.Bot.outputs.run_windows_anaconda == 'True' }}
+    uses:
+      ./.github/workflows/anaconda_windows.yml
+    with:
+      python_version: ${{ (needs.Bot.outputs.python_version == '') && '3.10' || needs.Bot.outputs.python_version  }}
+      ref: ${{ needs.Bot.outputs.REF }}
+
+  CleanUpBot:
+    needs:
+      - Bot
+      - linux
+      - windows
+      - macosx
+      - coverage
+      - docs
+      - pylint
+      - lint
+      - spelling
+      - pickle
+      - editable_pickle
+      - pickle_wheel
+      - linux_anaconda
+      - windows_anaconda
+    if: ${{ always() && needs.Bot.outputs.cleanup_trigger != '' }}
+    runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v3
-      - name: Set up Python 3.7
+      - name: Set up Python ${{ inputs.python_version }}
         uses: actions/setup-python@v4
         with:
-          python-version: 3.7
-      - name: Install Python dependencies
-        run: |
-          python -m pip install --upgrade pip
-          python -m pip install defusedxml
-        shell: bash
-      - name: Collect coverage information
-        uses: actions/download-artifact@v3
-        with:
-          name: coverage-artifact
-      - name: Collect diff information
+          python-version: 3.9
+      - id: run_bot
         run: |
-          BASE_BRANCH=$GITHUB_BASE_REF
-          git fetch
-          git diff origin/${BASE_BRANCH}..HEAD --no-indent-heuristic --unified=0 --output=pull_diff.txt --no-color
-          ls
-        shell: bash
-      - name: Check coverage
+          python ci_tools/bot_interaction.py $GITHUB_EVENT_PATH $GITHUB_OUTPUT ${{ github.run_id }} ${{ needs.Bot.outputs.cleanup_trigger }}
+        env:
+          GH_TOKEN: ${{ github.token }}
+      - name: Post status
+        if: ${{ github.event_name != 'pull_request' }}
         run: |
-          python ci_tools/check_new_coverage.py pull_diff.txt cobertura.xml $GITHUB_EVENT_PATH $GITHUB_STEP_SUMMARY
-        shell: bash
+          gh api --method POST -H "Accept: application/vnd.github+json" \
+            ${{ needs.Bot.outputs.status_url }} \
+            -f state="${{ steps.run_bot.outputs.global_state }}" -f target_url="${{ github.event.repository.html_url }}/actions/runs/${{ github.run_id }}" \
+            -f description="${{ github.event.comment.body }}" -f context="Tests on Draft"
+        env:
+          GH_TOKEN: ${{ github.token }}
diff --git a/ci_tools/bot_messages/show_tests.txt b/ci_tools/bot_messages/show_tests.txt
new file mode 100644
index 0000000000..a8e3322c6e
--- /dev/null
+++ b/ci_tools/bot_messages/show_tests.txt
@@ -0,0 +1,15 @@
+The following is a list of keywords which can be used to run tests. Tests in bold are run by pull requests marked as ready for review:
+- **linux** : Runs the unit tests on a linux system.
+- **windows** : Runs the unit tests on a linux system.
+- **macosx** : Runs the unit tests on a linux system.
+- **coverage** : Runs the unit tests on a linux system and checks the coverage of the tests.
+- **docs** : Checks if the documentation follows the numpydoc format.
+- **pylint** : Runs pylint on files which are too big to be handled by codacy.
+- **lint** : Runs a linter to check that Pyccel's best practices are followed.
+- **spelling** : Checks if everything in the documentation is spelled (and capitalised) correctly.
+- pr_tests : Runs all the tests marked in bold.
+- pickle : Checks that .pyccel files have been correctly generated and installed by the installation process.
+- editable_pickle : Checks that .pyccel files have been correctly generated and installed by the editable installation process.
+- pickle_wheel : Checks that .pyccel files have been correctly generated and packaged into the wheel.
+- linux_anaconda : Runs the unit tests on a linux system using anaconda for python.
+- windows_anaconda : Runs the unit tests on a windows system using anaconda for python.