Django 1.10 is here ! Above its new features there are some deleted code and I came up against optparse
removing. To be honest, this module is deprecated since Python 2.7 (still here in 3.6), deprecated in Django since 1.7 and removed in 1.10.
Don't blame me too fast, I took the wave with everyone and stopped to use optparse
in favor of argparse
. But I maintain Django-DBBackup and this project must support all Django versions from 1.6.
What is the problem ?
Developers who used Django <= 1.7 will remember this kind of code:
from optparse import make_option
class Command(BaseCommand):
"""This is my old style command."""
option_list = BaseCommand.option_list + (
make_option("--noinput", action='store_false', dest='interactive', default=True,
help='Tells Django to NOT prompt the user for input of any kind.'),
make_option('-q', "--quiet", action='store_true', default=False,
help='Tells Django to NOT output other text than errors.')
)
This way was horrible because you must declare yourself Django common options making heritage complex.
The new style is the following:
class Command(BaseCommand):
"""This is my new style command."""
def add_arguements(self, parser):
parser.add_argument("--noinput", action='store_false', dest='interactive', default=True,
help='Tells Django to NOT prompt the user for input of any kind.'),
parser.add_argument('-q', "--quiet", action='store_true', default=False,
help='Tells Django to NOT output other text than errors.')
A new add_arguments
method has been added to mechanism allowing to handle the parser in every aspect.
Django lets users use both methods during 1.7 to 1.9, but with 1.10 Command.option_list
became useless making new style mandatory. DBBackup must deal with 1.6 and 1.10, it must be able to use both style.
My solution
The solution has several requirements and pitfalls:
- If Django < 1.10, we must set
Command.option_list
- if Django >= 1.10, we must use
Command.add_arguments
- We can't use only
Command.add_arguments
because it isn't in 1.6 mechanism - Some arguments are unsed in
argparse
- I want to make it as DRY as possible
from optparse import make_option as optparse_make_option
import django
from django.core.management.base import BaseCommand as _BaseCommand, CommandError
# Useful only in optparse
USELESS_ARGS = ('callback', 'callback_args', 'callback_kwargs', 'metavar')
# In optparse types are str
TYPES = {
'string': str,
'int': int,
'long': long,
'float': float,
'complex': complex,
'choice': list
}
# Dummy function for keep old code style
def make_option(*args, **kwargs):
return args, kwargs
class BaseCommand(_BaseCommand):
"""Inherit from it for get command compatible Django 1.6-1.10"""
# Options given to children classes
base_option_list = (
make_option("--noinput", action='store_false', dest='interactive', default=True,
help='Tells Django to NOT prompt the user for input of any kind.'),
make_option('-q', "--quiet", action='store_true', default=False,
help='Tells Django to NOT output other text than errors.')
)
# Children options, unused here
option_list = ()
def __init__(self, *args, **kwargs):
# Merge parent and parent options
self.option_list = self.base_option_list + self.option_list
if django.VERSION < (1, 10):
# Create real optparse.Option
options = tuple([optparse_make_option(*_args, **_kwargs)
for _args, _kwargs in self.option_list])
self.option_list = options + _BaseCommand.option_list
super(BaseCommand, self).__init__(*args, **kwargs)
# Used only with 1.10
def add_arguments(self, parser):
for args, kwargs in self.option_list:
kwargs = dict([
(k, v) for k, v in kwargs.items()
if not k.startswith('_') and
k not in USELESS_ARGS])
parser.add_argument(*args, **kwargs)
It is a BaseCommand
, the final one can look like:
from ._base import BaseCommand, make_option
class Command(BaseCommand):
option_list = (
make_option("-x", "--xxx", help="XXX argument"),
)
Simply...
Explanation please ?
As you guess, I made a mix between both styles but instead of use make_option
for create an optparse.Option
, I simply store args
& kwargs
and use them with the appropriate way depending of Django version:
- In Django < 1.10, stored
args
/kwargs
are used in__init__ to create
optparse.Options
- In Django >= 1.10 stored
args
/kwargs
are used inadd_arguments
to createargparse.Action
Comments
No comments yet.