Previous topic

Miscellaneous

Next topic

Working with computer clusters

This Page

Pylearn2 API Change Best Practices GuideΒΆ

API changes are any changes that affect the way a piece of code interacts with the outside world. This means changing the name of any class, function, method, parameter name. It can also mean changing a default argument value, or changing the behavior that results from setting an argument to a certain value. Because API changes require the outside world to adapt to changes in pylearn2, they should be done as rarely as possible, and with great care. As of this writing, 145 people are watching pylearn2 on github. Pylearn2 is used to store reproducible scientific results, and has been used to host five different contests on kaggle.com. Breaking interfaces in pylearn2 will upset people all over the internet. Unfortunately, given pylearn2’s mission of being a cutting-edge research library, new research directions will often require changes to pylearn2’s interface. This guide explains how to change APIs while doing the least damage possible.

  • E-mail pylearn-dev@googlegroups.com about proposed changes before you start working on them. This will give the other users of pylearn2 the opportunity to see possible problems your changes might cause, and help you figure out the safest possible way to accomplish what you want to with the API change.

  • Whenever possible, make the old version of the interface still work for 6 months before it is phased out.

    • You should detect when someone uses the old interface, and use
    warnings.warn(“<Old interface element> is deprecated. Use “

    “<new interface element> instead. <Old interface element> will be removed” “on or after <date 6 months from now>”, stacklevel=2)

    to warn that the interface is going to change.

    • If the interface change doesn’t cause any serious behavior changes (i.e., you’re just not asking for some metadata that is no longer required to accomplish the task) then it’s OK to just issue the warning. But if the change that takes place after the six month warning will alter numerical results, or cause a crash if someone uses the old interface, you should take the following steps to update everything in the library to the new interface:

      • Put a “raise AssertionError()” before all of your new warnings, and run the unit tests. Fix all tests that fail because they would trigger your deprecation warning.
      • Use “grep -r” to find all instances of the name of the thing you’re changing, and make sure that they all use the right interface. Sadly, not everything in pylearn2 is unit tested, so just running the tests might miss some cases.
      • Remove the “raise AssertionError()” statements before sending your pull request. However, you must leave the warnings in, because clients of the library might (and probably are) still be using the old interface.
    • If you’re changing the name of a parameter of a function / method, keep the new name, add the old name, and have both default to None. Inside the function, raise a warning if the old name is specified. If both the old name and the new name are specified, raise a warning if both are set to the same value. Raise an error if both are set, and they’re set to different values. If both are set to None, fill in the default value. If you are also planning to change the default after the end of the deprecation warning period, add a warning whenever the default is filled in.

      Example:

    # Suppose you have a function
    
    def my_func(my_arg = 1):
    
    # and you want to change it to
    
    def my_func(arg = 2):
    
    # You should start your function off like this:
    
    def my_func(my_arg = None, arg = None):
    
         if my_arg is not None:
             warnings.warn("my_arg is deprecated. Use arg instead. my_arg will be removed "
                 "on or after October 18, 2013")
             if arg is not None:
                 if arg == my_arg:
                     warnings.warn("You are specifying both arg and my_arg. They are aliases. "
                      "You are setting them both to the same thing, so it's OK, but you should "
                      "probably switch to specifying only arg")
                 else:
                     raise ValueError("my_arg and arg are aliases, but you set them to conflicting "
                      "values")
             arg = my_arg
    
         if arg is None:
             warnings.warn("You are using the default value of arg. This default will change on or "
              "after October 18, 2013.")
             arg = 2
    
    • Make sure there are unit tests for the functionality you’re changing. If you have to write a lot of logic to handle warnings, changes to default values, etc. write unit tests to make sure the old interface still works. This includes making sure that the behavior when you pass no arguments is the same (i.e., make sure you didn’t change the default behavior by accident).