Skip to content
This repository has been archived by the owner on Apr 16, 2023. It is now read-only.

Predict app #121

Open
wants to merge 14 commits into
base: dev
Choose a base branch
from
Open

Conversation

DigitalPhilosopher
Copy link

Feel free to open a PR before all of these items have been completed.

Pull Request Checklist

  • Pull request includes a description of the change and the reason behind it.
  • Pull request uses keywords to close relevant issues.
  • Pull request includes unit tests for any new functionality.
  • README and docs have been updated.
  • ./.ci/local_checks.sh passes locally. (The app must be running. See README.md for instructions.)

Maintainer's responsibilities:

  • _version.py has been updated.
  • CHANGELOG.md has been updated.
  • Updated app container has been pushed, if relevant, with current version number.
  • App container version number has been updated in README.

- Add the abstract class Validator
- Add the class PredictRequestValidator for validating single predict
requests
- Add fastai to requirements
- Use Validator in predict single
- Add abort function to Validator
- Add PredictZipRequestValidator to module requests
- Handle file through file class
- File is removed in the destructor
- Use in predict_single
- Add ZipArchive to handle zips
- Add predict multiple method to Predictor
- Remove unused utils
- Change File to set file or pathname
- Change predict_zip in app
- Add docstrings for new classes
- Remove unused imports
- Remove imports from __init__
- Fix circle import from File and app
@gsganden
Copy link
Collaborator

Got it, thanks! Will review at my earliest opportunity.

@DigitalPhilosopher
Copy link
Author

Hey @gsganden, is there anything else you would change in my PR? I would be very happy with some advice and comments on my changes. Thanks very much :)

@gsganden
Copy link
Collaborator

It might take me a little while, but I will get to it!

Copy link
Collaborator

@gsganden gsganden left a comment

Choose a reason for hiding this comment

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

Thanks for the contribution! You and I have different coding styles that we'll need to reconcile. Overall, I favor more functional approaches. I'm open to accepting PRs that are not the way I would have done it, but I also want the overall design to be unified and idiomatic. There are also some places (particularly in the file and zipfile handling) where just using Python's standard library and built-in capabilities will result in code that other Python developers will find easier to understand.

How would you like to proceed? I'd be happy for you to take another crack at it if you are willing. I could also take some of your contributions and adapt them in a more functional style when I get a chance.

from werkzeug import secure_filename


class File:
Copy link
Collaborator

Choose a reason for hiding this comment

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

We don't need our own file class -- Python has built-in ways to do these things.

Copy link
Author

Choose a reason for hiding this comment

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

Especially for our use case, I wrote the File class, so it would remove the file upon destructing the object. This removes the need to manually handle this every time while handling a file.

I think maybe the naming here is the problem, so I renamed this class to be 'TemporaryFile'.

I would like to keep this class, since the functionality here is pretty awesome and makes the handling very simple. However it is your call, if you don't see the value.

What do you think?

Copy link
Collaborator

Choose a reason for hiding this comment

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

CLASSES = model.data.classes


class Predictor:
Copy link
Collaborator

Choose a reason for hiding this comment

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

Could we make these methods top-level functions? I don't see much benefit in having them together in a class rather than just a module, it requires another line of code for callers, and it seems to me less idiomatic Python.

Copy link
Author

Choose a reason for hiding this comment

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

Yes, I made them top-level functions now.
While developing the class I thought about adopting this class for other predictions as well. That was my thought behind this.

from ..utils import allowed_file


class ZipArchive:
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't think we need our own ZipArchive class -- the standard library has these capabilities https://docs.python.org/3/library/zipfile.html

Copy link
Author

Choose a reason for hiding this comment

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

Here the same as for the 'File' (now 'TemporaryFile'). It adds more functionality to the build in functions and can be reused.

ALLOWED_ZIP_FILES = {".zip"}


class Validator(ABC):
Copy link
Collaborator

Choose a reason for hiding this comment

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

The class structure here seems to me to add more overhead than it is worth. All we need is one function to validate predict requests, one to validate predict_multiple requests, and appropriate calls to abort.

Copy link
Author

Choose a reason for hiding this comment

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

I see your point and changed this to be a single method now.

@DigitalPhilosopher
Copy link
Author

Hey @gsganden I revisited the code and made it more functional and removed most of the object orientation.

However, I kept the File (now TemporaryFile) and ZipArchive as classes, as said before. If you really don't favor this approach, I would be willing to change it as well, but I think it adds a lot to the simplicity of the code and would favor to keep it. What do you think?

from ..validation.predict import validate_predict_request


predict_route = Blueprint("predict", __name__)
Copy link
Collaborator

Choose a reason for hiding this comment

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

I've never used Blueprint objects, but I'm intrigued. Can you point me to a resource that explains how they work?

Copy link
Collaborator

@gsganden gsganden 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 looking good. I think we can simplify it further by using the standard library tempfile and zipfile modules rather than creating custom classes. I'd also like to understand how Blueprint works if you could point me to relevant resources.

Copy link
Collaborator

@gsganden gsganden 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 looking good. I think we can simplify it further by using the standard library tempfile and zipfile modules rather than creating custom classes. I'd also like to understand how Blueprint works if you could point me to relevant resources.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants