s/optparse/argparse

This commit is contained in:
benoitc 2012-12-24 16:51:22 +01:00
parent 20cd49595a
commit ac1af72922
7 changed files with 2435 additions and 53 deletions

View File

@ -20,10 +20,11 @@ class Application(object):
the various necessities for any given web framework. the various necessities for any given web framework.
""" """
def __init__(self, usage=None): def __init__(self, usage=None, prog=None):
self.usage = usage self.usage = usage
self.cfg = None self.cfg = None
self.callable = None self.callable = None
self.prog = prog
self.logger = None self.logger = None
self.do_load_config() self.do_load_config()
@ -32,19 +33,20 @@ class Application(object):
self.load_config() self.load_config()
except Exception as e: except Exception as e:
sys.stderr.write("\nError: %s\n" % str(e)) sys.stderr.write("\nError: %s\n" % str(e))
traceback.print_exc()
sys.stderr.flush() sys.stderr.flush()
sys.exit(1) sys.exit(1)
def load_config(self): def load_config(self):
# init configuration # init configuration
self.cfg = Config(self.usage) self.cfg = Config(self.usage, prog=self.prog)
# parse console args # parse console args
parser = self.cfg.parser() parser = self.cfg.parser()
opts, args = parser.parse_args() args = parser.parse_args()
# optional settings from apps # optional settings from apps
cfg = self.init(parser, opts, args) cfg = self.init(parser, args, args.args)
# Load up the any app specific configuration # Load up the any app specific configuration
if cfg and cfg is not None: if cfg and cfg is not None:
@ -52,18 +54,18 @@ class Application(object):
self.cfg.set(k.lower(), v) self.cfg.set(k.lower(), v)
# Load up the config file if its found. # Load up the config file if its found.
if opts.config and os.path.exists(opts.config): if args.config and os.path.exists(args.config):
cfg = { cfg = {
"__builtins__": __builtins__, "__builtins__": __builtins__,
"__name__": "__config__", "__name__": "__config__",
"__file__": opts.config, "__file__": args.config,
"__doc__": None, "__doc__": None,
"__package__": None "__package__": None
} }
try: try:
execfile_(opts.config, cfg, cfg) execfile_(args.config, cfg, cfg)
except Exception: except Exception:
print("Failed to read config file: %s" % opts.config) print("Failed to read config file: %s" % args.config)
traceback.print_exc() traceback.print_exc()
sys.exit(1) sys.exit(1)
@ -79,9 +81,11 @@ class Application(object):
# Lastly, update the configuration with any command line # Lastly, update the configuration with any command line
# settings. # settings.
for k, v in opts.__dict__.items(): for k, v in args.__dict__.items():
if v is None: if v is None:
continue continue
if k == "args":
continue
self.cfg.set(k.lower(), v) self.cfg.set(k.lower(), v)
def init(self, parser, opts, args): def init(self, parser, opts, args):

View File

@ -105,13 +105,13 @@ class DjangoApplicationCommand(Application):
def __init__(self, options, admin_media_path): def __init__(self, options, admin_media_path):
self.usage = None self.usage = None
self.prog = None
self.cfg = None self.cfg = None
self.config_file = options.get("config") or "" self.config_file = options.get("config") or ""
self.options = options self.options = options
self.admin_media_path = admin_media_path self.admin_media_path = admin_media_path
self.callable = None self.callable = None
self.project_path = None self.project_path = None
self.do_load_config() self.do_load_config()
def init(self, *args): def init(self, *args):
@ -139,4 +139,4 @@ def run():
applications. applications.
""" """
from gunicorn.app.djangoapp import DjangoApplication from gunicorn.app.djangoapp import DjangoApplication
DjangoApplication("%prog [OPTIONS] [SETTINGS_PATH]").run() DjangoApplication("%(prog)s [OPTIONS] [SETTINGS_PATH]").run()

View File

@ -147,7 +147,7 @@ def run():
apllications like Pylons or Turbogears2 apllications like Pylons or Turbogears2
""" """
from gunicorn.app.pasterapp import PasterApplication from gunicorn.app.pasterapp import PasterApplication
PasterApplication("%prog [OPTIONS] pasteconfig.ini").run() PasterApplication("%(prog)s [OPTIONS] pasteconfig.ini").run()
def paste_server(app, gcfg=None, host="127.0.0.1", port=None, *args, **kwargs): def paste_server(app, gcfg=None, host="127.0.0.1", port=None, *args, **kwargs):

View File

@ -31,4 +31,4 @@ def run():
generic WSGI applications. generic WSGI applications.
""" """
from gunicorn.app.wsgiapp import WSGIApplication from gunicorn.app.wsgiapp import WSGIApplication
WSGIApplication("%prog [OPTIONS] APP_MODULE").run() WSGIApplication("%(prog)s [OPTIONS] APP_MODULE").run()

2362
gunicorn/argparse_compat.py Normal file

File diff suppressed because it is too large Load Diff

View File

@ -6,16 +6,20 @@
import copy import copy
import grp import grp
import inspect import inspect
import optparse try:
import argparse
except ImportError: # python 2.6
from . import argparse_compat as argparse
import os import os
import pwd import pwd
import sys
import textwrap import textwrap
import types import types
from gunicorn import __version__ from gunicorn import __version__
from gunicorn.errors import ConfigError from gunicorn.errors import ConfigError
from gunicorn import six
from gunicorn import util from gunicorn import util
from gunicorn.six import string_types, integer_types, bytes_to_str
KNOWN_SETTINGS = [] KNOWN_SETTINGS = []
@ -39,9 +43,10 @@ def make_settings(ignore=None):
class Config(object): class Config(object):
def __init__(self, usage=None): def __init__(self, usage=None, prog=None):
self.settings = make_settings() self.settings = make_settings()
self.usage = usage self.usage = usage
self.prog = prog or sys.argv[0]
def __getattr__(self, name): def __getattr__(self, name):
if name not in self.settings: if name not in self.settings:
@ -61,9 +66,10 @@ class Config(object):
def parser(self): def parser(self):
kwargs = { kwargs = {
"usage": self.usage, "usage": self.usage,
"version": __version__ "version": "%(prog)s (version " + __version__ + ")\n",
"prog": self.prog
} }
parser = optparse.OptionParser(**kwargs) parser = argparse.ArgumentParser(**kwargs)
keys = list(self.settings) keys = list(self.settings)
@ -73,6 +79,8 @@ class Config(object):
keys = sorted(self.settings, key=self.settings.__getitem__) keys = sorted(self.settings, key=self.settings.__getitem__)
for k in keys: for k in keys:
self.settings[k].add_option(parser) self.settings[k].add_option(parser)
parser.add_argument("args", nargs="*", help=argparse.SUPPRESS)
return parser return parser
@property @property
@ -90,7 +98,7 @@ class Config(object):
@property @property
def address(self): def address(self):
s = self.settings['bind'].get() s = self.settings['bind'].get()
return [util.parse_address(bytes_to_str(bind)) for bind in s] return [util.parse_address(six.bytes_to_str(bind)) for bind in s]
@property @property
def uid(self): def uid(self):
@ -176,17 +184,25 @@ class Setting(object):
if not self.cli: if not self.cli:
return return
args = tuple(self.cli) args = tuple(self.cli)
help_txt = "%s [%s]" % (self.short, self.default)
help_txt = help_txt.replace("%", "%%")
kwargs = { kwargs = {
"dest": self.name, "dest": self.name,
"metavar": self.meta or None,
"action": self.action or "store", "action": self.action or "store",
"type": self.type or "string", "type": self.type or str,
"default": None, "default": None,
"help": "%s [%s]" % (self.short, self.default) "help": help_txt
} }
if self.meta is not None:
kwargs['metavar'] = self.meta
if kwargs["action"] != "store": if kwargs["action"] != "store":
kwargs.pop("type") kwargs.pop("type")
parser.add_option(*args, **kwargs)
parser.add_argument(*args, **kwargs)
def copy(self): def copy(self):
return copy.copy(self) return copy.copy(self)
@ -195,7 +211,7 @@ class Setting(object):
return self.value return self.value
def set(self, val): def set(self, val):
assert callable(self.validator), "Invalid validator: %s" % self.name assert six.callable(self.validator), "Invalid validator: %s" % self.name
self.value = self.validator(val) self.value = self.validator(val)
def __lt__(self, other): def __lt__(self, other):
@ -209,7 +225,7 @@ Setting = SettingMeta('Setting', (Setting,), {})
def validate_bool(val): def validate_bool(val):
if isinstance(val, bool): if isinstance(val, bool):
return val return val
if not isinstance(val, string_types): if not isinstance(val, six.string_types):
raise TypeError("Invalid type for casting: %s" % val) raise TypeError("Invalid type for casting: %s" % val)
if val.lower().strip() == "true": if val.lower().strip() == "true":
return True return True
@ -226,7 +242,7 @@ def validate_dict(val):
def validate_pos_int(val): def validate_pos_int(val):
if not isinstance(val, integer_types): if not isinstance(val, six.integer_types):
val = int(val, 0) val = int(val, 0)
else: else:
# Booleans are ints! # Booleans are ints!
@ -239,7 +255,7 @@ def validate_pos_int(val):
def validate_string(val): def validate_string(val):
if val is None: if val is None:
return None return None
if not isinstance(val, string_types): if not isinstance(val, six.string_types):
raise TypeError("Not a string: %s" % val) raise TypeError("Not a string: %s" % val)
return val.strip() return val.strip()
@ -249,7 +265,7 @@ def validate_list_string(val):
return [] return []
# legacy syntax # legacy syntax
if isinstance(val, string_types): if isinstance(val, six.string_types):
val = [val] val = [val]
return [validate_string(v) for v in val] return [validate_string(v) for v in val]
@ -274,7 +290,7 @@ def validate_class(val):
def validate_callable(arity): def validate_callable(arity):
def _validate_callable(val): def _validate_callable(val):
if isinstance(val, string_types): if isinstance(val, six.string_types):
try: try:
mod_name, obj_name = val.rsplit(".", 1) mod_name, obj_name = val.rsplit(".", 1)
except ValueError: except ValueError:
@ -288,8 +304,8 @@ def validate_callable(arity):
except AttributeError: except AttributeError:
raise TypeError("Can not load '%s' from '%s'" raise TypeError("Can not load '%s' from '%s'"
"" % (obj_name, mod_name)) "" % (obj_name, mod_name))
if not callable(val): if not six.callable(val):
raise TypeError("Value is not callable: %s" % val) raise TypeError("Value is not six.callable: %s" % val)
if arity != -1 and arity != len(inspect.getargspec(val)[0]): if arity != -1 and arity != len(inspect.getargspec(val)[0]):
raise TypeError("Value must have an arity of: %s" % arity) raise TypeError("Value must have an arity of: %s" % arity)
return val return val
@ -388,7 +404,7 @@ class Backlog(Setting):
cli = ["--backlog"] cli = ["--backlog"]
meta = "INT" meta = "INT"
validator = validate_pos_int validator = validate_pos_int
type = "int" type = int
default = 2048 default = 2048
desc = """\ desc = """\
The maximum number of pending connections. The maximum number of pending connections.
@ -408,7 +424,7 @@ class Workers(Setting):
cli = ["-w", "--workers"] cli = ["-w", "--workers"]
meta = "INT" meta = "INT"
validator = validate_pos_int validator = validate_pos_int
type = "int" type = int
default = 1 default = 1
desc = """\ desc = """\
The number of worker process for handling requests. The number of worker process for handling requests.
@ -454,7 +470,7 @@ class WorkerConnections(Setting):
cli = ["--worker-connections"] cli = ["--worker-connections"]
meta = "INT" meta = "INT"
validator = validate_pos_int validator = validate_pos_int
type = "int" type = int
default = 1000 default = 1000
desc = """\ desc = """\
The maximum number of simultaneous clients. The maximum number of simultaneous clients.
@ -469,7 +485,7 @@ class MaxRequests(Setting):
cli = ["--max-requests"] cli = ["--max-requests"]
meta = "INT" meta = "INT"
validator = validate_pos_int validator = validate_pos_int
type = "int" type = int
default = 0 default = 0
desc = """\ desc = """\
The maximum number of requests a worker will process before restarting. The maximum number of requests a worker will process before restarting.
@ -489,7 +505,7 @@ class Timeout(Setting):
cli = ["-t", "--timeout"] cli = ["-t", "--timeout"]
meta = "INT" meta = "INT"
validator = validate_pos_int validator = validate_pos_int
type = "int" type = int
default = 30 default = 30
desc = """\ desc = """\
Workers silent for more than this many seconds are killed and restarted. Workers silent for more than this many seconds are killed and restarted.
@ -507,7 +523,7 @@ class GracefulTimeout(Setting):
cli = ["--graceful-timeout"] cli = ["--graceful-timeout"]
meta = "INT" meta = "INT"
validator = validate_pos_int validator = validate_pos_int
type = "int" type = int
default = 30 default = 30
desc = """\ desc = """\
Timeout for graceful workers restart. Timeout for graceful workers restart.
@ -524,7 +540,7 @@ class Keepalive(Setting):
cli = ["--keep-alive"] cli = ["--keep-alive"]
meta = "INT" meta = "INT"
validator = validate_pos_int validator = validate_pos_int
type = "int" type = int
default = 2 default = 2
desc = """\ desc = """\
The number of seconds to wait for requests on a Keep-Alive connection. The number of seconds to wait for requests on a Keep-Alive connection.
@ -539,7 +555,7 @@ class LimitRequestLine(Setting):
cli = ["--limit-request-line"] cli = ["--limit-request-line"]
meta = "INT" meta = "INT"
validator = validate_pos_int validator = validate_pos_int
type = "int" type = int
default = 4094 default = 4094
desc = """\ desc = """\
The maximum size of HTTP request line in bytes. The maximum size of HTTP request line in bytes.
@ -563,7 +579,7 @@ class LimitRequestFields(Setting):
cli = ["--limit-request-fields"] cli = ["--limit-request-fields"]
meta = "INT" meta = "INT"
validator = validate_pos_int validator = validate_pos_int
type = "int" type = int
default = 100 default = 100
desc = """\ desc = """\
Limit the number of HTTP headers fields in a request. Limit the number of HTTP headers fields in a request.
@ -581,7 +597,7 @@ class LimitRequestFieldSize(Setting):
cli = ["--limit-request-field_size"] cli = ["--limit-request-field_size"]
meta = "INT" meta = "INT"
validator = validate_pos_int validator = validate_pos_int
type = "int" type = int
default = 8190 default = 8190
desc = """\ desc = """\
Limit the allowed size of an HTTP request header field. Limit the allowed size of an HTTP request header field.
@ -716,7 +732,7 @@ class Umask(Setting):
cli = ["-m", "--umask"] cli = ["-m", "--umask"]
meta = "INT" meta = "INT"
validator = validate_pos_int validator = validate_pos_int
type = "int" type = int
default = 0 default = 0
desc = """\ desc = """\
A bit mask for the file mode on files written by Gunicorn. A bit mask for the file mode on files written by Gunicorn.
@ -977,7 +993,7 @@ class OnStarting(Setting):
name = "on_starting" name = "on_starting"
section = "Server Hooks" section = "Server Hooks"
validator = validate_callable(1) validator = validate_callable(1)
type = "callable" type = six.callable
def on_starting(server): def on_starting(server):
pass pass
@ -993,7 +1009,7 @@ class OnReload(Setting):
name = "on_reload" name = "on_reload"
section = "Server Hooks" section = "Server Hooks"
validator = validate_callable(1) validator = validate_callable(1)
type = "callable" type = six.callable
def on_reload(server): def on_reload(server):
pass pass
@ -1009,7 +1025,7 @@ class WhenReady(Setting):
name = "when_ready" name = "when_ready"
section = "Server Hooks" section = "Server Hooks"
validator = validate_callable(1) validator = validate_callable(1)
type = "callable" type = six.callable
def when_ready(server): def when_ready(server):
pass pass
@ -1025,7 +1041,7 @@ class Prefork(Setting):
name = "pre_fork" name = "pre_fork"
section = "Server Hooks" section = "Server Hooks"
validator = validate_callable(2) validator = validate_callable(2)
type = "callable" type = six.callable
def pre_fork(server, worker): def pre_fork(server, worker):
pass pass
@ -1042,7 +1058,7 @@ class Postfork(Setting):
name = "post_fork" name = "post_fork"
section = "Server Hooks" section = "Server Hooks"
validator = validate_callable(2) validator = validate_callable(2)
type = "callable" type = six.callable
def post_fork(server, worker): def post_fork(server, worker):
pass pass
@ -1059,7 +1075,7 @@ class PreExec(Setting):
name = "pre_exec" name = "pre_exec"
section = "Server Hooks" section = "Server Hooks"
validator = validate_callable(1) validator = validate_callable(1)
type = "callable" type = six.callable
def pre_exec(server): def pre_exec(server):
pass pass
@ -1075,7 +1091,7 @@ class PreRequest(Setting):
name = "pre_request" name = "pre_request"
section = "Server Hooks" section = "Server Hooks"
validator = validate_callable(2) validator = validate_callable(2)
type = "callable" type = six.callable
def pre_request(worker, req): def pre_request(worker, req):
worker.log.debug("%s %s" % (req.method, req.path)) worker.log.debug("%s %s" % (req.method, req.path))
@ -1092,7 +1108,7 @@ class PostRequest(Setting):
name = "post_request" name = "post_request"
section = "Server Hooks" section = "Server Hooks"
validator = validate_post_request validator = validate_post_request
type = "callable" type = six.callable
def post_request(worker, req, environ, resp): def post_request(worker, req, environ, resp):
pass pass
@ -1109,7 +1125,7 @@ class WorkerExit(Setting):
name = "worker_exit" name = "worker_exit"
section = "Server Hooks" section = "Server Hooks"
validator = validate_callable(2) validator = validate_callable(2)
type = "callable" type = six.callable
def worker_exit(server, worker): def worker_exit(server, worker):
pass pass
@ -1126,7 +1142,7 @@ class NumWorkersChanged(Setting):
name = "nworkers_changed" name = "nworkers_changed"
section = "Server Hooks" section = "Server Hooks"
validator = validate_callable(3) validator = validate_callable(3)
type = "callable" type = six.callable
def nworkers_changed(server, new_value, old_value): def nworkers_changed(server, new_value, old_value):
pass pass

View File

@ -34,7 +34,7 @@ class AltArgs(object):
class NoConfigApp(Application): class NoConfigApp(Application):
def __init__(self): def __init__(self):
super(NoConfigApp, self).__init__("no_usage") super(NoConfigApp, self).__init__("no_usage", prog="gunicorn_test")
def init(self, parser, opts, args): def init(self, parser, opts, args):
pass pass