pyobject 1.2.6__tar.gz → 1.2.7__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. pyobject-1.2.7/LICENSE +21 -0
  2. {pyobject-1.2.6/pyobject.egg-info → pyobject-1.2.7}/PKG-INFO +23 -12
  3. {pyobject-1.2.6 → pyobject-1.2.7}/README.rst +22 -10
  4. {pyobject-1.2.6 → pyobject-1.2.7}/pyobject/__init__.py +6 -3
  5. {pyobject-1.2.6 → pyobject-1.2.7}/pyobject/browser.py +41 -28
  6. {pyobject-1.2.6 → pyobject-1.2.7}/pyobject/pyobj_extension.c +68 -1
  7. {pyobject-1.2.6 → pyobject-1.2.7}/pyobject/test/browser_chs_locale.py +44 -30
  8. {pyobject-1.2.6 → pyobject-1.2.7/pyobject.egg-info}/PKG-INFO +23 -12
  9. {pyobject-1.2.6 → pyobject-1.2.7}/setup.py +0 -1
  10. pyobject-1.2.6/LICENSE +0 -674
  11. {pyobject-1.2.6 → pyobject-1.2.7}/MANIFEST.in +0 -0
  12. {pyobject-1.2.6 → pyobject-1.2.7}/pyobject/code_.py +0 -0
  13. {pyobject-1.2.6 → pyobject-1.2.7}/pyobject/images/back.gif +0 -0
  14. {pyobject-1.2.6 → pyobject-1.2.7}/pyobject/images/codeobject.gif +0 -0
  15. {pyobject-1.2.6 → pyobject-1.2.7}/pyobject/images/dict.gif +0 -0
  16. {pyobject-1.2.6 → pyobject-1.2.7}/pyobject/images/empty_dict.gif +0 -0
  17. {pyobject-1.2.6 → pyobject-1.2.7}/pyobject/images/empty_list.gif +0 -0
  18. {pyobject-1.2.6 → pyobject-1.2.7}/pyobject/images/empty_tuple.gif +0 -0
  19. {pyobject-1.2.6 → pyobject-1.2.7}/pyobject/images/forward.gif +0 -0
  20. {pyobject-1.2.6 → pyobject-1.2.7}/pyobject/images/function.gif +0 -0
  21. {pyobject-1.2.6 → pyobject-1.2.7}/pyobject/images/list.gif +0 -0
  22. {pyobject-1.2.6 → pyobject-1.2.7}/pyobject/images/number.gif +0 -0
  23. {pyobject-1.2.6 → pyobject-1.2.7}/pyobject/images/python.gif +0 -0
  24. {pyobject-1.2.6 → pyobject-1.2.7}/pyobject/images/python.ico +0 -0
  25. {pyobject-1.2.6 → pyobject-1.2.7}/pyobject/images/refresh.gif +0 -0
  26. {pyobject-1.2.6 → pyobject-1.2.7}/pyobject/images/string.gif +0 -0
  27. {pyobject-1.2.6 → pyobject-1.2.7}/pyobject/images/tuple.gif +0 -0
  28. {pyobject-1.2.6 → pyobject-1.2.7}/pyobject/newtypes.py +0 -0
  29. {pyobject-1.2.6 → pyobject-1.2.7}/pyobject/search.py +0 -0
  30. {pyobject-1.2.6 → pyobject-1.2.7}/pyobject/super_reflect.py +0 -0
  31. {pyobject-1.2.6 → pyobject-1.2.7}/pyobject/test/README.md +0 -0
  32. {pyobject-1.2.6 → pyobject-1.2.7}/pyobject/test/__init__.py +0 -0
  33. {pyobject-1.2.6 → pyobject-1.2.7}/pyobject/test/empty.pyc +0 -0
  34. {pyobject-1.2.6 → pyobject-1.2.7}/pyobject/test/interpreter_shutdown.py +0 -0
  35. {pyobject-1.2.6 → pyobject-1.2.7}/pyobject/test/pyc_zipper_lzma.py +0 -0
  36. {pyobject-1.2.6 → pyobject-1.2.7}/pyobject/test/pyc_zipper_unpack.py +0 -0
  37. {pyobject-1.2.6 → pyobject-1.2.7}/pyobject/test/pyc_zipper_zlib.py +0 -0
  38. {pyobject-1.2.6 → pyobject-1.2.7}/pyobject/test/testcode.py +0 -0
  39. {pyobject-1.2.6 → pyobject-1.2.7}/pyobject.egg-info/SOURCES.txt +0 -0
  40. {pyobject-1.2.6 → pyobject-1.2.7}/pyobject.egg-info/dependency_links.txt +0 -0
  41. {pyobject-1.2.6 → pyobject-1.2.7}/pyobject.egg-info/top_level.txt +0 -0
  42. {pyobject-1.2.6 → pyobject-1.2.7}/setup.cfg +0 -0
pyobject-1.2.7/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 qfcy
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -1,13 +1,12 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pyobject
3
- Version: 1.2.6
3
+ Version: 1.2.7
4
4
  Summary: 一个提供操作Python对象底层工具的模块。A utility tool with some submodules for operating internal python objects.
5
5
  Home-page: https://github.com/qfcy/pyobject
6
6
  Author: qfcy
7
7
  Author-email: 3076711200@qq.com
8
8
  Keywords: pyobject,python,object,utility,object browser,bytecode,reflect,object search,OOP,对象,字节码,对象浏览器
9
9
  Classifier: Programming Language :: Python
10
- Classifier: Natural Language :: Chinese (Simplified)
11
10
  Classifier: Topic :: Utilities
12
11
  Classifier: Topic :: Software Development :: Bug Tracking
13
12
  Classifier: Topic :: Software Development :: Debuggers
@@ -143,7 +142,9 @@ def __init__(self, code=None)
143
142
 
144
143
  方法
145
144
  -------
146
- ### 主要方法
145
+
146
+ **主要方法**
147
+
147
148
  - ``exec(globals_=None, locals_=None)``:在全局和局部作用域字典中执行代码对象。
148
149
  - ``eval(globals_=None, locals_=None)``:在全局和局部作用域字典中执行代码对象,并获取返回值。
149
150
  - ``copy()``:复制一份``Code``对象,返回复制的副本。
@@ -152,20 +153,21 @@ def __init__(self, code=None)
152
153
  - ``get_flags()``:返回 ``co_flags`` 属性的标志名称列表,如``["NOFREE"]``。
153
154
  - ``get_sub_code(name)``:搜索代码的``co_consts``中的子代码,如函数、类定义等,不会递归搜索。返回搜索到的``Code``对象,未找到时抛出``ValueError``。
154
155
 
155
- ### 序列化
156
+ **序列化**
157
+
156
158
  - ``to_pycfile(filename)``:使用 ``marshal`` 模块将代码对象转储到 ``.pyc`` 文件中。
157
159
  - ``from_pycfile(filename)``:从 ``.pyc`` 文件创建 ``Code`` 实例。
158
160
  - ``from_file(filename)``:从 ``.py`` 或 ``.pyc`` 文件创建 ``Code`` 实例。
159
161
  - ``pickle(filename)``:将 ``Code`` 对象序列化为 pickle 文件。
160
162
 
161
- ### 调试和检查
163
+ **调试和检查**
162
164
 
163
165
  - ``show(*args, **kw)``:在内部调用``pyobject.desc``,显示代码对象的属性,参数用法和``desc()``的用法相同。
164
166
  - ``info()``:在内部调用``dis.show_code``,显示字节码的基本信息。
165
167
  - ``dis(*args, **kw)``:调用 ``dis`` 模块输出字节码的反汇编,和``dis.dis(c.to_code())``相同。
166
168
  - ``decompile(version=None, *args, **kw)``:调用 ``uncompyle6`` 库将代码对象反编译为源代码。(安装``pyobject``库时, ``uncompyle6`` 库是可选的。)
167
169
 
168
- ### 工厂函数
170
+ **工厂函数**
169
171
 
170
172
  - ``fromfunc(function)``:从 Python 函数对象创建 ``Code`` 实例,和``Code(func.__code__)``相同。
171
173
  - ``fromstring(string, mode='exec', filename='')``:从源代码字符串创建 ``Code`` 实例,参数用法和``compile``内置函数相同,在内部调用``compile()``。
@@ -244,10 +246,12 @@ list_in(obj, lst)::
244
246
  本函数直接比较对象的指针,提高了效率。
245
247
 
246
248
 
247
- 版本: 1.2.6
249
+ 版本: 1.2.7
248
250
 
249
251
  更新日志:
250
252
 
253
+ 2025-3-6(v1.2.7):为pyobject.browser新增了``dir()``中不存在的类属性(如``__flags__``, ``__mro__``),修改了pyobj_extension模块。
254
+
251
255
  2025-2-15(v1.2.6):修复了pyobject.browser浏览过大对象的卡顿问题,改进了pyobject.code_模块,新增了正在开发中的反射库pyobject.super_reflect,
252
256
  在pyobj_extension新增了``getrefcount_nogil``和``setrefcount_nogil``。
253
257
 
@@ -388,7 +392,9 @@ Attributes introduced in Python 3.8 and later:
388
392
 
389
393
  Methods
390
394
  -------
391
- ### Core Methods
395
+
396
+ **Core Methods**
397
+
392
398
  - ``exec(globals_=None, locals_=None)``: Executes the code object within the provided global and local scope dictionaries.
393
399
  - ``eval(globals_=None, locals_=None)``: Executes the code object within the provided global and local scope dictionaries and returns the result.
394
400
  - ``copy()``: Creates a copy of the `Code` object and returns the duplicate.
@@ -397,19 +403,22 @@ Methods
397
403
  - ``get_flags()``: Returns a list of flag names for the ``co_flags`` attribute, e.g., ``["NOFREE"]``.
398
404
  - ``get_sub_code(name)``: Searches for sub-code objects (e.g., functions or class definitions) in the ``co_consts`` attribute. This method does not perform recursive searches. Returns the found `Code` object or raises a ``ValueError`` if not found.
399
405
 
400
- ### Serialization
406
+ **Serialization**
407
+
401
408
  - ``to_pycfile(filename)``: Dumps the code object into a `.pyc` file using the ``marshal`` module.
402
409
  - ``from_pycfile(filename)``: Creates a `Code` instance from a `.pyc` file.
403
410
  - ``from_file(filename)``: Creates a `Code` instance from a `.py` or `.pyc` file.
404
411
  - ``pickle(filename)``: Serializes the `Code` object into a pickle file.
405
412
 
406
- ### Debugging and Inspection
413
+ **Debugging and Inspection**
414
+
407
415
  - ``show(*args, **kw)``: Internally calls ``pyobject.desc`` to display the attributes of the code object. The parameters are the same as those used in ``desc()``.
408
416
  - ``info()``: Internally calls ``dis.show_code`` to display basic information about the bytecode.
409
417
  - ``dis(*args, **kw)``: Calls the ``dis`` module to output the disassembly of the bytecode, equivalent to ``dis.dis(c.to_code())``.
410
418
  - ``decompile(version=None, *args, **kw)``: Calls the ``uncompyle6`` library to decompile the code object into source code. (The ``uncompyle6`` library is optional when installing the ``pyobject`` package.)
411
419
 
412
- ### Factory Functions
420
+ **Factory Functions**
421
+
413
422
  - ``fromfunc(function)``: Creates a `Code` instance from a Python function object, equivalent to ``Code(func.__code__)``.
414
423
  - ``fromstring(string, mode='exec', filename='')``: Creates a `Code` instance from a source code string. The parameters are the same as those used in the built-in ``compile`` function, which is called internally.
415
424
 
@@ -486,11 +495,13 @@ list_in(obj, lst)::
486
495
  Compared to the built-in Python call "obj in lst" that invokes the "==" operator (__eq__) multiple times, this function directly compares the pointers to improve efficiency.
487
496
 
488
497
 
489
- Version: 1.2.6
498
+ Version: 1.2.7
490
499
 
491
500
  Change Log
492
501
  ==========
493
502
 
503
+ 2025-3-6(v1.2.7): Added support for special class attributes excluded from ``dir()`` (such as ``__flags__``, ``__mro__``) in pyobject.browser and modified the pyobj_extension module.
504
+
494
505
  2025-2-15 (v1.2.6): Fixed the lag issue when browsing large objects in ``pyobject.browser``, improved the ``pyobject.code_`` module, introduced a new reflection library
495
506
  ``pyobject.super_reflect`` currently in development, and added ``getrefcount_nogil`` and ``setrefcount_nogil`` to the ``pyobj_extension`` module.
496
507
 
@@ -126,7 +126,9 @@ def __init__(self, code=None)
126
126
 
127
127
  方法
128
128
  -------
129
- ### 主要方法
129
+
130
+ **主要方法**
131
+
130
132
  - ``exec(globals_=None, locals_=None)``:在全局和局部作用域字典中执行代码对象。
131
133
  - ``eval(globals_=None, locals_=None)``:在全局和局部作用域字典中执行代码对象,并获取返回值。
132
134
  - ``copy()``:复制一份``Code``对象,返回复制的副本。
@@ -135,20 +137,21 @@ def __init__(self, code=None)
135
137
  - ``get_flags()``:返回 ``co_flags`` 属性的标志名称列表,如``["NOFREE"]``。
136
138
  - ``get_sub_code(name)``:搜索代码的``co_consts``中的子代码,如函数、类定义等,不会递归搜索。返回搜索到的``Code``对象,未找到时抛出``ValueError``。
137
139
 
138
- ### 序列化
140
+ **序列化**
141
+
139
142
  - ``to_pycfile(filename)``:使用 ``marshal`` 模块将代码对象转储到 ``.pyc`` 文件中。
140
143
  - ``from_pycfile(filename)``:从 ``.pyc`` 文件创建 ``Code`` 实例。
141
144
  - ``from_file(filename)``:从 ``.py`` 或 ``.pyc`` 文件创建 ``Code`` 实例。
142
145
  - ``pickle(filename)``:将 ``Code`` 对象序列化为 pickle 文件。
143
146
 
144
- ### 调试和检查
147
+ **调试和检查**
145
148
 
146
149
  - ``show(*args, **kw)``:在内部调用``pyobject.desc``,显示代码对象的属性,参数用法和``desc()``的用法相同。
147
150
  - ``info()``:在内部调用``dis.show_code``,显示字节码的基本信息。
148
151
  - ``dis(*args, **kw)``:调用 ``dis`` 模块输出字节码的反汇编,和``dis.dis(c.to_code())``相同。
149
152
  - ``decompile(version=None, *args, **kw)``:调用 ``uncompyle6`` 库将代码对象反编译为源代码。(安装``pyobject``库时, ``uncompyle6`` 库是可选的。)
150
153
 
151
- ### 工厂函数
154
+ **工厂函数**
152
155
 
153
156
  - ``fromfunc(function)``:从 Python 函数对象创建 ``Code`` 实例,和``Code(func.__code__)``相同。
154
157
  - ``fromstring(string, mode='exec', filename='')``:从源代码字符串创建 ``Code`` 实例,参数用法和``compile``内置函数相同,在内部调用``compile()``。
@@ -227,10 +230,12 @@ list_in(obj, lst)::
227
230
  本函数直接比较对象的指针,提高了效率。
228
231
 
229
232
 
230
- 版本: 1.2.6
233
+ 版本: 1.2.7
231
234
 
232
235
  更新日志:
233
236
 
237
+ 2025-3-6(v1.2.7):为pyobject.browser新增了``dir()``中不存在的类属性(如``__flags__``, ``__mro__``),修改了pyobj_extension模块。
238
+
234
239
  2025-2-15(v1.2.6):修复了pyobject.browser浏览过大对象的卡顿问题,改进了pyobject.code_模块,新增了正在开发中的反射库pyobject.super_reflect,
235
240
  在pyobj_extension新增了``getrefcount_nogil``和``setrefcount_nogil``。
236
241
 
@@ -371,7 +376,9 @@ Attributes introduced in Python 3.8 and later:
371
376
 
372
377
  Methods
373
378
  -------
374
- ### Core Methods
379
+
380
+ **Core Methods**
381
+
375
382
  - ``exec(globals_=None, locals_=None)``: Executes the code object within the provided global and local scope dictionaries.
376
383
  - ``eval(globals_=None, locals_=None)``: Executes the code object within the provided global and local scope dictionaries and returns the result.
377
384
  - ``copy()``: Creates a copy of the `Code` object and returns the duplicate.
@@ -380,19 +387,22 @@ Methods
380
387
  - ``get_flags()``: Returns a list of flag names for the ``co_flags`` attribute, e.g., ``["NOFREE"]``.
381
388
  - ``get_sub_code(name)``: Searches for sub-code objects (e.g., functions or class definitions) in the ``co_consts`` attribute. This method does not perform recursive searches. Returns the found `Code` object or raises a ``ValueError`` if not found.
382
389
 
383
- ### Serialization
390
+ **Serialization**
391
+
384
392
  - ``to_pycfile(filename)``: Dumps the code object into a `.pyc` file using the ``marshal`` module.
385
393
  - ``from_pycfile(filename)``: Creates a `Code` instance from a `.pyc` file.
386
394
  - ``from_file(filename)``: Creates a `Code` instance from a `.py` or `.pyc` file.
387
395
  - ``pickle(filename)``: Serializes the `Code` object into a pickle file.
388
396
 
389
- ### Debugging and Inspection
397
+ **Debugging and Inspection**
398
+
390
399
  - ``show(*args, **kw)``: Internally calls ``pyobject.desc`` to display the attributes of the code object. The parameters are the same as those used in ``desc()``.
391
400
  - ``info()``: Internally calls ``dis.show_code`` to display basic information about the bytecode.
392
401
  - ``dis(*args, **kw)``: Calls the ``dis`` module to output the disassembly of the bytecode, equivalent to ``dis.dis(c.to_code())``.
393
402
  - ``decompile(version=None, *args, **kw)``: Calls the ``uncompyle6`` library to decompile the code object into source code. (The ``uncompyle6`` library is optional when installing the ``pyobject`` package.)
394
403
 
395
- ### Factory Functions
404
+ **Factory Functions**
405
+
396
406
  - ``fromfunc(function)``: Creates a `Code` instance from a Python function object, equivalent to ``Code(func.__code__)``.
397
407
  - ``fromstring(string, mode='exec', filename='')``: Creates a `Code` instance from a source code string. The parameters are the same as those used in the built-in ``compile`` function, which is called internally.
398
408
 
@@ -469,11 +479,13 @@ list_in(obj, lst)::
469
479
  Compared to the built-in Python call "obj in lst" that invokes the "==" operator (__eq__) multiple times, this function directly compares the pointers to improve efficiency.
470
480
 
471
481
 
472
- Version: 1.2.6
482
+ Version: 1.2.7
473
483
 
474
484
  Change Log
475
485
  ==========
476
486
 
487
+ 2025-3-6(v1.2.7): Added support for special class attributes excluded from ``dir()`` (such as ``__flags__``, ``__mro__``) in pyobject.browser and modified the pyobj_extension module.
488
+
477
489
  2025-2-15 (v1.2.6): Fixed the lag issue when browsing large objects in ``pyobject.browser``, improved the ``pyobject.code_`` module, introduced a new reflection library
478
490
  ``pyobject.super_reflect`` currently in development, and added ``getrefcount_nogil`` and ``setrefcount_nogil`` to the ``pyobj_extension`` module.
479
491
 
@@ -6,7 +6,7 @@ from warnings import warn
6
6
  from pprint import pprint
7
7
 
8
8
  __author__="qfcy"
9
- __version__="1.2.6"
9
+ __version__="1.2.7"
10
10
 
11
11
  _ignore_names=["__builtins__","__doc__"]
12
12
  __all__=["objectname","bases","describe","desc"]
@@ -15,7 +15,8 @@ def objectname(obj):
15
15
  """objectname(obj) - Returns the name of an object in the format xxmodule.xxclass.
16
16
  For example: objectname(int) -> 'builtins.int'."""
17
17
  if not obj.__class__==type:obj=obj.__class__
18
- if obj.__module__=="__main__":return obj.__name__
18
+ if not hasattr(obj,"__module__") or obj.__module__=="__main__":
19
+ return obj.__name__
19
20
  return "{}.{}".format(obj.__module__,obj.__name__)
20
21
 
21
22
  ###无递归版本
@@ -106,7 +107,9 @@ except (ImportError,SystemError):warn("Failed to import pyobject.code_.")
106
107
  try:
107
108
  from pyobj_extension import *
108
109
  __all__.extend(["convptr","py_incref","py_decref","getrealrefcount",
109
- "setrefcount","list_in","getrefcount_nogil","setrefcount_nogil"])
110
+ "setrefcount","list_in","getrefcount_nogil","setrefcount_nogil",
111
+ "get_type_flag","set_type_flag","set_type_base","set_type_bases",
112
+ "set_type_mro"])
110
113
  except ImportError:warn("Failed to import module pyobj_extension.")
111
114
 
112
115
  def test():
@@ -20,19 +20,18 @@ except ImportError:from __init__ import objectname,_shortrepr
20
20
  _IMAGE_PATH=os.path.join(os.path.split(__file__)[0],"images")
21
21
  SKIP=(WrapperDescriptorType, MethodWrapperType,\
22
22
  MethodDescriptorType, ClassMethodDescriptorType)
23
+ TYPE_EXTRA_ATTRS = ("__basicsize__","__dictoffset__","__flags__",
24
+ "__itemsize__","__weakrefoffset__")
25
+ TYPE_EXTRA_CLASS_ATTRS = ("__base__","__bases__","__mro__")
23
26
 
24
27
  def isfunc(obj):
25
28
  # 判断一个对象是否为函数或方法
26
29
  if isfunction(obj) or ismethod(obj):return True
27
30
  # 使用typing而不用types.WrapperDescriptorType是为了与旧版本兼容
28
31
  func_types=[types.LambdaType,types.BuiltinFunctionType,
29
- types.BuiltinMethodType,typing.WrapperDescriptorType,
30
- typing.MethodWrapperType,typing.MethodDescriptorType]
31
- if sys.version_info.minor>=7:
32
- ClassMethodDescriptorType=types.ClassMethodDescriptorType
33
- else: # 3.7之前的旧版本
34
- ClassMethodDescriptorType=type(dict.__dict__['fromkeys'])
35
- func_types.append(ClassMethodDescriptorType)
32
+ types.BuiltinMethodType,WrapperDescriptorType,
33
+ MethodWrapperType,MethodDescriptorType,
34
+ ClassMethodDescriptorType]
36
35
  for type_ in func_types:
37
36
  if isinstance(obj,type_):
38
37
  return True
@@ -223,15 +222,19 @@ class ObjectBrowser():
223
222
  self.tvw.item(self.functions_tag,open=True)
224
223
  # 添加属性
225
224
  attrs=dir(obj)
225
+ if isinstance(obj,type):
226
+ for attr in TYPE_EXTRA_ATTRS:
227
+ if hasattr(obj,attr):
228
+ attrs.append(attr) # 对类添加额外的,一般不会出现在dir()的返回值的属性
226
229
  for i in range(len(attrs)):
227
230
  attr=attrs[i]
228
231
  if self.verbose or not attr.startswith("_"):
229
232
  try:
230
- object=getattr(obj,attr)
231
- value=_shortrepr(object,self.MAX_VIEW_LEN)
232
- image=self._get_image(object)
233
- tags=("gray",) if isinstance(object,SKIP) else () # 将部分类型设为灰色,如MethodWrapperType
234
- self.tvw.insert(self._get_type(object), tk.END, #attr,
233
+ object_=getattr(obj,attr)
234
+ value=_shortrepr(object_,self.MAX_VIEW_LEN)
235
+ image=self._get_image(object_)
236
+ tags=("gray",) if isinstance(object_,SKIP) else () # 将部分类型设为灰色,如MethodWrapperType
237
+ self.tvw.insert(self._get_type(object_), tk.END, #attr,
235
238
  text=attr, image=image,
236
239
  values=(value,),tags=tags) # values从第二列开始
237
240
  except Exception as error: # 显示错误消息
@@ -239,20 +242,30 @@ class ObjectBrowser():
239
242
  self.tvw.insert(self.attributes_tag, tk.END,
240
243
  text=attr, image=self.obj_image,
241
244
  values=(value,),tags=("error",))
242
- # __bases__属性一般不会出现在dir()的返回值中
243
- if hasattr(obj,"__bases__") and "__bases__" not in attrs:
244
- bases=obj.__bases__
245
- self.tvw.insert(self.classes_tag, tk.END, "__bases__",
246
- text="__bases__", image=self._get_image(bases),
247
- values=(repr(bases),))
245
+ # 添加类特有的属性 (不会在dir()出现)
246
+ if isinstance(obj,type):
247
+ for attr in TYPE_EXTRA_CLASS_ATTRS:
248
+ if not hasattr(obj,attr):continue
249
+ try:
250
+ object_=getattr(obj,attr)
251
+ value=_shortrepr(object_,self.MAX_VIEW_LEN)
252
+ self.tvw.insert(self.classes_tag, tk.END,
253
+ text=attr, image=self._get_image(object_),
254
+ values=(value,))
255
+ except Exception as error: # 显示错误
256
+ value='<{}: {}>'.format(type(error).__name__,str(error))
257
+ self.tvw.insert(self.classes_tag, tk.END,
258
+ text=attr, image=self.obj_image,
259
+ values=(value,),tags=("error",))
260
+
248
261
  # 添加列表数据
249
262
  if isinstance(obj,(list,tuple)):
250
263
  for i in range(len(obj)):
251
264
  index=str(i)
252
265
  try:
253
- object=obj[i]
254
- value=_shortrepr(object,self.MAX_VIEW_LEN)
255
- image=self._get_image(object)
266
+ object_=obj[i]
267
+ value=_shortrepr(object_,self.MAX_VIEW_LEN)
268
+ image=self._get_image(object_)
256
269
  self.tvw.insert(self.lst_tag, tk.END,
257
270
  text=index, image=image,
258
271
  values=(value,))
@@ -267,9 +280,9 @@ class ObjectBrowser():
267
280
  for key in obj.keys():
268
281
  key_name=repr(key)
269
282
  try:
270
- object=obj[key]
271
- value=_shortrepr(object,self.MAX_VIEW_LEN)
272
- image=self._get_image(object)
283
+ object_=obj[key]
284
+ value=_shortrepr(object_,self.MAX_VIEW_LEN)
285
+ image=self._get_image(object_)
273
286
  self.tvw.insert(self.dict_tag, tk.END,
274
287
  text=key_name, image=image,
275
288
  values=(value,))
@@ -420,11 +433,11 @@ class ObjectBrowser():
420
433
  try:
421
434
  # 对象的属性可能有改变,重新获取对象的属性
422
435
  scope={self.rootobj_name:self.root_obj} # 获取第一个浏览的根对象及其名称
423
- object=eval(path,scope)
436
+ object_=eval(path,scope)
424
437
  except Exception: # 默认使用新获取的对象,只有出错时,才使用旧的对象
425
- object=obj
426
- else:object=obj
427
- self.browse(object,path)
438
+ object_=obj
439
+ else:object_=obj
440
+ self.browse(object_,path)
428
441
  def back(self): # 后退
429
442
  if self.history_index!=0:
430
443
  self.history_index-=1
@@ -204,6 +204,67 @@ PyObject *_list_setnull(PyObject *self, PyObject *args) {
204
204
  Py_RETURN_NONE;
205
205
  }
206
206
 
207
+ static PyObject* get_type_flag(PyObject *self, PyObject *args, PyObject *kwargs) {
208
+ static char *kwlist[] = {"typeobj", NULL};
209
+ PyObject *typeobj;
210
+
211
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", kwlist, &typeobj))
212
+ return NULL;
213
+
214
+ PyTypeObject *type = (PyTypeObject *)typeobj;
215
+ unsigned long flags = type->tp_flags;
216
+ return PyLong_FromUnsignedLong(flags);
217
+ }
218
+ static PyObject* set_type_flag(PyObject *self, PyObject *args, PyObject *kwargs) {
219
+ static char *kwlist[] = {"typeobj", "flag", NULL};
220
+ PyObject *typeobj, *flag;
221
+
222
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO", kwlist, &typeobj, &flag))
223
+ return NULL;
224
+
225
+ unsigned long new_flag = PyLong_AsUnsignedLong(flag);
226
+ PyTypeObject *type = (PyTypeObject *)typeobj;
227
+ type->tp_flags = new_flag;
228
+ Py_RETURN_NONE;
229
+ }
230
+
231
+ static PyObject* set_type_base(PyObject *self, PyObject *args, PyObject *kwargs) {
232
+ static char *kwlist[] = {"typeobj", "base", NULL};
233
+ PyObject *typeobj, *base;
234
+
235
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO", kwlist, &typeobj, &base))
236
+ return NULL;
237
+
238
+ Py_INCREF(base);
239
+ PyTypeObject *type = (PyTypeObject *)typeobj;
240
+ type->tp_base = base;
241
+ Py_RETURN_NONE;
242
+ }
243
+ static PyObject* set_type_bases(PyObject *self, PyObject *args, PyObject *kwargs) {
244
+ static char *kwlist[] = {"typeobj", "bases", NULL};
245
+ PyObject *typeobj, *bases;
246
+
247
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO", kwlist, &typeobj, &bases))
248
+ return NULL;
249
+
250
+ Py_INCREF(bases);
251
+ PyTypeObject *type = (PyTypeObject *)typeobj;
252
+ type->tp_bases = bases;
253
+ Py_RETURN_NONE;
254
+ }
255
+ static PyObject* set_type_mro(PyObject *self, PyObject *args, PyObject *kwargs) {
256
+ static char *kwlist[] = {"typeobj", "mro", NULL};
257
+ PyObject *typeobj, *mro;
258
+
259
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO", kwlist, &typeobj, &mro))
260
+ return NULL;
261
+
262
+ Py_INCREF(mro);
263
+ PyTypeObject *type = (PyTypeObject *)typeobj;
264
+ type->tp_mro = mro;
265
+ Py_RETURN_NONE;
266
+ }
267
+
207
268
  /*
208
269
  * List of functions to add to pyobj_extension in exec_pyobj_extension().
209
270
  */
@@ -216,7 +277,13 @@ static PyMethodDef pyobj_extension_functions[] = {
216
277
  { "getrefcount_nogil", (PyCFunction)getrefcount_nogil, METH_VARARGS, getrefcount_nogil_doc },
217
278
  { "setrefcount_nogil", (PyCFunction)setrefcount_nogil, METH_VARARGS | METH_KEYWORDS, setrefcount_nogil_doc },
218
279
  { "list_in", (PyCFunction)list_in, METH_VARARGS | METH_KEYWORDS, list_in_doc },
280
+
219
281
  { "_list_setnull", (PyCFunction)_list_setnull, METH_VARARGS, "_list_setnull(lst,index)"},
282
+ {"get_type_flag", (PyCFunction)get_type_flag, METH_VARARGS | METH_KEYWORDS, "get_type_flag(typeobj: type)"},
283
+ {"set_type_flag", (PyCFunction)set_type_flag, METH_VARARGS | METH_KEYWORDS, "set_type_flag(typeobj: type, flag: int)"},
284
+ {"set_type_base", (PyCFunction)set_type_base, METH_VARARGS | METH_KEYWORDS, "set_type_base(typeobj: type, base: type)"},
285
+ {"set_type_bases", (PyCFunction)set_type_bases, METH_VARARGS | METH_KEYWORDS, "set_type_bases(typeobj: type, bases: tuple)"},
286
+ {"set_type_mro", (PyCFunction)set_type_mro, METH_VARARGS | METH_KEYWORDS, "set_type_mro(typeobj: type, mro: tuple)"},
220
287
  { NULL, NULL, 0, NULL } /* marks end of array */
221
288
  };
222
289
 
@@ -227,7 +294,7 @@ static PyMethodDef pyobj_extension_functions[] = {
227
294
  int exec_pyobj_extension(PyObject *module) {
228
295
  PyModule_AddFunctions(module, pyobj_extension_functions);
229
296
  PyModule_AddStringConstant(module, "__author__", "qfcy");
230
- PyModule_AddStringConstant(module, "__version__", "1.2.6");
297
+ PyModule_AddStringConstant(module, "__version__", "1.2.7");
231
298
  PyModule_AddIntConstant(module, "_REFCNT_DELTA", REFCNT_DELTA);
232
299
 
233
300
  return 0; /* success */
@@ -21,19 +21,18 @@ except ImportError:from __init__ import objectname,_shortrepr
21
21
  _IMAGE_PATH=os.path.join(os.path.split(__file__)[0],"..","images")
22
22
  SKIP=(WrapperDescriptorType, MethodWrapperType,\
23
23
  MethodDescriptorType, ClassMethodDescriptorType)
24
+ TYPE_EXTRA_ATTRS = ("__basicsize__","__dictoffset__","__flags__",
25
+ "__itemsize__","__weakrefoffset__")
26
+ TYPE_EXTRA_CLASS_ATTRS = ("__base__","__bases__","__mro__")
24
27
 
25
28
  def isfunc(obj):
26
29
  # 判断一个对象是否为函数或方法
27
30
  if isfunction(obj) or ismethod(obj):return True
28
31
  # 使用typing而不用types.WrapperDescriptorType是为了与旧版本兼容
29
32
  func_types=[types.LambdaType,types.BuiltinFunctionType,
30
- types.BuiltinMethodType,typing.WrapperDescriptorType,
31
- typing.MethodWrapperType,typing.MethodDescriptorType]
32
- if sys.version_info.minor>=7:
33
- ClassMethodDescriptorType=types.ClassMethodDescriptorType
34
- else: # 3.7之前的旧版本
35
- ClassMethodDescriptorType=type(dict.__dict__['fromkeys'])
36
- func_types.append(ClassMethodDescriptorType)
33
+ types.BuiltinMethodType,WrapperDescriptorType,
34
+ MethodWrapperType,MethodDescriptorType,
35
+ ClassMethodDescriptorType]
37
36
  for type_ in func_types:
38
37
  if isinstance(obj,type_):
39
38
  return True
@@ -148,7 +147,8 @@ class ObjectBrowser():
148
147
  self.tvw.pack(side=tk.BOTTOM,expand=True,fill=tk.BOTH)
149
148
 
150
149
  self.menu=tk.Menu(self.master,tearoff=False)
151
- self.menu.add_command(label="新窗口打开",command=self.open_in_new_window,state=tk.DISABLED)
150
+ self.menu.add_command(label="新窗口打开",command=self.open_in_new_window,
151
+ state=tk.DISABLED)
152
152
  self.menu.add_command(label="新增属性",command=self.new_item,state=tk.DISABLED)
153
153
  self.menu.add_command(label="删除",command=self.del_item,state=tk.DISABLED)
154
154
  def on_rightclick(event):
@@ -214,7 +214,7 @@ class ObjectBrowser():
214
214
  return self.classes_tag
215
215
  else:return self.attributes_tag
216
216
  def refresh(self,event=None,_first=False): # _first: 是否为初次加载
217
- "更新自身显示的数据。"
217
+ # 更新自身显示的数据
218
218
  obj=self.obj
219
219
  self.master.title("{} - {}".format(self.title,objectname(obj)))
220
220
  self.label["text"]=" 路径: %s 对象: %s" % (self.name, _shortrepr(obj))
@@ -223,15 +223,19 @@ class ObjectBrowser():
223
223
  self.tvw.item(self.functions_tag,open=True)
224
224
  # 添加属性
225
225
  attrs=dir(obj)
226
+ if isinstance(obj,type):
227
+ for attr in TYPE_EXTRA_ATTRS:
228
+ if hasattr(obj,attr):
229
+ attrs.append(attr) # 对类添加额外的,一般不会出现在dir()的返回值的属性
226
230
  for i in range(len(attrs)):
227
231
  attr=attrs[i]
228
232
  if self.verbose or not attr.startswith("_"):
229
233
  try:
230
- object=getattr(obj,attr)
231
- value=_shortrepr(object,self.MAX_VIEW_LEN)
232
- image=self._get_image(object)
233
- tags=("gray",) if isinstance(object,SKIP) else () # 将部分类型设为灰色,如MethodWrapperType
234
- self.tvw.insert(self._get_type(object), tk.END, #attr,
234
+ object_=getattr(obj,attr)
235
+ value=_shortrepr(object_,self.MAX_VIEW_LEN)
236
+ image=self._get_image(object_)
237
+ tags=("gray",) if isinstance(object_,SKIP) else () # 将部分类型设为灰色,如MethodWrapperType
238
+ self.tvw.insert(self._get_type(object_), tk.END, #attr,
235
239
  text=attr, image=image,
236
240
  values=(value,),tags=tags) # values从第二列开始
237
241
  except Exception as error: # 显示错误消息
@@ -239,20 +243,30 @@ class ObjectBrowser():
239
243
  self.tvw.insert(self.attributes_tag, tk.END,
240
244
  text=attr, image=self.obj_image,
241
245
  values=(value,),tags=("error",))
242
- # __bases__属性一般不会出现在dir()的返回值中
243
- if hasattr(obj,"__bases__") and "__bases__" not in attrs:
244
- bases=obj.__bases__
245
- self.tvw.insert(self.classes_tag, tk.END, "__bases__",
246
- text="__bases__", image=self._get_image(bases),
247
- values=(repr(bases),))
246
+ # 添加类特有的属性 (不会在dir()出现)
247
+ if isinstance(obj,type):
248
+ for attr in TYPE_EXTRA_CLASS_ATTRS:
249
+ if not hasattr(obj,attr):continue
250
+ try:
251
+ object_=getattr(obj,attr)
252
+ value=_shortrepr(object_,self.MAX_VIEW_LEN)
253
+ self.tvw.insert(self.classes_tag, tk.END,
254
+ text=attr, image=self._get_image(object_),
255
+ values=(value,))
256
+ except Exception as error: # 显示错误
257
+ value='<{}: {}>'.format(type(error).__name__,str(error))
258
+ self.tvw.insert(self.classes_tag, tk.END,
259
+ text=attr, image=self.obj_image,
260
+ values=(value,),tags=("error",))
261
+
248
262
  # 添加列表数据
249
263
  if isinstance(obj,(list,tuple)):
250
264
  for i in range(len(obj)):
251
265
  index=str(i)
252
266
  try:
253
- object=obj[i]
254
- value=_shortrepr(object,self.MAX_VIEW_LEN)
255
- image=self._get_image(object)
267
+ object_=obj[i]
268
+ value=_shortrepr(object_,self.MAX_VIEW_LEN)
269
+ image=self._get_image(object_)
256
270
  self.tvw.insert(self.lst_tag, tk.END,
257
271
  text=index, image=image,
258
272
  values=(value,))
@@ -267,9 +281,9 @@ class ObjectBrowser():
267
281
  for key in obj.keys():
268
282
  key_name=repr(key)
269
283
  try:
270
- object=obj[key]
271
- value=_shortrepr(object,self.MAX_VIEW_LEN)
272
- image=self._get_image(object)
284
+ object_=obj[key]
285
+ value=_shortrepr(object_,self.MAX_VIEW_LEN)
286
+ image=self._get_image(object_)
273
287
  self.tvw.insert(self.dict_tag, tk.END,
274
288
  text=key_name, image=image,
275
289
  values=(value,))
@@ -420,11 +434,11 @@ class ObjectBrowser():
420
434
  try:
421
435
  # 对象的属性可能有改变,重新获取对象的属性
422
436
  scope={self.rootobj_name:self.root_obj} # 获取第一个浏览的根对象及其名称
423
- object=eval(path,scope)
437
+ object_=eval(path,scope)
424
438
  except Exception: # 默认使用新获取的对象,只有出错时,才使用旧的对象
425
- object=obj
426
- else:object=obj
427
- self.browse(object,path)
439
+ object_=obj
440
+ else:object_=obj
441
+ self.browse(object_,path)
428
442
  def back(self): # 后退
429
443
  if self.history_index!=0:
430
444
  self.history_index-=1