1
0
mirror of https://github.com/django/django.git synced 2025-06-05 11:39:13 +00:00

[1.8.x] Fixed #24979 -- Removed usage of inspect.getargspec().

Backport of 3872a33132a4bb6aa22b237927597bbfdf6f21d7 from master
This commit is contained in:
Tim Graham 2015-06-10 17:24:04 -04:00
parent 84ec3bfc11
commit e2ea30c440
10 changed files with 114 additions and 36 deletions

View File

@ -20,6 +20,7 @@ from django.template.engine import Engine
from django.utils import six from django.utils import six
from django.utils._os import upath from django.utils._os import upath
from django.utils.decorators import method_decorator 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.utils.translation import ugettext as _
from django.views.generic import TemplateView from django.views.generic import TemplateView
@ -247,7 +248,7 @@ class ModelDetailView(BaseAdminDocsView):
# Gather model methods. # Gather model methods.
for func_name, func in model.__dict__.items(): 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: try:
for exclude in MODEL_METHODS_EXCLUDE: for exclude in MODEL_METHODS_EXCLUDE:
if func_name.startswith(exclude): if func_name.startswith(exclude):

View File

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

View File

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

View File

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

View File

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

View File

@ -333,8 +333,16 @@ class ConnectionRouter(object):
# If the router doesn't have a method, skip to the next one. # If the router doesn't have a method, skip to the next one.
continue continue
argspec = inspect.getargspec(method) if six.PY3:
if len(argspec.args) == 3 and not argspec.keywords: 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)
has_deprecated_signature = len(argspec.args) == 3 and not argspec.keywords
if has_deprecated_signature:
warnings.warn( warnings.warn(
"The signature of allow_migrate has changed from " "The signature of allow_migrate has changed from "
"allow_migrate(self, db, model) to " "allow_migrate(self, db, model) to "

View File

@ -2,6 +2,7 @@ import sys
import threading import threading
import weakref import weakref
from django.utils.inspect import func_accepts_kwargs
from django.utils.six.moves import range from django.utils.six.moves import range
if sys.version_info < (3, 4): if sys.version_info < (3, 4):
@ -87,24 +88,11 @@ class Signal(object):
# If DEBUG is on, check that we got a good receiver # If DEBUG is on, check that we got a good receiver
if settings.configured and settings.DEBUG: if settings.configured and settings.DEBUG:
import inspect
assert callable(receiver), "Signal receivers must be callable." assert callable(receiver), "Signal receivers must be callable."
# Check for **kwargs # Check for **kwargs
# Not all callables are inspectable with getargspec, so we'll if not func_accepts_kwargs(receiver):
# try a couple different ways but in the end fall back on assuming raise ValueError("Signal receivers must accept keyword arguments (**kwargs).")
# 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 dispatch_uid: if dispatch_uid:
lookup_key = (dispatch_uid, _make_id(sender)) lookup_key = (dispatch_uid, _make_id(sender))

View File

@ -51,11 +51,11 @@ u'<html></html>'
from __future__ import unicode_literals from __future__ import unicode_literals
import inspect
import re import re
import warnings import warnings
from functools import partial from functools import partial
from importlib import import_module from importlib import import_module
from inspect import getargspec, getcallargs
from django.apps import apps from django.apps import apps
from django.template.context import ( # NOQA: imported for backwards compatibility from django.template.context import ( # NOQA: imported for backwards compatibility
@ -68,6 +68,7 @@ from django.utils.encoding import (
) )
from django.utils.formats import localize from django.utils.formats import localize
from django.utils.html import conditional_escape from django.utils.html import conditional_escape
from django.utils.inspect import getargspec
from django.utils.itercompat import is_iterable from django.utils.itercompat import is_iterable
from django.utils.module_loading import module_has_submodule from django.utils.module_loading import module_has_submodule
from django.utils.safestring import ( from django.utils.safestring import (
@ -686,7 +687,8 @@ class FilterExpression(object):
plen = len(provided) + 1 plen = len(provided) + 1
# Check to see if a decorator is providing the real function. # Check to see if a decorator is providing the real function.
func = getattr(func, '_decorated_function', func) func = getattr(func, '_decorated_function', func)
args, varargs, varkw, defaults = getargspec(func)
args, _, _, defaults = getargspec(func)
alen = len(args) alen = len(args)
dlen = len(defaults or []) dlen = len(defaults or [])
# Not enough OR Too many # Not enough OR Too many
@ -847,7 +849,7 @@ class Variable(object):
current = current() current = current()
except TypeError: except TypeError:
try: try:
getcallargs(current) inspect.getcallargs(current)
except TypeError: # arguments *were* required except TypeError: # arguments *were* required
current = context.template.engine.string_if_invalid # invalid method call current = context.template.engine.string_if_invalid # invalid method call
else: else:

View File

@ -1,3 +1,5 @@
from __future__ import absolute_import
import inspect import inspect
import warnings 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