Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

General refactor #138

Merged
merged 9 commits into from
Oct 9, 2024
Merged

General refactor #138

merged 9 commits into from
Oct 9, 2024

Conversation

cc-a
Copy link
Contributor

@cc-a cc-a commented Oct 7, 2024

Description

This PR takes a pass at refactoring (mostly moving stuff around) the code base and simplifying some of the tests. It:

  • Separates the view functions in process_manager/views.py into 3 submodules handling pages (full individual pages), partials (elements embedded within larger pages used by HTMX) and actions (acting on dune processes). The tests are also split accordingly.
  • Pulls out commands that interact with the process manager into process_manager/process_manager_interface.py and standardises how we wrap async calls to ProcessManagerDriver methods.
  • Reduces the use of adhoc mocking by adding an auto-used mock fixture that prevents gRPC calls being made during tests.
  • Shortens the names of tests that are class methods to reduce redundant information.
  • Adds a PermissionRequired test class as an extension to LoginRequired which checkes that an authenticated but unpriveleged user is blocked from a view correctly.
  • Neatens some of the fixtures a bit.

Type of change

  • Documentation (non-breaking change that adds or improves the documentation)
  • New feature (non-breaking change which adds functionality)
  • Optimization (non-breaking, back-end change that speeds up the code)
  • Bug fix (non-breaking change which fixes an issue)
  • Breaking change (whatever its nature)

Key checklist

  • All tests pass (eg. python -m pytest)
  • The documentation builds and looks OK (eg. python -m sphinx -b html docs docs/build)
  • Pre-commit hooks run successfully (eg. pre-commit run --all-files)

Further checks

  • Code is commented, particularly in hard-to-understand areas
  • Tests added or an issue has been opened to tackle that in the future. (Indicate issue here: # (issue))

@codecov-commenter
Copy link

codecov-commenter commented Oct 7, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 100.00%. Comparing base (f9f2bea) to head (864ca64).
Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff            @@
##              main      #138   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files            5         5           
  Lines           44        46    +2     
=========================================
+ Hits            44        46    +2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link
Contributor

@alexdewar alexdewar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! I've made some small comments.

Not really related to this PR: but it feels kinda wrong that we're wrapping all the async calls to make them synchronous. The DUNE folks have given us a nice async API and it seems a pity to circumvent it! It looks like Django can handle async views (see here, with the caveat that if your middleware isn't async-aware then it'll just fall back on using threads internally. In any case, if we could do things that way we could avoid some of the boilerplate wrapping code. Worth opening an issue for?

process_manager/process_manager_interface.py Outdated Show resolved Hide resolved
process_manager/views/pages.py Show resolved Hide resolved
tests/process_manager/views/__init__.py Outdated Show resolved Hide resolved
process_manager/views/actions.py Show resolved Hide resolved
process_manager/process_manager_interface.py Show resolved Hide resolved
@cc-a
Copy link
Contributor Author

cc-a commented Oct 8, 2024

Not really related to this PR: but it feels kinda wrong that we're wrapping all the async calls to make them synchronous. The DUNE folks have given us a nice async API and it seems a pity to circumvent it! It looks like Django can handle async views (see here, with the caveat that if your middleware isn't async-aware then it'll just fall back on using threads internally. In any case, if we could do things that way we could avoid some of the boilerplate wrapping code. Worth opening an issue for?

Yeah, something that's crossed my mind as well. I've created #140 to follow up.

Copy link
Contributor

@AdrianDAlessandro AdrianDAlessandro left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is good, I've been wanting to do the same kind of refactor. I have a lot of comments, but they're a combination of questions and reminders to open new issues. So I'm not requesting changes.

There are some missing docstrings that don't seem to be getting caught by linting (I think they're all functions that begin with "_"). Is this intentional?

drunc_ui/settings/settings.py Show resolved Hide resolved
process_manager/process_manager_interface.py Show resolved Hide resolved
process_manager/process_manager_interface.py Show resolved Hide resolved
process_manager/process_manager_interface.py Show resolved Hide resolved
tests/conftest.py Show resolved Hide resolved
tests/test_process_manager_interface.py Outdated Show resolved Hide resolved
tests/process_manager/views/test_page_views.py Outdated Show resolved Hide resolved
Copy link
Contributor

@jamesturner246 jamesturner246 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still following. Looks good to me 👍

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, so the get_whatevers are just placeholders until async views are done/decided on.

tests/conftest.py Show resolved Hide resolved
Copy link
Collaborator

@dalonsoa dalonsoa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a couple of questions, but otherwise it looks good to me!

Comment on lines +51 to +55
class BootProcessView(PermissionRequiredMixin, FormView[BootProcessForm]):
"""View for the BootProcess form."""

template_name = "process_manager/boot_process.html"
form_class = BootProcessForm
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need BootProcessForm in when indicating the class to inherit from? It doesn't seem to add much to aid the type checking, as far as I can tell.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FormView is a generic type and we're disallowing Any generics so we either have to provide this or ignore the error.

success_url = reverse_lazy("process_manager:index")
permission_required = "main.can_modify_processes"

def form_valid(self, form: BootProcessForm) -> HttpResponse:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's nothing in this method that uses specific features from the BootProcessForm, so using just forms.Form is more generic and enough for the type checker to work.

Suggested change
def form_valid(self, form: BootProcessForm) -> HttpResponse:
def form_valid(self, form: form.Form) -> HttpResponse:

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that BootProcessForm makes the most sense as that is the type we expect in order for the correct data to be present for the function to work correctly. If it was just typed as Form then any Form subclass would be valid even though these don't contain the required data.

no check boxes selected. POST renders the table with checked boxes for any table row
with a uuid provided in the select key of the request data.
"""
selected_rows = request.POST.getlist("select", [])
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When it is a GET method, does POST still exist with no select? Otherwise, how do we distinguish between a GET and a POST?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does still exist. We make use of the case that there is no difference in behaviour of the function when there is a GET request or a POST request with no data.

tests/conftest.py Show resolved Hide resolved
@cc-a cc-a merged commit 560b576 into main Oct 9, 2024
4 checks passed
@cc-a cc-a deleted the general-refactor branch October 9, 2024 09:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants