Skip to content
Projeler
Gruplar
Parçacıklar
Yardım
Yükleniyor...
Oturum aç / Kaydol
Gezinmeyi değiştir
C
cpython
Proje
Proje
Ayrıntılar
Etkinlik
Cycle Analytics
Depo (repository)
Depo (repository)
Dosyalar
Kayıtlar (commit)
Dallar (branch)
Etiketler
Katkıda bulunanlar
Grafik
Karşılaştır
Grafikler
Konular (issue)
0
Konular (issue)
0
Liste
Pano
Etiketler
Kilometre Taşları
Birleştirme (merge) Talepleri
0
Birleştirme (merge) Talepleri
0
CI / CD
CI / CD
İş akışları (pipeline)
İşler
Zamanlamalar
Grafikler
Paketler
Paketler
Wiki
Wiki
Parçacıklar
Parçacıklar
Üyeler
Üyeler
Collapse sidebar
Close sidebar
Etkinlik
Grafik
Grafikler
Yeni bir konu (issue) oluştur
İşler
Kayıtlar (commit)
Konu (issue) Panoları
Kenar çubuğunu aç
Batuhan Osman TASKAYA
cpython
Commits
95fc51df
Kaydet (Commit)
95fc51df
authored
Kas 20, 2010
tarafından
Michael Foord
Dosyalara gözat
Seçenekler
Dosyalara Gözat
İndir
Eposta Yamaları
Sade Fark
Issue 9732: addition of getattr_static to the inspect module
üst
89197fe9
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
295 additions
and
2 deletions
+295
-2
glossary.rst
Doc/glossary.rst
+8
-0
inspect.rst
Doc/library/inspect.rst
+67
-0
inspect.py
Lib/inspect.py
+64
-0
test_inspect.py
Lib/test/test_inspect.py
+151
-1
NEWS
Misc/NEWS
+2
-0
python-wing4.wpr
Misc/python-wing4.wpr
+3
-1
No files found.
Doc/glossary.rst
Dosyayı görüntüle @
95fc51df
...
...
@@ -435,6 +435,14 @@ Glossary
its first :term:`argument` (which is usually called ``self``).
See :term:`function` and :term:`nested scope`.
method resolution order
Method Resolution Order is the order in which base classes are searched
for a member during lookup. See `The Python 2.3 Method Resolution Order
<http://www.python.org/download/releases/2.3/mro/>`_.
MRO
See :term:`method resolution order`.
mutable
Mutable objects can change their value but keep their :func:`id`. See
also :term:`immutable`.
...
...
Doc/library/inspect.rst
Dosyayı görüntüle @
95fc51df
...
...
@@ -563,3 +563,70 @@ line.
entry in the list represents the caller; the last entry represents where the
exception was raised.
Fetching attributes statically
------------------------------
Both :func:`getattr` and :func:`hasattr` can trigger code execution when
fetching or checking for the existence of attributes. Descriptors, like
properties, will be invoked and :meth:`__getattr__` and :meth:`__getattribute__`
may be called.
For cases where you want passive introspection, like documentation tools, this
can be inconvenient. `getattr_static` has the same signature as :func:`getattr`
but avoids executing code when it fetches attributes.
.. function:: getattr_static(obj, attr, default=None)
Retrieve attributes without triggering dynamic lookup via the
descriptor protocol, `__getattr__` or `__getattribute__`.
Note: this function may not be able to retrieve all attributes
that getattr can fetch (like dynamically created attributes)
and may find attributes that getattr can't (like descriptors
that raise AttributeError). It can also return descriptors objects
instead of instance members.
There are several cases that will break `getattr_static` or be handled
incorrectly. These are pathological enough not to worry about (i.e. if you do
any of these then you deserve to have everything break anyway):
* :data:`~object.__dict__` existing (e.g. as a property) but returning the
wrong dictionary or even returning something other than a
dictionary
* classes created with :data:`~object.__slots__` that have the `__slots__`
member deleted from the class, or a fake `__slots__` attribute
attached to the instance, or any other monkeying with
`__slots__`
* objects that lie about their type by having `__class__` as a
descriptor (`getattr_static` traverses the :term:`MRO` of whatever type
`obj.__class__` returns instead of the real type)
* type objects that lie about their :term:`MRO`
Descriptors are not resolved (for example slot descriptors or
getset descriptors on objects implemented in C). The descriptor
is returned instead of the underlying attribute.
You can handle these with code like the following. Note that
for arbitrary getset descriptors invoking these may trigger
code execution::
# example code for resolving the builtin descriptor types
class _foo(object):
__slots__ = ['foo']
slot_descriptor = type(_foo.foo)
getset_descriptor = type(type(open(__file__)).name)
wrapper_descriptor = type(str.__dict__['__add__'])
descriptor_types = (slot_descriptor, getset_descriptor, wrapper_descriptor)
result = getattr_static(some_object, 'foo')
if type(result) in descriptor_types:
try:
result = result.__get__()
except AttributeError:
# descriptors can raise AttributeError to
# indicate there is no underlying value
# in which case the descriptor itself will
# have to do
pass
Lib/inspect.py
Dosyayı görüntüle @
95fc51df
...
...
@@ -1054,3 +1054,67 @@ def stack(context=1):
def
trace
(
context
=
1
):
"""Return a list of records for the stack below the current exception."""
return
getinnerframes
(
sys
.
exc_info
()[
2
],
context
)
# ------------------------------------------------ static version of getattr
_sentinel
=
object
()
def
_check_instance
(
obj
,
attr
):
instance_dict
=
{}
try
:
instance_dict
=
object
.
__getattribute__
(
obj
,
"__dict__"
)
except
AttributeError
:
pass
return
instance_dict
.
get
(
attr
,
_sentinel
)
def
_check_class
(
klass
,
attr
):
for
entry
in
getmro
(
klass
):
try
:
return
entry
.
__dict__
[
attr
]
except
KeyError
:
pass
return
_sentinel
def
getattr_static
(
obj
,
attr
,
default
=
_sentinel
):
"""Retrieve attributes without triggering dynamic lookup via the
descriptor protocol, __getattr__ or __getattribute__.
Note: this function may not be able to retrieve all attributes
that getattr can fetch (like dynamically created attributes)
and may find attributes that getattr can't (like descriptors
that raise AttributeError). It can also return descriptor objects
instead of instance members in some cases. See the
documentation for details.
"""
instance_result
=
_sentinel
if
not
isinstance
(
obj
,
type
):
instance_result
=
_check_instance
(
obj
,
attr
)
klass
=
obj
.
__class__
else
:
klass
=
obj
klass_result
=
_check_class
(
klass
,
attr
)
if
instance_result
is
not
_sentinel
and
klass_result
is
not
_sentinel
:
if
(
_check_class
(
type
(
klass_result
),
'__get__'
)
is
not
_sentinel
and
_check_class
(
type
(
klass_result
),
'__set__'
)
is
not
_sentinel
):
return
klass_result
if
instance_result
is
not
_sentinel
:
return
instance_result
if
klass_result
is
not
_sentinel
:
return
klass_result
if
obj
is
klass
:
# for types we check the metaclass too
for
entry
in
getmro
(
type
(
klass
)):
try
:
return
entry
.
__dict__
[
attr
]
except
KeyError
:
pass
if
default
is
not
_sentinel
:
return
default
raise
AttributeError
(
attr
)
Lib/test/test_inspect.py
Dosyayı görüntüle @
95fc51df
...
...
@@ -706,12 +706,162 @@ class TestGetcallargsUnboundMethods(TestGetcallargsMethods):
locs
=
dict
(
locs
or
{},
inst
=
self
.
inst
)
return
(
func
,
'inst,'
+
call_params_string
,
locs
)
class
TestGetattrStatic
(
unittest
.
TestCase
):
def
test_basic
(
self
):
class
Thing
(
object
):
x
=
object
()
thing
=
Thing
()
self
.
assertEqual
(
inspect
.
getattr_static
(
thing
,
'x'
),
Thing
.
x
)
self
.
assertEqual
(
inspect
.
getattr_static
(
thing
,
'x'
,
None
),
Thing
.
x
)
with
self
.
assertRaises
(
AttributeError
):
inspect
.
getattr_static
(
thing
,
'y'
)
self
.
assertEqual
(
inspect
.
getattr_static
(
thing
,
'y'
,
3
),
3
)
def
test_inherited
(
self
):
class
Thing
(
object
):
x
=
object
()
class
OtherThing
(
Thing
):
pass
something
=
OtherThing
()
self
.
assertEqual
(
inspect
.
getattr_static
(
something
,
'x'
),
Thing
.
x
)
def
test_instance_attr
(
self
):
class
Thing
(
object
):
x
=
2
def
__init__
(
self
,
x
):
self
.
x
=
x
thing
=
Thing
(
3
)
self
.
assertEqual
(
inspect
.
getattr_static
(
thing
,
'x'
),
3
)
del
thing
.
x
self
.
assertEqual
(
inspect
.
getattr_static
(
thing
,
'x'
),
2
)
def
test_property
(
self
):
class
Thing
(
object
):
@property
def
x
(
self
):
raise
AttributeError
(
"I'm pretending not to exist"
)
thing
=
Thing
()
self
.
assertEqual
(
inspect
.
getattr_static
(
thing
,
'x'
),
Thing
.
x
)
def
test_descriptor
(
self
):
class
descriptor
(
object
):
def
__get__
(
*
_
):
raise
AttributeError
(
"I'm pretending not to exist"
)
desc
=
descriptor
()
class
Thing
(
object
):
x
=
desc
thing
=
Thing
()
self
.
assertEqual
(
inspect
.
getattr_static
(
thing
,
'x'
),
desc
)
def
test_classAttribute
(
self
):
class
Thing
(
object
):
x
=
object
()
self
.
assertEqual
(
inspect
.
getattr_static
(
Thing
,
'x'
),
Thing
.
x
)
def
test_inherited_classattribute
(
self
):
class
Thing
(
object
):
x
=
object
()
class
OtherThing
(
Thing
):
pass
self
.
assertEqual
(
inspect
.
getattr_static
(
OtherThing
,
'x'
),
Thing
.
x
)
def
test_slots
(
self
):
class
Thing
(
object
):
y
=
'bar'
__slots__
=
[
'x'
]
def
__init__
(
self
):
self
.
x
=
'foo'
thing
=
Thing
()
self
.
assertEqual
(
inspect
.
getattr_static
(
thing
,
'x'
),
Thing
.
x
)
self
.
assertEqual
(
inspect
.
getattr_static
(
thing
,
'y'
),
'bar'
)
del
thing
.
x
self
.
assertEqual
(
inspect
.
getattr_static
(
thing
,
'x'
),
Thing
.
x
)
def
test_metaclass
(
self
):
class
meta
(
type
):
attr
=
'foo'
class
Thing
(
object
,
metaclass
=
meta
):
pass
self
.
assertEqual
(
inspect
.
getattr_static
(
Thing
,
'attr'
),
'foo'
)
class
sub
(
meta
):
pass
class
OtherThing
(
object
,
metaclass
=
sub
):
x
=
3
self
.
assertEqual
(
inspect
.
getattr_static
(
OtherThing
,
'attr'
),
'foo'
)
class
OtherOtherThing
(
OtherThing
):
pass
# this test is odd, but it was added as it exposed a bug
self
.
assertEqual
(
inspect
.
getattr_static
(
OtherOtherThing
,
'x'
),
3
)
def
test_no_dict_no_slots
(
self
):
self
.
assertEqual
(
inspect
.
getattr_static
(
1
,
'foo'
,
None
),
None
)
self
.
assertNotEqual
(
inspect
.
getattr_static
(
'foo'
,
'lower'
),
None
)
def
test_no_dict_no_slots_instance_member
(
self
):
# returns descriptor
with
open
(
__file__
)
as
handle
:
self
.
assertEqual
(
inspect
.
getattr_static
(
handle
,
'name'
),
type
(
handle
)
.
name
)
def
test_inherited_slots
(
self
):
# returns descriptor
class
Thing
(
object
):
__slots__
=
[
'x'
]
def
__init__
(
self
):
self
.
x
=
'foo'
class
OtherThing
(
Thing
):
pass
# it would be nice if this worked...
# we get the descriptor instead of the instance attribute
self
.
assertEqual
(
inspect
.
getattr_static
(
OtherThing
(),
'x'
),
Thing
.
x
)
def
test_descriptor
(
self
):
class
descriptor
(
object
):
def
__get__
(
self
,
instance
,
owner
):
return
3
class
Foo
(
object
):
d
=
descriptor
()
foo
=
Foo
()
# for a non data descriptor we return the instance attribute
foo
.
__dict__
[
'd'
]
=
1
self
.
assertEqual
(
inspect
.
getattr_static
(
foo
,
'd'
),
1
)
# if the descriptor is a data-desciptor we should return the
# descriptor
descriptor
.
__set__
=
lambda
s
,
i
,
v
:
None
self
.
assertEqual
(
inspect
.
getattr_static
(
foo
,
'd'
),
Foo
.
__dict__
[
'd'
])
def
test_metaclass_with_descriptor
(
self
):
class
descriptor
(
object
):
def
__get__
(
self
,
instance
,
owner
):
return
3
class
meta
(
type
):
d
=
descriptor
()
class
Thing
(
object
,
metaclass
=
meta
):
pass
self
.
assertEqual
(
inspect
.
getattr_static
(
Thing
,
'd'
),
meta
.
__dict__
[
'd'
])
def
test_main
():
run_unittest
(
TestDecorators
,
TestRetrievingSourceCode
,
TestOneliners
,
TestBuggyCases
,
TestInterpreterStack
,
TestClassesAndFunctions
,
TestPredicates
,
TestGetcallargsFunctions
,
TestGetcallargsMethods
,
TestGetcallargsUnboundMethods
)
TestGetcallargsUnboundMethods
,
TestGetattrStatic
)
if
__name__
==
"__main__"
:
test_main
()
Misc/NEWS
Dosyayı görüntüle @
95fc51df
...
...
@@ -25,6 +25,8 @@ Library
complex zeros on systems where the log1p function fails to respect
the sign of zero. This fixes a test failure on AIX.
- Issue #9732: Addition of getattr_static to the inspect module.
- Issue #10446: Module documentation generated by pydoc now links to a
version-specific online reference manual.
...
...
Misc/python-wing4.wpr
Dosyayı görüntüle @
95fc51df
...
...
@@ -5,7 +5,9 @@
##################################################################
[project attributes]
proj.directory-list = [{'dirloc': loc('..'),
'excludes': [u'Lib/__pycache__'],
'excludes': [u'Lib/__pycache__',
u'Doc/build',
u'build'],
'filter': '*',
'include_hidden': False,
'recursive': True,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment