Fixed #24979 -- Removed usage of inspect.getargspec().

This commit is contained in:
Tim Graham 2015-06-10 17:24:04 -04:00
parent 4b600ed244
commit 3872a33132
13 changed files with 118 additions and 40 deletions

View File

@ -14,6 +14,7 @@ from django.db import models
from django.http import Http404
from django.template.engine import Engine
from django.utils.decorators import method_decorator
from django.utils.inspect import func_has_no_args
from django.utils.translation import ugettext as _
from django.views.generic import TemplateView
@ -243,7 +244,7 @@ class ModelDetailView(BaseAdminDocsView):
# Gather model methods.
for func_name, func in model.__dict__.items():
if (inspect.isfunction(func) and len(inspect.getargspec(func)[0]) == 1):
if inspect.isfunction(func) and func_has_no_args(func):
try:
for exclude in MODEL_METHODS_EXCLUDE:
if func_name.startswith(exclude):

View File

@ -1,8 +1,8 @@
import argparse
import inspect
from django.contrib.gis import gdal
from django.core.management.base import BaseCommand, CommandError
from django.utils.inspect import get_func_args
class LayerOptionAction(argparse.Action):
@ -91,7 +91,7 @@ class Command(BaseCommand):
from django.contrib.gis.utils.ogrinspect import _ogrinspect, mapping
# Filter options to params accepted by `_ogrinspect`
ogr_options = {k: v for k, v in options.items()
if k in inspect.getargspec(_ogrinspect).args and v is not None}
if k in get_func_args(_ogrinspect) and v is not None}
output = [s for s in _ogrinspect(ds, model_name, **ogr_options)]
if options['mapping']:

View File

@ -2,7 +2,6 @@ import errno
import os
import warnings
from datetime import datetime
from inspect import getargspec
from django.conf import settings
from django.core.exceptions import SuspiciousFileOperation
@ -14,6 +13,7 @@ from django.utils.deconstruct import deconstructible
from django.utils.deprecation import RemovedInDjango20Warning
from django.utils.encoding import filepath_to_uri, force_text
from django.utils.functional import LazyObject
from django.utils.inspect import func_supports_parameter
from django.utils.module_loading import import_string
from django.utils.six.moves.urllib.parse import urljoin
from django.utils.text import get_valid_filename
@ -49,8 +49,7 @@ class Storage(object):
if not hasattr(content, 'chunks'):
content = File(content)
args, varargs, varkw, defaults = getargspec(self.get_available_name)
if 'max_length' in args:
if func_supports_parameter(self.get_available_name, 'max_length'):
name = self.get_available_name(name, max_length=max_length)
else:
warnings.warn(

View File

@ -3,7 +3,6 @@ from __future__ import unicode_literals
import collections
import datetime
import decimal
import inspect
import math
import os
import re
@ -18,6 +17,7 @@ from django.utils import datetime_safe, six
from django.utils._os import upath
from django.utils.encoding import force_text
from django.utils.functional import Promise
from django.utils.inspect import get_func_args
from django.utils.module_loading import module_dir
from django.utils.timezone import utc
from django.utils.version import get_docs_version
@ -97,7 +97,7 @@ class OperationWriter(object):
imports = set()
name, args, kwargs = self.operation.deconstruct()
argspec = inspect.getargspec(self.operation.__init__)
operation_args = get_func_args(self.operation.__init__)
# See if this operation is in django.db.migrations. If it is,
# We can just use the fact we already have that imported,
@ -110,15 +110,14 @@ class OperationWriter(object):
self.indent()
# Start at one because argspec includes "self"
for i, arg in enumerate(args, 1):
for i, arg in enumerate(args):
arg_value = arg
arg_name = argspec.args[i]
arg_name = operation_args[i]
_write(arg_name, arg_value)
i = len(args)
# Only iterate over remaining arguments
for arg_name in argspec.args[i + 1:]:
for arg_name in operation_args[i:]:
if arg_name in kwargs: # Don't sort to maintain signature order
arg_value = kwargs[arg_name]
_write(arg_name, arg_value)

View File

@ -1,7 +1,6 @@
import datetime
import os
import warnings
from inspect import getargspec
from django import forms
from django.core import checks
@ -13,6 +12,7 @@ from django.db.models.fields import Field
from django.utils import six
from django.utils.deprecation import RemovedInDjango20Warning
from django.utils.encoding import force_str, force_text
from django.utils.inspect import func_supports_parameter
from django.utils.translation import ugettext_lazy as _
@ -89,8 +89,7 @@ class FieldFile(File):
def save(self, name, content, save=True):
name = self.field.generate_filename(self.instance, name)
args, varargs, varkw, defaults = getargspec(self.storage.save)
if 'max_length' in args:
if func_supports_parameter(self.storage.save, 'max_length'):
self.name = self.storage.save(name, content, max_length=self.field.max_length)
else:
warnings.warn(

View File

@ -290,8 +290,16 @@ class ConnectionRouter(object):
# If the router doesn't have a method, skip to the next one.
continue
if six.PY3:
sig = inspect.signature(router.allow_migrate)
has_deprecated_signature = not any(
p.kind == inspect.Parameter.VAR_KEYWORD for p in sig.parameters.values()
)
else:
argspec = inspect.getargspec(router.allow_migrate)
if len(argspec.args) == 3 and not argspec.keywords:
has_deprecated_signature = len(argspec.args) == 3 and not argspec.keywords
if has_deprecated_signature:
warnings.warn(
"The signature of allow_migrate has changed from "
"allow_migrate(self, db, model) to "

View File

@ -4,6 +4,7 @@ import warnings
import weakref
from django.utils.deprecation import RemovedInDjango21Warning
from django.utils.inspect import func_accepts_kwargs
from django.utils.six.moves import range
if sys.version_info < (3, 4):
@ -89,24 +90,11 @@ class Signal(object):
# If DEBUG is on, check that we got a good receiver
if settings.configured and settings.DEBUG:
import inspect
assert callable(receiver), "Signal receivers must be callable."
# Check for **kwargs
# Not all callables are inspectable with getargspec, so we'll
# try a couple different ways but in the end fall back on assuming
# it is -- we don't want to prevent registration of valid but weird
# callables.
try:
argspec = inspect.getargspec(receiver)
except TypeError:
try:
argspec = inspect.getargspec(receiver.__call__)
except (TypeError, AttributeError):
argspec = None
if argspec:
assert argspec[2] is not None, \
"Signal receivers must accept keyword arguments (**kwargs)."
if not func_accepts_kwargs(receiver):
raise ValueError("Signal receivers must accept keyword arguments (**kwargs).")
if dispatch_uid:
lookup_key = (dispatch_uid, _make_id(sender))

View File

@ -51,10 +51,10 @@ u'<html></html>'
from __future__ import unicode_literals
import inspect
import logging
import re
import warnings
from inspect import getargspec, getcallargs
from django.template.context import ( # NOQA: imported for backwards compatibility
BaseContext, Context, ContextPopException, RequestContext,
@ -66,6 +66,7 @@ from django.utils.encoding import (
)
from django.utils.formats import localize
from django.utils.html import conditional_escape, escape
from django.utils.inspect import getargspec
from django.utils.safestring import (
EscapeData, SafeData, mark_for_escaping, mark_safe,
)
@ -723,7 +724,8 @@ class FilterExpression(object):
plen = len(provided) + 1
# Check to see if a decorator is providing the real function.
func = getattr(func, '_decorated_function', func)
args, varargs, varkw, defaults = getargspec(func)
args, _, _, defaults = getargspec(func)
alen = len(args)
dlen = len(defaults or [])
# Not enough OR Too many
@ -884,7 +886,7 @@ class Variable(object):
current = current()
except TypeError:
try:
getcallargs(current)
inspect.getcallargs(current)
except TypeError: # arguments *were* required
current = context.template.engine.string_if_invalid # invalid method call
else:

View File

@ -1,10 +1,10 @@
import functools
import warnings
from importlib import import_module
from inspect import getargspec
from django.utils import six
from django.utils.deprecation import RemovedInDjango21Warning
from django.utils.inspect import getargspec
from django.utils.itercompat import is_iterable
from .base import Node, Template, token_kwargs

View File

@ -1,8 +1,8 @@
import warnings
from inspect import getargspec
from django.template import Origin, Template, TemplateDoesNotExist
from django.utils.deprecation import RemovedInDjango21Warning
from django.utils.inspect import func_supports_parameter
class Loader(object):
@ -28,7 +28,7 @@ class Loader(object):
args = [template_name]
# RemovedInDjango21Warning: Add template_dirs for compatibility with
# old loaders
if 'template_dirs' in getargspec(self.get_template_sources)[0]:
if func_supports_parameter(self.get_template_sources, 'template_dirs'):
args.append(template_dirs)
for origin in self.get_template_sources(*args):

View File

@ -5,11 +5,11 @@ to load templates from them in order, caching the result.
import hashlib
import warnings
from inspect import getargspec
from django.template import Origin, Template, TemplateDoesNotExist
from django.utils.deprecation import RemovedInDjango21Warning
from django.utils.encoding import force_bytes
from django.utils.inspect import func_supports_parameter
from .base import Loader as BaseLoader
@ -51,7 +51,7 @@ class Loader(BaseLoader):
args = [template_name]
# RemovedInDjango21Warning: Add template_dirs for compatibility
# with old loaders
if 'template_dirs' in getargspec(loader.get_template_sources)[0]:
if func_supports_parameter(loader.get_template_sources, 'template_dirs'):
args.append(template_dirs)
for origin in loader.get_template_sources(*args):
yield origin

View File

@ -1,3 +1,5 @@
from __future__ import absolute_import
import inspect
import warnings

80
django/utils/inspect.py Normal file
View File

@ -0,0 +1,80 @@
from __future__ import absolute_import
import inspect
from django.utils import six
def getargspec(func):
if six.PY2:
return inspect.getargspec(func)
sig = inspect.signature(func)
args = [
p.name for p in sig.parameters.values()
if p.kind == inspect.Parameter.POSITIONAL_OR_KEYWORD
]
varargs = [
p.name for p in sig.parameters.values()
if p.kind == inspect.Parameter.VAR_POSITIONAL
]
varargs = varargs[0] if varargs else None
varkw = [
p.name for p in sig.parameters.values()
if p.kind == inspect.Parameter.VAR_KEYWORD
]
varkw = varkw[0] if varkw else None
defaults = [
p.default for p in sig.parameters.values()
if p.kind == inspect.Parameter.POSITIONAL_OR_KEYWORD and p.default is not p.empty
] or None
return args, varargs, varkw, defaults
def get_func_args(func):
if six.PY2:
argspec = inspect.getargspec(func)
return argspec.args[1:] # ignore 'self'
sig = inspect.signature(func)
return [
arg_name for arg_name, param in sig.parameters.items()
if param.kind == inspect.Parameter.POSITIONAL_OR_KEYWORD
]
def func_accepts_kwargs(func):
if six.PY2:
# Not all callables are inspectable with getargspec, so we'll
# try a couple different ways but in the end fall back on assuming
# it is -- we don't want to prevent registration of valid but weird
# callables.
try:
argspec = inspect.getargspec(func)
except TypeError:
try:
argspec = inspect.getargspec(func.__call__)
except (TypeError, AttributeError):
argspec = None
return not argspec or argspec[2] is not None
return any(
p for p in inspect.signature(func).parameters.values()
if p.kind == p.VAR_KEYWORD
)
def func_has_no_args(func):
args = inspect.getargspec(func)[0] if six.PY2 else [
p for p in inspect.signature(func).parameters.values()
if p.kind == p.POSITIONAL_OR_KEYWORD and p.default is p.empty
]
return len(args) == 1
def func_supports_parameter(func, parameter):
if six.PY3:
return parameter in inspect.signature(func).parameters
else:
args, varargs, varkw, defaults = inspect.getargspec(func)
return parameter in args