appmap 2.0.9__tar.gz → 2.1.0__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 (167) hide show
  1. {appmap-2.0.9 → appmap-2.1.0}/PKG-INFO +1 -1
  2. {appmap-2.0.9 → appmap-2.1.0}/_appmap/event.py +12 -2
  3. {appmap-2.0.9 → appmap-2.1.0}/_appmap/importer.py +42 -13
  4. appmap-2.1.0/_appmap/test/data/django/test/test_unittest_setup.py +11 -0
  5. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/example_class.py +47 -0
  6. appmap-2.0.9/_appmap/test/data/pytest/expected/pytest.appmap.json → appmap-2.1.0/_appmap/test/data/pytest/expected/pytest-numpy1.appmap.json +113 -51
  7. appmap-2.1.0/_appmap/test/data/pytest/expected/pytest-numpy2.appmap.json +242 -0
  8. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/pytest/expected/status_errored.metadata.json +1 -1
  9. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/pytest/expected/status_failed.metadata.json +1 -1
  10. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/pytest/expected/status_xfailed.metadata.json +1 -1
  11. appmap-2.1.0/_appmap/test/data/pytest/simple.py +19 -0
  12. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/pytest/test_simple.py +4 -2
  13. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/test_django.py +6 -4
  14. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/test_params.py +1 -1
  15. appmap-2.1.0/_appmap/test/test_properties.py +105 -0
  16. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/test_test_frameworks.py +14 -7
  17. {appmap-2.0.9 → appmap-2.1.0}/_appmap/unittest.py +12 -0
  18. {appmap-2.0.9 → appmap-2.1.0}/_appmap/utils.py +4 -0
  19. {appmap-2.0.9 → appmap-2.1.0}/pyproject.toml +1 -1
  20. appmap-2.0.9/_appmap/test/data/pytest/simple.py +0 -18
  21. {appmap-2.0.9 → appmap-2.1.0}/LICENSE +0 -0
  22. {appmap-2.0.9 → appmap-2.1.0}/README.md +0 -0
  23. {appmap-2.0.9 → appmap-2.1.0}/_appmap/__init__.py +0 -0
  24. {appmap-2.0.9 → appmap-2.1.0}/_appmap/configuration.py +0 -0
  25. {appmap-2.0.9 → appmap-2.1.0}/_appmap/django.py +0 -0
  26. {appmap-2.0.9 → appmap-2.1.0}/_appmap/env.py +0 -0
  27. {appmap-2.0.9 → appmap-2.1.0}/_appmap/fastapi.py +0 -0
  28. {appmap-2.0.9 → appmap-2.1.0}/_appmap/flask.py +0 -0
  29. {appmap-2.0.9 → appmap-2.1.0}/_appmap/generation.py +0 -0
  30. {appmap-2.0.9 → appmap-2.1.0}/_appmap/instrument.py +0 -0
  31. {appmap-2.0.9 → appmap-2.1.0}/_appmap/labels.py +0 -0
  32. {appmap-2.0.9 → appmap-2.1.0}/_appmap/metadata.py +0 -0
  33. {appmap-2.0.9 → appmap-2.1.0}/_appmap/noappmap.py +0 -0
  34. {appmap-2.0.9 → appmap-2.1.0}/_appmap/py_version_check.py +0 -0
  35. {appmap-2.0.9 → appmap-2.1.0}/_appmap/recorder.py +0 -0
  36. {appmap-2.0.9 → appmap-2.1.0}/_appmap/recording.py +0 -0
  37. {appmap-2.0.9 → appmap-2.1.0}/_appmap/remote_recording.py +0 -0
  38. {appmap-2.0.9 → appmap-2.1.0}/_appmap/singleton.py +0 -0
  39. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/__init__.py +0 -0
  40. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/appmap_test_base.py +0 -0
  41. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/bin/server_runner +0 -0
  42. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/conftest.py +0 -0
  43. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/appmap-all-paths-malformed.yml +0 -0
  44. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/appmap-broken.yml +0 -0
  45. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/appmap-class.yml +0 -0
  46. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/appmap-empty-path.yml +0 -0
  47. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/appmap-exclude-fn.yml +0 -0
  48. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/appmap-func.yml +0 -0
  49. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/appmap-malformed-path.yml +0 -0
  50. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/appmap-no-pyyaml.yml +0 -0
  51. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/appmap.yml +0 -0
  52. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/appmap_testing/__init__.py +0 -0
  53. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/appmap_testing/django_simplelazyobject.py +0 -0
  54. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/config/src/package/__init__.py +0 -0
  55. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/config/test/__init__.py +0 -0
  56. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/config/test/foo.py +0 -0
  57. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/config-exclude/.hide/hidden_mod/__init__.py +0 -0
  58. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/config-exclude/node_modules/node_mod/__init__.py +0 -0
  59. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/config-exclude/src/package/__init__.py +0 -0
  60. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/config-exclude/test/__init__.py +0 -0
  61. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/config-exclude/venv/venv_mod/__init__.py +0 -0
  62. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/config-up/appmap.yml +0 -0
  63. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/config-up/project/p1/__init__.py +0 -0
  64. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/config-up/project/p2/sub1/__init__.py +0 -0
  65. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/django/appmap.yml +0 -0
  66. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/django/djangoapp/__init__.py +0 -0
  67. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/django/djangoapp/djangoapp.py +0 -0
  68. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/django/djangoapp/hello_world.html +0 -0
  69. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/django/djangoapp/middleware.py +0 -0
  70. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/django/djangoapp/settings.py +0 -0
  71. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/django/djangoapp/settings_dev.py +0 -0
  72. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/django/djangoapp/urls.py +0 -0
  73. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/django/init/sitecustomize.py +0 -0
  74. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/django/manage.py +0 -0
  75. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/django/pytest.ini +0 -0
  76. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/django/test/__init__.py +0 -0
  77. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/django/test/test_app.py +0 -0
  78. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/expected.appmap.json +0 -0
  79. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/fastapi/appmap.yml +0 -0
  80. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/fastapi/fastapiapp/__init__.py +0 -0
  81. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/fastapi/fastapiapp/main.py +0 -0
  82. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/fastapi/init/sitecustomize.py +0 -0
  83. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/fastapi/test_app.py +0 -0
  84. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/flask/appmap.yml +0 -0
  85. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/flask/flaskapp.py +0 -0
  86. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/flask/init/sitecustomize.py +0 -0
  87. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/flask/templates/test.html +0 -0
  88. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/flask/test_app.py +0 -0
  89. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/package1/__init__.py +0 -0
  90. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/package1/package2/__init__.py +0 -0
  91. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/package1/package2/__main__.py +0 -0
  92. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/package1/package2/mod1.py +0 -0
  93. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/params.py +0 -0
  94. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/pytest/appmap.yml +0 -0
  95. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/pytest/test_noappmap.py +0 -0
  96. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/remote.appmap.json +0 -0
  97. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/trial/.gitignore +0 -0
  98. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/trial/appmap.yml +0 -0
  99. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/trial/expected/pytest.appmap.json +0 -0
  100. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/trial/init/sitecustomize.py +0 -0
  101. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/trial/test/__init__.py +0 -0
  102. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/trial/test/test_deferred.py +0 -0
  103. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/unittest/appmap.yml +0 -0
  104. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/unittest/expected/pytest.appmap.json +0 -0
  105. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/unittest/expected/status_errored.metadata.json +0 -0
  106. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/unittest/expected/status_failed.metadata.json +0 -0
  107. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/unittest/expected/status_xfailed.metadata.json +0 -0
  108. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/unittest/expected/status_xsucceeded.metadata.json +0 -0
  109. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/unittest/expected/unittest.appmap.json +0 -0
  110. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/unittest/init/sitecustomize.py +0 -0
  111. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/unittest/simple/__init__.py +0 -0
  112. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/unittest/simple/test_noappmap.py +0 -0
  113. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/data/unittest/simple/test_simple.py +0 -0
  114. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/helpers.py +0 -0
  115. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/normalize.py +0 -0
  116. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/test_command.py +0 -0
  117. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/test_configuration.py +0 -0
  118. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/test_describe_value.py +0 -0
  119. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/test_django_simplelazyobject.py +0 -0
  120. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/test_env.py +0 -0
  121. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/test_events.py +0 -0
  122. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/test_fastapi.py +0 -0
  123. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/test_flask.py +0 -0
  124. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/test_generation.py +0 -0
  125. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/test_http.py +0 -0
  126. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/test_importer.py +0 -0
  127. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/test_labels.py +0 -0
  128. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/test_metadata.py +0 -0
  129. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/test_recording.py +0 -0
  130. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/test_runner.py +0 -0
  131. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/test_sqlalchemy.py +0 -0
  132. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/test_util.py +0 -0
  133. {appmap-2.0.9 → appmap-2.1.0}/_appmap/test/web_framework.py +0 -0
  134. {appmap-2.0.9 → appmap-2.1.0}/_appmap/testing_framework.py +0 -0
  135. {appmap-2.0.9 → appmap-2.1.0}/_appmap/trace_logger.py +0 -0
  136. {appmap-2.0.9 → appmap-2.1.0}/_appmap/web_framework.py +0 -0
  137. {appmap-2.0.9 → appmap-2.1.0}/appmap/__init__.py +0 -0
  138. {appmap-2.0.9 → appmap-2.1.0}/appmap/command/__init__.py +0 -0
  139. {appmap-2.0.9 → appmap-2.1.0}/appmap/command/appmap_agent_init.py +0 -0
  140. {appmap-2.0.9 → appmap-2.1.0}/appmap/command/appmap_agent_status.py +0 -0
  141. {appmap-2.0.9 → appmap-2.1.0}/appmap/command/appmap_agent_validate.py +0 -0
  142. {appmap-2.0.9 → appmap-2.1.0}/appmap/command/runner.py +0 -0
  143. {appmap-2.0.9 → appmap-2.1.0}/appmap/django.py +0 -0
  144. {appmap-2.0.9 → appmap-2.1.0}/appmap/fastapi.py +0 -0
  145. {appmap-2.0.9 → appmap-2.1.0}/appmap/flask.py +0 -0
  146. {appmap-2.0.9 → appmap-2.1.0}/appmap/http.py +0 -0
  147. {appmap-2.0.9 → appmap-2.1.0}/appmap/labeling/__init__.py +0 -0
  148. {appmap-2.0.9 → appmap-2.1.0}/appmap/labeling/crypto.yml +0 -0
  149. {appmap-2.0.9 → appmap-2.1.0}/appmap/labeling/django.yml +0 -0
  150. {appmap-2.0.9 → appmap-2.1.0}/appmap/labeling/flask.yml +0 -0
  151. {appmap-2.0.9 → appmap-2.1.0}/appmap/labeling/formats.yml +0 -0
  152. {appmap-2.0.9 → appmap-2.1.0}/appmap/labeling/http.yml +0 -0
  153. {appmap-2.0.9 → appmap-2.1.0}/appmap/labeling/jobs.yml +0 -0
  154. {appmap-2.0.9 → appmap-2.1.0}/appmap/labeling/jwt.yml +0 -0
  155. {appmap-2.0.9 → appmap-2.1.0}/appmap/labeling/logger.yml +0 -0
  156. {appmap-2.0.9 → appmap-2.1.0}/appmap/labeling/random.yml +0 -0
  157. {appmap-2.0.9 → appmap-2.1.0}/appmap/pytest.py +0 -0
  158. {appmap-2.0.9 → appmap-2.1.0}/appmap/sqlalchemy.py +0 -0
  159. {appmap-2.0.9 → appmap-2.1.0}/appmap/unittest.py +0 -0
  160. {appmap-2.0.9 → appmap-2.1.0}/appmap/uvicorn.py +0 -0
  161. {appmap-2.0.9 → appmap-2.1.0}/appmap.pth +0 -0
  162. {appmap-2.0.9 → appmap-2.1.0}/vendor/_appmap/wrapt/LICENSE +0 -0
  163. {appmap-2.0.9 → appmap-2.1.0}/vendor/_appmap/wrapt/__init__.py +0 -0
  164. {appmap-2.0.9 → appmap-2.1.0}/vendor/_appmap/wrapt/arguments.py +0 -0
  165. {appmap-2.0.9 → appmap-2.1.0}/vendor/_appmap/wrapt/decorators.py +0 -0
  166. {appmap-2.0.9 → appmap-2.1.0}/vendor/_appmap/wrapt/importer.py +0 -0
  167. {appmap-2.0.9 → appmap-2.1.0}/vendor/_appmap/wrapt/wrappers.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: appmap
3
- Version: 2.0.9
3
+ Version: 2.1.0
4
4
  Summary: Create AppMap files by recording a Python application.
5
5
  Home-page: https://github.com/applandinc/appmap-python
6
6
  License: MIT
@@ -176,7 +176,7 @@ class Param:
176
176
 
177
177
  class CallEvent(Event):
178
178
  # pylint: disable=method-cache-max-size-none
179
- __slots__ = ["_fn", "_fqfn", "static", "receiver", "parameters", "labels"]
179
+ __slots__ = ["_fn", "_fqfn", "static", "receiver", "parameters", "labels", "auxtype"]
180
180
 
181
181
  @staticmethod
182
182
  def make(fn, fntype):
@@ -283,7 +283,10 @@ class CallEvent(Event):
283
283
  @property
284
284
  @lru_cache(maxsize=None)
285
285
  def method_id(self):
286
- return self._fqfn.fqfn[1]
286
+ ret = self._fqfn.fqfn[1]
287
+ if self.auxtype is not None:
288
+ ret = f"{ret} ({self.auxtype})"
289
+ return ret
287
290
 
288
291
  @property
289
292
  @lru_cache(maxsize=None)
@@ -319,6 +322,13 @@ class CallEvent(Event):
319
322
  parameters = parameters[1:]
320
323
  self.parameters = parameters
321
324
  self.labels = labels
325
+ self.auxtype = None
326
+ if fntype & FnType.GET:
327
+ self.auxtype = "get"
328
+ elif fntype & FnType.SET:
329
+ self.auxtype = "set"
330
+ elif fntype & FnType.DEL:
331
+ self.auxtype = "del"
322
332
 
323
333
  def to_dict(self, attrs=None):
324
334
  ret = super().to_dict() # get the attrs defined in __slots__
@@ -37,14 +37,14 @@ class FilterableCls(Filterable):
37
37
  class FilterableFn(
38
38
  namedtuple(
39
39
  "FilterableFn",
40
- Filterable._fields + ("static_fn",),
40
+ Filterable._fields + ("static_fn", "auxtype"),
41
41
  )
42
42
  ):
43
43
  __slots__ = ()
44
44
 
45
- def __new__(cls, scope, fn, static_fn):
45
+ def __new__(cls, scope, fn, static_fn, auxtype=None):
46
46
  fqname = "%s.%s" % (scope.fqname, fn.__name__)
47
- self = super(FilterableFn, cls).__new__(cls, scope.scope, fqname, fn, static_fn)
47
+ self = super(FilterableFn, cls).__new__(cls, scope.scope, fqname, fn, static_fn, auxtype)
48
48
  return self
49
49
 
50
50
  @property
@@ -52,7 +52,10 @@ class FilterableFn(
52
52
  if self.scope == Scope.MODULE:
53
53
  return FnType.MODULE
54
54
 
55
- return FnType.classify(self.static_fn)
55
+ ret = FnType.classify(self.static_fn)
56
+ if self.auxtype is not None:
57
+ ret |= self.auxtype
58
+ return ret
56
59
 
57
60
 
58
61
  class Filter(ABC): # pylint: disable=too-few-public-methods
@@ -122,19 +125,31 @@ def get_members(cls):
122
125
  # instead iterate over dir(cls), we would see functions from
123
126
  # superclasses, too. Those don't need to be instrumented here,
124
127
  # they'll get taken care of when the superclass is imported.
125
- ret = []
128
+ functions = []
129
+ properties = {}
126
130
  modname = cls.__module__ if hasattr(cls, "__module__") else cls.__name__
127
131
  for key in cls.__dict__:
128
132
  if key.startswith("__"):
129
133
  continue
130
134
  static_value = inspect.getattr_static(cls, key)
131
- if not is_member_func(static_value):
132
- continue
133
- value = getattr(cls, key)
134
- if value.__module__ != modname:
135
- continue
136
- ret.append((key, static_value, value))
137
- return ret
135
+ if isinstance(static_value, property):
136
+ properties[key] = (
137
+ static_value,
138
+ {
139
+ "fget": (static_value.fget, FnType.GET),
140
+ "fset": (static_value.fset, FnType.SET),
141
+ "fdel": (static_value.fdel, FnType.DEL),
142
+ },
143
+ )
144
+ else:
145
+ if not is_member_func(static_value):
146
+ continue
147
+ value = getattr(cls, key)
148
+ if value.__module__ != modname:
149
+ continue
150
+ functions.append((key, static_value, value))
151
+
152
+ return (functions, properties)
138
153
 
139
154
 
140
155
  class Importer:
@@ -177,7 +192,7 @@ class Importer:
177
192
 
178
193
  def instrument_functions(filterable, selected_functions=None):
179
194
  logger.trace(" looking for members of %s", filterable.obj)
180
- functions = get_members(filterable.obj)
195
+ functions, properties = get_members(filterable.obj)
181
196
  logger.trace(" functions %s", functions)
182
197
 
183
198
  for fn_name, static_fn, fn in functions:
@@ -185,6 +200,20 @@ class Importer:
185
200
  new_fn = cls.instrument_function(fn_name, filterableFn, selected_functions)
186
201
  if new_fn != fn:
187
202
  wrapt.wrap_function_wrapper(filterable.obj, fn_name, new_fn)
203
+ # Now that we've instrumented all the functions, go through the properties and update
204
+ # them
205
+ for prop_name, (prop, prop_fns) in properties.items():
206
+ instrumented_fns = {}
207
+ for k, (fn, auxtype) in prop_fns.items():
208
+ if fn is None:
209
+ continue
210
+ filterableFn = FilterableFn(filterable, fn, fn, auxtype)
211
+ new_fn = cls.instrument_function(fn.__name__, filterableFn, selected_functions)
212
+ if new_fn != fn:
213
+ new_fn = wrapt.FunctionWrapper(fn, new_fn)
214
+ instrumented_fns[k] = new_fn
215
+ instrumented_fns["doc"] = prop.__doc__
216
+ setattr(filterable.obj, prop_name, property(**instrumented_fns))
188
217
 
189
218
  # Import Config here, to avoid circular top-level imports.
190
219
  from .configuration import Config # pylint: disable=import-outside-toplevel
@@ -0,0 +1,11 @@
1
+
2
+ from unittest import TestCase
3
+
4
+ from django.test import Client
5
+
6
+ class DisabledRequestsRecordingTest(TestCase):
7
+ def setUp(self) -> None:
8
+ Client().get("/")
9
+
10
+ def test_request_in_setup(self):
11
+ pass
@@ -113,6 +113,53 @@ class ExampleClass(Super, ClassMethodMixin):
113
113
  def return_self(self):
114
114
  return self
115
115
 
116
+ def __init__(self):
117
+ self._read_only = "read only"
118
+ self._fully_accessible = "fully accessible"
119
+ self._undecorated = "undecorated"
120
+
121
+ @property
122
+ def read_only(self):
123
+ """Read-only"""
124
+ return self._read_only
125
+
126
+ @property
127
+ def fully_accessible(self):
128
+ """Fully-accessible"""
129
+ return self._fully_accessible
130
+
131
+ @fully_accessible.setter
132
+ def fully_accessible(self, v):
133
+ self._fully_accessible = v
134
+
135
+ @fully_accessible.deleter
136
+ def fully_accessible(self):
137
+ del self._fully_accessible
138
+
139
+ def get_undecorated(self):
140
+ return self._undecorated
141
+
142
+ def set_undecorated(self, value):
143
+ self._undecorated = value
144
+
145
+ def delete_undecorated(self):
146
+ del self._undecorated
147
+
148
+ undecorated_property = property(get_undecorated, set_undecorated, delete_undecorated)
149
+
150
+ def set_write_only(self, v):
151
+ self._write_only = v
152
+
153
+ def del_write_only(self):
154
+ del self._write_only
155
+
156
+ write_only = property(None, set_write_only, del_write_only, "Write-only")
157
+
116
158
 
117
159
  def modfunc():
118
160
  return "Hello world!"
161
+
162
+ if __name__ == "__main__":
163
+ ec = ExampleClass()
164
+ ec.fully_accessible = "updated"
165
+ print(ec.fully_accessible)
@@ -8,75 +8,95 @@
8
8
  "name": "appmap",
9
9
  "url": "https://github.com/applandinc/appmap-python"
10
10
  },
11
- "source_location": "test_simple.py:5",
12
- "name": "hello world",
13
- "feature": "Hello world",
14
11
  "app": "Simple",
15
12
  "recorder": {
16
13
  "name": "pytest",
17
14
  "type": "tests"
18
15
  },
16
+ "source_location": "test_simple.py:5",
17
+ "name": "hello world",
18
+ "feature": "Hello world",
19
19
  "test_status": "succeeded"
20
20
  },
21
21
  "events": [
22
22
  {
23
+ "defined_class": "simple.Simple",
24
+ "method_id": "hello_world",
25
+ "path": "simple.py",
26
+ "lineno": 8,
23
27
  "static": false,
24
28
  "receiver": {
29
+ "class": "simple.Simple",
25
30
  "kind": "req",
26
- "value": "<simple.Simple object at 0xabcdef>",
27
31
  "name": "self",
28
- "class": "simple.Simple"
32
+ "value": "<simple.Simple object at 0xabcdef>"
29
33
  },
30
34
  "parameters": [],
31
35
  "id": 1,
32
36
  "event": "call",
33
- "thread_id": 1,
34
- "defined_class": "simple.Simple",
35
- "method_id": "hello_world",
36
- "path": "simple.py",
37
- "lineno": 16
37
+ "thread_id": 1
38
38
  },
39
39
  {
40
+ "defined_class": "simple.Simple",
41
+ "method_id": "hello",
42
+ "path": "simple.py",
43
+ "lineno": 2,
40
44
  "static": false,
41
45
  "receiver": {
46
+ "class": "simple.Simple",
42
47
  "kind": "req",
43
- "value": "<simple.Simple object at 0xabcdef>",
44
48
  "name": "self",
45
- "class": "simple.Simple"
49
+ "value": "<simple.Simple object at 0xabcdef>"
46
50
  },
47
51
  "parameters": [],
48
52
  "id": 2,
49
53
  "event": "call",
50
- "thread_id": 1,
51
- "defined_class": "simple.Simple",
52
- "method_id": "get_non_json_serializable",
53
- "path": "simple.py",
54
- "lineno": 13
54
+ "thread_id": 1
55
55
  },
56
56
  {
57
+ "return_value": {
58
+ "class": "builtins.str",
59
+ "value": "'Hello'"
60
+ },
61
+ "parent_id": 2,
62
+ "id": 3,
63
+ "event": "return",
64
+ "thread_id": 1
65
+ },
66
+ {
67
+ "defined_class": "simple.Simple",
68
+ "method_id": "world",
69
+ "path": "simple.py",
70
+ "lineno": 5,
57
71
  "static": false,
58
72
  "receiver": {
73
+ "class": "simple.Simple",
59
74
  "kind": "req",
60
- "value": "<simple.Simple object at 0xabcdef>",
61
75
  "name": "self",
62
- "class": "simple.Simple"
76
+ "value": "<simple.Simple object at 0xabcdef>"
63
77
  },
64
78
  "parameters": [],
65
- "id": 3,
79
+ "id": 4,
66
80
  "event": "call",
67
- "thread_id": 1,
68
- "defined_class": "simple.Simple",
69
- "method_id": "hello",
70
- "path": "simple.py",
71
- "lineno": 7
81
+ "thread_id": 1
72
82
  },
73
83
  {
74
84
  "return_value": {
75
- "value": "'Hello'",
76
- "class": "builtins.str"
85
+ "class": "builtins.str",
86
+ "value": "'world!'"
77
87
  },
78
- "parent_id": 3,
79
- "id": 4,
88
+ "parent_id": 4,
89
+ "id": 5,
90
+ "event": "return",
91
+ "thread_id": 1
92
+ },
93
+ {
94
+ "return_value": {
95
+ "class": "builtins.str",
96
+ "value": "'Hello world!'"
97
+ },
98
+ "parent_id": 1,
99
+ "id": 6,
80
100
  "event": "return",
81
101
  "thread_id": 1
82
102
  },
@@ -89,27 +109,52 @@
89
109
  "class": "simple.Simple"
90
110
  },
91
111
  "parameters": [],
92
- "id": 5,
112
+ "id": 7,
93
113
  "event": "call",
94
114
  "thread_id": 1,
95
115
  "defined_class": "simple.Simple",
96
- "method_id": "world",
116
+ "method_id": "show_numpy_dict",
97
117
  "path": "simple.py",
98
- "lineno": 10
118
+ "lineno": 11
99
119
  },
100
120
  {
101
- "return_value": {
102
- "value": "'world!'",
103
- "class": "builtins.str"
121
+ "static": false,
122
+ "receiver": {
123
+ "kind": "req",
124
+ "value": "<simple.Simple object at 0xabcdef>",
125
+ "name": "self",
126
+ "class": "simple.Simple"
104
127
  },
105
- "parent_id": 5,
106
- "id": 6,
107
- "event": "return",
108
- "thread_id": 1
128
+ "parameters": [
129
+ {
130
+ "kind": "req",
131
+ "value": "{0: 'zero', 1: 'one'}",
132
+ "name": "d",
133
+ "class": "builtins.dict",
134
+ "properties": [
135
+ {
136
+ "name": "0",
137
+ "class": "builtins.str"
138
+ },
139
+ {
140
+ "name": "1",
141
+ "class": "builtins.str"
142
+ }
143
+ ],
144
+ "size": 2
145
+ }
146
+ ],
147
+ "id": 8,
148
+ "event": "call",
149
+ "thread_id": 1,
150
+ "defined_class": "simple.Simple",
151
+ "method_id": "get_numpy_dict",
152
+ "path": "simple.py",
153
+ "lineno": 18
109
154
  },
110
155
  {
111
156
  "return_value": {
112
- "value": "{0: 'Hello', 1: 'world!'}",
157
+ "value": "{0: 'zero', 1: 'one'}",
113
158
  "class": "builtins.dict",
114
159
  "properties": [
115
160
  {
@@ -123,18 +168,29 @@
123
168
  ],
124
169
  "size": 2
125
170
  },
126
- "parent_id": 2,
127
- "id": 7,
171
+ "parent_id": 8,
172
+ "id": 9,
128
173
  "event": "return",
129
174
  "thread_id": 1
130
175
  },
131
176
  {
132
177
  "return_value": {
133
- "value": "'Hello world!'",
134
- "class": "builtins.str"
178
+ "value": "{0: 'zero', 1: 'one'}",
179
+ "class": "builtins.dict",
180
+ "properties": [
181
+ {
182
+ "name": "0",
183
+ "class": "builtins.str"
184
+ },
185
+ {
186
+ "name": "1",
187
+ "class": "builtins.str"
188
+ }
189
+ ],
190
+ "size": 2
135
191
  },
136
- "parent_id": 1,
137
- "id": 8,
192
+ "parent_id": 7,
193
+ "id": 10,
138
194
  "event": "return",
139
195
  "thread_id": 1
140
196
  }
@@ -149,27 +205,33 @@
149
205
  "type": "class",
150
206
  "children": [
151
207
  {
152
- "name": "get_non_json_serializable",
208
+ "name": "get_numpy_dict",
153
209
  "type": "function",
154
- "location": "simple.py:13",
210
+ "location": "simple.py:18",
155
211
  "static": false
156
212
  },
157
213
  {
158
214
  "name": "hello",
159
215
  "type": "function",
160
- "location": "simple.py:7",
216
+ "location": "simple.py:2",
161
217
  "static": false
162
218
  },
163
219
  {
164
220
  "name": "hello_world",
165
221
  "type": "function",
166
- "location": "simple.py:16",
222
+ "location": "simple.py:8",
223
+ "static": false
224
+ },
225
+ {
226
+ "name": "show_numpy_dict",
227
+ "type": "function",
228
+ "location": "simple.py:11",
167
229
  "static": false
168
230
  },
169
231
  {
170
232
  "name": "world",
171
233
  "type": "function",
172
- "location": "simple.py:10",
234
+ "location": "simple.py:5",
173
235
  "static": false
174
236
  }
175
237
  ]