Make request object available to JSExtension instances

Review Request #8595 — Created Jan. 5, 2017 and submitted

Information

Djblets
master
c20f607...

Reviewers

By making the request object available, the extension subclass can e.g. get
hold of the current user which can be useful.

Tested that getting a user's groups as discussed in this mail thread works.

Unit tests pass.

Description From Last Updated

This will ultimately break any existing extensions that don't define this parameter. We'll need to retain compatibility here. I think …

chipx86chipx86

Col: 5 E301 expected 1 blank line, found 0

reviewbotreviewbot

Col: 5 E301 expected 1 blank line, found 0

reviewbotreviewbot

Let's just call this js_extension_items. That's specific enough to give info on what we're adding, and generic enough for future …

chipx86chipx86

Blank line between these.

chipx86chipx86

Blank line between these.

chipx86chipx86

Just one blank line between these.

chipx86chipx86

This is probably going to get hard to maintain over time, and is a bit wordy. What we can do …

chipx86chipx86
reviewbot
  1. Tool: PEP8 Style Checker
    Processed Files:
        djblets/extensions/templatetags/djblets_extensions.py
        djblets/extensions/extension.py
    
    
    
    Tool: Pyflakes
    Processed Files:
        djblets/extensions/templatetags/djblets_extensions.py
        djblets/extensions/extension.py
    
    
  2. 
      
chipx86
  1. Thanks for the contribution! I have some notes on the necessary design for this. Let me know if you don't have time to do this, and we'll finish it up on our end. I'd like to get this into 2.5.8.

  2. djblets/extensions/extension.py (Diff revision 1)
     
     
    Show all issues

    This will ultimately break any existing extensions that don't define this parameter. We'll need to retain compatibility here.

    I think JSExtension itself should not expect to be re-instantiated on every page. We may want to cache instances down the road. So I think this parameter should live in get_model_data() instead. However, the same compatibility problem applies.

    What I'd suggest is to update init_js_extensions to call get_context_data itself. Instead of setting js_extensions in the context, we'd want to instead pass a list of dictionaries containing two items:

    1) js_extension
    2) context_data

    This way, we can pre-compute this data without the template having to do it, which allows us to pass the request.

    Now, about that compatibility issue. We need to conditionally determine whether get_context_data can take a request (the new version should actually take a request as a keyword argument, and **kwargs for future expansion).

    You can check before calling by doing:

    arg_spec = inspect.getargspec(js_extension.get_context_data)
    
    if arg_spec.keywords is None:
        warnings.warn('%s.get_context_data will need to take keyword arguments. The old '
                      'function signature is deprecated.'
                      % js_extension_cls.__name__)
    
        context_data = js_extension.get_context_data()
    else:
        context_data = js_extension.get_context_data(request=request)
    

    Something like that.

    We'll also need unit tests to ensure both calls work.

  3. 
      
erijo
reviewbot
  1. Tool: Pyflakes
    Processed Files:
        djblets/extensions/templatetags/djblets_extensions.py
        djblets/extensions/extension.py
    
    Ignored Files:
        djblets/extensions/templates/extensions/init_js_extensions.html
    
    
    
    Tool: PEP8 Style Checker
    Processed Files:
        djblets/extensions/templatetags/djblets_extensions.py
        djblets/extensions/extension.py
    
    Ignored Files:
        djblets/extensions/templates/extensions/init_js_extensions.html
    
    
  2. 
      
erijo
reviewbot
  1. Tool: Pyflakes
    Processed Files:
        djblets/extensions/templatetags/tests.py
        djblets/extensions/templatetags/djblets_extensions.py
        djblets/extensions/extension.py
    
    Ignored Files:
        djblets/extensions/templates/extensions/init_js_extensions.html
    
    
    
    Tool: PEP8 Style Checker
    Processed Files:
        djblets/extensions/templatetags/tests.py
        djblets/extensions/templatetags/djblets_extensions.py
        djblets/extensions/extension.py
    
    Ignored Files:
        djblets/extensions/templates/extensions/init_js_extensions.html
    
    
  2. Show all issues
    Col: 5
     E301 expected 1 blank line, found 0
    
  3. Show all issues
    Col: 5
     E301 expected 1 blank line, found 0
    
  4. 
      
erijo
reviewbot
  1. Tool: Pyflakes
    Processed Files:
        djblets/extensions/templatetags/tests.py
        djblets/extensions/templatetags/djblets_extensions.py
        djblets/extensions/extension.py
    
    Ignored Files:
        djblets/extensions/templates/extensions/init_js_extensions.html
    
    
    
    Tool: PEP8 Style Checker
    Processed Files:
        djblets/extensions/templatetags/tests.py
        djblets/extensions/templatetags/djblets_extensions.py
        djblets/extensions/extension.py
    
    Ignored Files:
        djblets/extensions/templates/extensions/init_js_extensions.html
    
    
  2. 
      
chipx86
  1. Thanks for taking on the unit test! Much appreciated :)

    Got a few more notes on the new code, but this is pretty close to what I'd like to see for the change. Just a few things for how we style code, and a couple suggestions on how we can represent state for the template and check against it in the test.

  2. Show all issues

    Let's just call this js_extension_items. That's specific enough to give info on what we're adding, and generic enough for future expansion purposes.

    It should also be a list, so that the ordering is reliable and consistent (which is important). Each entry can be a dictionary with js_extension and model_data keys, which the template can access.

  3. Show all issues

    Blank line between these.

  4. Show all issues

    Blank line between these.

  5. djblets/extensions/templatetags/tests.py (Diff revision 4)
     
     
     
     
     
    Show all issues

    Just one blank line between these.

  6. djblets/extensions/templatetags/tests.py (Diff revision 4)
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
    Show all issues

    This is probably going to get hard to maintain over time, and is a bit wordy. What we can do instead is check just for the bits that we're looking for. A regex would be a good option for this.

    content = t.render(Context({...}))
    
    self.assertIsNotNone(re.search(
        r'new FooNew\({\s+"test": "new",',
        content))
    
    self.assertIsNotNone(re.search(
        r'new FooOld\({\s+"test": "old",',
        content))
    

    etc. That helps us ensure that we have the content we expect in the relative location we expect, without worrying about changes in whitespace or having to match against a huge string.

  7. 
      
erijo
reviewbot
  1. Tool: Pyflakes
    Processed Files:
        djblets/extensions/templatetags/tests.py
        djblets/extensions/templatetags/djblets_extensions.py
        djblets/extensions/extension.py
    
    Ignored Files:
        djblets/extensions/templates/extensions/init_js_extensions.html
    
    
    
    Tool: PEP8 Style Checker
    Processed Files:
        djblets/extensions/templatetags/tests.py
        djblets/extensions/templatetags/djblets_extensions.py
        djblets/extensions/extension.py
    
    Ignored Files:
        djblets/extensions/templates/extensions/init_js_extensions.html
    
    
  2. 
      
chipx86
  1. Ship It!
  2. 
      
erijo
Review request changed
Status:
Completed
Change Summary:
Pushed to master (f4baa4e)