Framework for handling file attachments by mimetype

Review Request #2967 — Created March 18, 2012 and submitted

Information

Review Board

Reviewers

This is meant as an overview of the design for a framework handling file attachments according to different mimetypes (e.g., generating a thumbnail, determining the icon url, etc.). The FileAttachment class will have some notion of a handler, which will be called at the appropriate points (a la strategy patter). For mimetype-specific parsing, I chose mimeparse, although I suspect the spec may be amenable to simple string/regular-expression matching.

I was thinking of creating a MimetypeHandler class that will have a factory classmethod that will allow it to iterate over all the subclasses and find the appropriate handler. A handler indicates this capability through a matches classmethod. Ideally, each subclass will operate on a subset of the mimetypes that the parent class operates on. I'm not sure if using subclasses is the best way to do this, as the class will be registered automatically once you install the extension. I've worked around it as follows, but I'm not sure if it is a good way to do it:
    def matches(self, mimetype):
        ext_manager = get_extension_manager()
        for e in ext_manager.get_enabled_extensions():
            if e.__class__ == TextMimetypeHandler:
                return mimetype[0] == 'text'
        return False

I've also included a working extension for text mimetypes.
This works on a LinuxMint 10 (linux 2.6.35-22) virtual machine with Review board 1.7a on Firefox 3.6.16.

Description From Last Updated

No blank line. Djblets is third-party in Review Board's perspective.

chipx86chipx86

First line, immediately after the """, must be a one-line summary. Then a blank line, then a description of the …

chipx86chipx86

It'd be nice to document these functions.

chipx86chipx86

Blank line between these.

chipx86chipx86

Blank line between these.

chipx86chipx86

Blank line. (I prefer blank lines between blocks (if statements, loops, etc.) and other code on the same level.)

chipx86chipx86

This should be using the static() function. It's a templatetag, but you can import it and use it like a …

chipx86chipx86

Same comment here about one-line summary.

chipx86chipx86

Is this the right default? I'm not sure we want to default every MimetypeHandler to matching. Maybe keep this False …

chipx86chipx86

Always have a period after sentences in docs. These will eventually end up on webpages. When you only have one …

chipx86chipx86

What's the point of the function? Can this roll into get_thumbnail below? Or is it for subclasses? If it's for …

chipx86chipx86

Yeah, should be fine. Make this a @property though.

chipx86chipx86

It's nice to keep these roughly alphabetical.

chipx86chipx86

I believe border, margin, and padding can be "0" instead of "0px".

ME medanat

This is a classmethod, so 'self' is wrong. It should be 'cls'.

chipx86chipx86

Same about cls vs. self.

chipx86chipx86

The % should be aligned with the '<img

chipx86chipx86

Parameters need to align. And, hmm, I think you could get the full path from the FileField. Not sure you …

chipx86chipx86

with: is only in Python 2.6. Just use standard: f = open(...) ... f.close()

chipx86chipx86

Are you sure height - 1 is correct? range is inclusive (so a height of 3 will produce [0, 1, …

chipx86chipx86

The % preview should be aligned with the parameters.

chipx86chipx86

Weird convention. Shouldn't use _, and should spell out Mimetype. Same with all other classes here.

chipx86chipx86
AM
chipx86
  1. Looks like a fantastic start. Some style stuff to fix, and a couple ideas regarding mimetype matching.
    
    What about the renderer for the .txt file you show in the screenshot? Seems like a good one to include too.
  2. reviewboard/attachments/mimetypes.py (Diff revision 1)
     
     
     
     
    Show all issues
    No blank line. Djblets is third-party in Review Board's perspective.
  3. reviewboard/attachments/mimetypes.py (Diff revision 1)
     
     
     
    Show all issues
    First line, immediately after the """, must be a one-line summary. Then a blank line, then a description of the class.
  4. reviewboard/attachments/mimetypes.py (Diff revision 1)
     
     
    Show all issues
    It'd be nice to document these functions.
  5. reviewboard/attachments/mimetypes.py (Diff revision 1)
     
     
     
    Show all issues
    Blank line between these.
  6. reviewboard/attachments/mimetypes.py (Diff revision 1)
     
     
    Interesting. Never knew about __subclasses__.
    
    This will, I assume, only return direct subclasses and not subclasses of subclasses, but I guess in this case we're likely to recurse?
    
    My one concern is how we deal with priorities. If two things claim to match, one should win, but which? Some might be more specific.
    
    For example, a handler specifically for text/* and one for text/html should prefer the second for HTML files.
    
    We can figure this out by having a way of scoring the match by assigning one point for each of the following:
    
    * Mimetype matches in some form (exactly, or through wildcards, or by stripping out the +foo, or by being a subset of the mimetype -- text/plain vs text/html)
    * Left-hand side of the "/" matches exactly.
    * Right-hand side matches (possibly by stripping out the stuff after "+", if it exists, or being a mimetype that is a subset of another)
    * Right-hand side matches exactly (including the "+foo")
    
    So.. something like that.
    
    The points are only returned if the mimetype is compatible. Through the scoring, we can pick one handler over another based on how confident that handler is that it knows better what the mimetype is.
    
    By consolidating this logic in MimetypeHandler, the subclasses could by default just have a list of mimetypes they support instead of overriding handles(). Of course, they could always override that, but it keeps the basic case simple.
  7. reviewboard/attachments/mimetypes.py (Diff revision 1)
     
     
     
    Show all issues
    Blank line between these.
  8. reviewboard/attachments/mimetypes.py (Diff revision 1)
     
     
     
    Show all issues
    Blank line.
    
    (I prefer blank lines between blocks (if statements, loops, etc.) and other code on the same level.)
  9. reviewboard/attachments/mimetypes.py (Diff revision 1)
     
     
    Show all issues
    This should be using the static() function. It's a templatetag, but you can import it and use it like a function. If you grep around the codebase, you'll see examples.
    
    Also, you can get rid of MEDIA_SERIAL now.
  10. reviewboard/attachments/mimetypes.py (Diff revision 1)
     
     
     
    Show all issues
    Same comment here about one-line summary.
  11. reviewboard/attachments/mimetypes.py (Diff revision 1)
     
     
     
    Show all issues
    Is this the right default? I'm not sure we want to default every MimetypeHandler to matching. Maybe keep this False here, and have a GenericMimetypeHandler subclass that sets this to True.
  12. reviewboard/attachments/mimetypes.py (Diff revision 1)
     
     
     
     
    Show all issues
    Always have a period after sentences in docs. These will eventually end up on webpages.
    
    When you only have one line, the """ should be right up against both sides of the text.
  13. reviewboard/attachments/mimetypes.py (Diff revision 1)
     
     
     
     
     
     
    Show all issues
    What's the point of the function? Can this roll into get_thumbnail below? Or is it for subclasses?
    
    If it's for subclasses, it shouldn't have a _.
  14. reviewboard/attachments/models.py (Diff revision 1)
     
     
     
     
    Show all issues
    Yeah, should be fine. Make this a @property though.
  15. reviewboard/static/rb/css/reviews.less (Diff revision 1)
     
     
     
     
     
     
    Show all issues
    It's nice to keep these roughly alphabetical.
  16. 
      
AM
ME
  1. 
      
  2. reviewboard/static/rb/css/reviews.less (Diff revision 2)
     
     
     
     
     
     
     
    Show all issues
    I believe border, margin, and padding can be "0" instead of "0px".
  3. 
      
AM
chipx86
  1. This is looking great. The remaining things are very minor, but this will be going in soon :)
  2. reviewboard/attachments/mimetypes.py (Diff revision 3)
     
     
     
    Show all issues
    This is a classmethod, so 'self' is wrong. It should be 'cls'.
  3. reviewboard/attachments/mimetypes.py (Diff revision 3)
     
     
     
    Show all issues
    Same about cls vs. self.
  4. reviewboard/attachments/mimetypes.py (Diff revision 3)
     
     
     
    Show all issues
    The % should be aligned with the '<img
  5. reviewboard/attachments/mimetypes.py (Diff revision 3)
     
     
     
    Show all issues
    Parameters need to align.
    
    And, hmm, I think you could get the full path from the FileField. Not sure you need to os.path.join. There's a method injected into the model, I believe.
  6. reviewboard/attachments/mimetypes.py (Diff revision 3)
     
     
    Show all issues
    with: is only in Python 2.6. Just use standard:
    
    f = open(...)
    ...
    f.close()
  7. reviewboard/attachments/mimetypes.py (Diff revision 3)
     
     
    Show all issues
    Are you sure height - 1 is correct? range is inclusive (so a height of 3 will produce [0, 1, 2], or in your case, [0, 1]).
    1. I subtract one from the height because I set preview to be escape(f.readline()) before the loop.
  8. reviewboard/attachments/mimetypes.py (Diff revision 3)
     
     
     
    Show all issues
    The % preview should be aligned with the parameters.
  9. reviewboard/attachments/tests.py (Diff revision 3)
     
     
    Show all issues
    Weird convention. Shouldn't use _, and should spell out Mimetype.
    
    Same with all other classes here.
  10. 
      
AM
chipx86
  1. I know this was forever ago now, but we're finally back in feature mode for the release. This is awesome, and I'm just about to commit it. Thanks for all your work on this!
  2. 
      
AM
Review request changed
Status:
Completed