appmap 2.1.9__tar.gz → 2.2.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 (195) hide show
  1. appmap-2.2.0/.gitignore +26 -0
  2. appmap-2.2.0/PKG-INFO +223 -0
  3. {appmap-2.1.9 → appmap-2.2.0}/README.md +44 -42
  4. {appmap-2.1.9 → appmap-2.2.0}/_appmap/env.py +14 -2
  5. {appmap-2.1.9 → appmap-2.2.0}/_appmap/event.py +24 -18
  6. {appmap-2.1.9 → appmap-2.2.0}/_appmap/instrument.py +15 -4
  7. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/example_class.py +4 -0
  8. appmap-2.2.0/_appmap/test/data/pytest/expected/status_xsucceeded.metadata.json +1 -0
  9. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/test_describe_value.py +19 -5
  10. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/test_events.py +56 -0
  11. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/test_params.py +3 -1
  12. {appmap-2.1.9 → appmap-2.2.0}/_appmap/web_framework.py +1 -1
  13. {appmap-2.1.9 → appmap-2.2.0}/appmap/__init__.py +2 -2
  14. appmap-2.2.0/pyproject.toml +139 -0
  15. appmap-2.2.0/vendor/_appmap/wrapt/LICENSE +24 -0
  16. appmap-2.2.0/vendor/_appmap/wrapt/__init__.py +27 -0
  17. appmap-2.2.0/vendor/_appmap/wrapt/arguments.py +38 -0
  18. appmap-2.2.0/vendor/_appmap/wrapt/decorators.py +541 -0
  19. appmap-2.2.0/vendor/_appmap/wrapt/importer.py +293 -0
  20. appmap-2.2.0/vendor/_appmap/wrapt/wrappers.py +1100 -0
  21. appmap-2.2.0/vendor/patches/wrapt.patch +297 -0
  22. appmap-2.2.0/vendor/vendor.txt +1 -0
  23. appmap-2.1.9/PKG-INFO +0 -167
  24. appmap-2.1.9/pyproject.toml +0 -126
  25. {appmap-2.1.9 → appmap-2.2.0}/LICENSE +0 -0
  26. {appmap-2.1.9 → appmap-2.2.0}/_appmap/__init__.py +0 -0
  27. {appmap-2.1.9 → appmap-2.2.0}/_appmap/configuration.py +0 -0
  28. {appmap-2.1.9 → appmap-2.2.0}/_appmap/django.py +0 -0
  29. {appmap-2.1.9 → appmap-2.2.0}/_appmap/fastapi.py +0 -0
  30. {appmap-2.1.9 → appmap-2.2.0}/_appmap/flask.py +0 -0
  31. {appmap-2.1.9 → appmap-2.2.0}/_appmap/generation.py +0 -0
  32. {appmap-2.1.9 → appmap-2.2.0}/_appmap/importer.py +0 -0
  33. {appmap-2.1.9 → appmap-2.2.0}/_appmap/labels.py +0 -0
  34. {appmap-2.1.9 → appmap-2.2.0}/_appmap/metadata.py +0 -0
  35. {appmap-2.1.9 → appmap-2.2.0}/_appmap/noappmap.py +0 -0
  36. {appmap-2.1.9 → appmap-2.2.0}/_appmap/py_version_check.py +0 -0
  37. {appmap-2.1.9 → appmap-2.2.0}/_appmap/recorder.py +0 -0
  38. {appmap-2.1.9 → appmap-2.2.0}/_appmap/recording.py +0 -0
  39. {appmap-2.1.9 → appmap-2.2.0}/_appmap/remote_recording.py +0 -0
  40. {appmap-2.1.9 → appmap-2.2.0}/_appmap/singleton.py +0 -0
  41. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/__init__.py +0 -0
  42. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/appmap_test_base.py +0 -0
  43. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/bin/server_runner +0 -0
  44. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/conftest.py +0 -0
  45. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/appmap-all-paths-malformed.yml +0 -0
  46. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/appmap-broken.yml +0 -0
  47. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/appmap-class.yml +0 -0
  48. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/appmap-empty-path.yml +0 -0
  49. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/appmap-exclude-fn.yml +0 -0
  50. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/appmap-func.yml +0 -0
  51. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/appmap-malformed-path.yml +0 -0
  52. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/appmap-no-pyyaml.yml +0 -0
  53. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/appmap.yml +0 -0
  54. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/appmap_testing/__init__.py +0 -0
  55. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/appmap_testing/django_simplelazyobject.py +0 -0
  56. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/config/src/package/__init__.py +0 -0
  57. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/config/test/__init__.py +0 -0
  58. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/config/test/foo.py +0 -0
  59. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/config-exclude/.hide/hidden_mod/__init__.py +0 -0
  60. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/config-exclude/node_modules/node_mod/__init__.py +0 -0
  61. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/config-exclude/src/package/__init__.py +0 -0
  62. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/config-exclude/test/__init__.py +0 -0
  63. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/config-exclude/venv/venv_mod/__init__.py +0 -0
  64. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/config-up/appmap.yml +0 -0
  65. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/config-up/project/p1/__init__.py +0 -0
  66. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/config-up/project/p2/sub1/__init__.py +0 -0
  67. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/django/appmap.yml +0 -0
  68. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/django/djangoapp/__init__.py +0 -0
  69. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/django/djangoapp/djangoapp.py +0 -0
  70. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/django/djangoapp/hello_world.html +0 -0
  71. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/django/djangoapp/middleware.py +0 -0
  72. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/django/djangoapp/settings.py +0 -0
  73. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/django/djangoapp/settings_dev.py +0 -0
  74. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/django/djangoapp/urls.py +0 -0
  75. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/django/init/sitecustomize.py +0 -0
  76. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/django/manage.py +0 -0
  77. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/django/pytest.ini +0 -0
  78. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/django/test/__init__.py +0 -0
  79. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/django/test/test_app.py +0 -0
  80. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/django/test/test_request.py +0 -0
  81. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/django/test/test_unittest_setup.py +0 -0
  82. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/expected.appmap.json +0 -0
  83. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/fastapi/appmap.yml +0 -0
  84. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/fastapi/fastapiapp/__init__.py +0 -0
  85. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/fastapi/fastapiapp/main.py +0 -0
  86. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/fastapi/init/sitecustomize.py +0 -0
  87. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/fastapi/test_app.py +0 -0
  88. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/flask/appmap.yml +0 -0
  89. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/flask/flaskapp.py +0 -0
  90. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/flask/init/sitecustomize.py +0 -0
  91. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/flask/templates/test.html +0 -0
  92. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/flask/test_app.py +0 -0
  93. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/flask-instrumented/appmap.yml +0 -0
  94. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/flask-instrumented/flaskapp.py +0 -0
  95. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/flask-instrumented/init/sitecustomize.py +0 -0
  96. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/flask-instrumented/test_app.py +0 -0
  97. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/package1/__init__.py +0 -0
  98. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/package1/package2/__init__.py +0 -0
  99. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/package1/package2/__main__.py +0 -0
  100. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/package1/package2/mod1.py +0 -0
  101. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/params.py +0 -0
  102. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/properties_class.py +0 -0
  103. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/pytest/appmap-no-test-cases.yml +0 -0
  104. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/pytest/appmap.yml +0 -0
  105. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/pytest/expected/pytest-numpy1-no-test-cases.appmap.json +0 -0
  106. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/pytest/expected/pytest-numpy1.appmap.json +0 -0
  107. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/pytest/expected/pytest-numpy2-no-test-cases.appmap.json +0 -0
  108. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/pytest/expected/pytest-numpy2.appmap.json +0 -0
  109. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/pytest/expected/status_errored.metadata.json +0 -0
  110. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/pytest/expected/status_failed.metadata.json +0 -0
  111. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/pytest/expected/status_xfailed.metadata.json +0 -0
  112. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/pytest/simple.py +0 -0
  113. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/pytest/tests/__init__.py +0 -0
  114. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/pytest/tests/test_noappmap.py +0 -0
  115. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/pytest/tests/test_simple.py +0 -0
  116. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/pytest-instrumented/appmap.yml +0 -0
  117. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/pytest-instrumented/init/sitecustomize.py +0 -0
  118. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/pytest-instrumented/test_instrumented.py +0 -0
  119. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/remote.appmap.json +0 -0
  120. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/trial/.gitignore +0 -0
  121. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/trial/appmap-no-test-cases.yml +0 -0
  122. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/trial/appmap.yml +0 -0
  123. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/trial/expected/pytest-no-test-cases.appmap.json +0 -0
  124. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/trial/expected/pytest.appmap.json +0 -0
  125. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/trial/init/sitecustomize.py +0 -0
  126. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/trial/test/__init__.py +0 -0
  127. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/trial/test/test_deferred.py +0 -0
  128. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/unittest/appmap-no-test-cases.yml +0 -0
  129. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/unittest/appmap.yml +0 -0
  130. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/unittest/expected/pytest.appmap.json +0 -0
  131. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/unittest/expected/status_errored.metadata.json +0 -0
  132. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/unittest/expected/status_failed.metadata.json +0 -0
  133. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/unittest/expected/status_xfailed.metadata.json +0 -0
  134. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/unittest/expected/status_xsucceeded.metadata.json +0 -0
  135. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/unittest/expected/unittest-no-test-cases.appmap.json +0 -0
  136. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/unittest/expected/unittest.appmap.json +0 -0
  137. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/unittest/init/sitecustomize.py +0 -0
  138. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/unittest/simple/__init__.py +0 -0
  139. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/unittest/simple/test_noappmap.py +0 -0
  140. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/unittest/simple/test_simple.py +0 -0
  141. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/helpers.py +0 -0
  142. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/normalize.py +0 -0
  143. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/test_command.py +0 -0
  144. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/test_configuration.py +0 -0
  145. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/test_django.py +0 -0
  146. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/test_django_simplelazyobject.py +0 -0
  147. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/test_env.py +0 -0
  148. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/test_fastapi.py +0 -0
  149. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/test_flask.py +0 -0
  150. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/test_generation.py +0 -0
  151. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/test_http.py +0 -0
  152. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/test_importer.py +0 -0
  153. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/test_labels.py +0 -0
  154. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/test_metadata.py +0 -0
  155. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/test_properties.py +0 -0
  156. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/test_recording.py +0 -0
  157. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/test_runner.py +0 -0
  158. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/test_sqlalchemy.py +0 -0
  159. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/test_test_frameworks.py +0 -0
  160. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/test_util.py +0 -0
  161. {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/web_framework.py +0 -0
  162. {appmap-2.1.9 → appmap-2.2.0}/_appmap/testing_framework.py +0 -0
  163. {appmap-2.1.9 → appmap-2.2.0}/_appmap/trace_logger.py +0 -0
  164. {appmap-2.1.9 → appmap-2.2.0}/_appmap/unittest.py +0 -0
  165. {appmap-2.1.9 → appmap-2.2.0}/_appmap/utils.py +0 -0
  166. {appmap-2.1.9/vendor → appmap-2.2.0}/_appmap/wrapt/LICENSE +0 -0
  167. {appmap-2.1.9/vendor → appmap-2.2.0}/_appmap/wrapt/__init__.py +0 -0
  168. {appmap-2.1.9/vendor → appmap-2.2.0}/_appmap/wrapt/arguments.py +0 -0
  169. {appmap-2.1.9/vendor → appmap-2.2.0}/_appmap/wrapt/decorators.py +0 -0
  170. {appmap-2.1.9/vendor → appmap-2.2.0}/_appmap/wrapt/importer.py +0 -0
  171. {appmap-2.1.9/vendor → appmap-2.2.0}/_appmap/wrapt/wrappers.py +0 -0
  172. {appmap-2.1.9 → appmap-2.2.0}/appmap/command/__init__.py +0 -0
  173. {appmap-2.1.9 → appmap-2.2.0}/appmap/command/appmap_agent_init.py +0 -0
  174. {appmap-2.1.9 → appmap-2.2.0}/appmap/command/appmap_agent_status.py +0 -0
  175. {appmap-2.1.9 → appmap-2.2.0}/appmap/command/appmap_agent_validate.py +0 -0
  176. {appmap-2.1.9 → appmap-2.2.0}/appmap/command/runner.py +0 -0
  177. {appmap-2.1.9 → appmap-2.2.0}/appmap/django.py +0 -0
  178. {appmap-2.1.9 → appmap-2.2.0}/appmap/fastapi.py +0 -0
  179. {appmap-2.1.9 → appmap-2.2.0}/appmap/flask.py +0 -0
  180. {appmap-2.1.9 → appmap-2.2.0}/appmap/http.py +0 -0
  181. {appmap-2.1.9 → appmap-2.2.0}/appmap/labeling/__init__.py +0 -0
  182. {appmap-2.1.9 → appmap-2.2.0}/appmap/labeling/crypto.yml +0 -0
  183. {appmap-2.1.9 → appmap-2.2.0}/appmap/labeling/django.yml +0 -0
  184. {appmap-2.1.9 → appmap-2.2.0}/appmap/labeling/flask.yml +0 -0
  185. {appmap-2.1.9 → appmap-2.2.0}/appmap/labeling/formats.yml +0 -0
  186. {appmap-2.1.9 → appmap-2.2.0}/appmap/labeling/http.yml +0 -0
  187. {appmap-2.1.9 → appmap-2.2.0}/appmap/labeling/jobs.yml +0 -0
  188. {appmap-2.1.9 → appmap-2.2.0}/appmap/labeling/jwt.yml +0 -0
  189. {appmap-2.1.9 → appmap-2.2.0}/appmap/labeling/logger.yml +0 -0
  190. {appmap-2.1.9 → appmap-2.2.0}/appmap/labeling/random.yml +0 -0
  191. {appmap-2.1.9 → appmap-2.2.0}/appmap/pytest.py +0 -0
  192. {appmap-2.1.9 → appmap-2.2.0}/appmap/sqlalchemy.py +0 -0
  193. {appmap-2.1.9 → appmap-2.2.0}/appmap/unittest.py +0 -0
  194. {appmap-2.1.9 → appmap-2.2.0}/appmap/uvicorn.py +0 -0
  195. {appmap-2.1.9 → appmap-2.2.0}/appmap.pth +0 -0
@@ -0,0 +1,26 @@
1
+ .envrc
2
+ .tool-versions
3
+
4
+ poetry.lock
5
+ uv.lock
6
+
7
+ __pycache__/
8
+ *.py[cod]
9
+ *$py.class
10
+ *.so
11
+
12
+ .python-version
13
+
14
+ /dist/
15
+ .venv/
16
+
17
+ htmlcov/
18
+
19
+ .vscode/
20
+
21
+ /.tox
22
+ /node_modules
23
+ /ruff.toml
24
+
25
+ appmap.log
26
+ *.sqlite3
appmap-2.2.0/PKG-INFO ADDED
@@ -0,0 +1,223 @@
1
+ Metadata-Version: 2.4
2
+ Name: appmap
3
+ Version: 2.2.0
4
+ Summary: Create AppMap files by recording a Python application.
5
+ Project-URL: Homepage, https://github.com/applandinc/appmap-python
6
+ Author-email: Alan Potter <alan@app.land>, Viraj Kanwade <viraj.kanwade@forgeahead.io>, Rafał Rzepecki <rafal@app.land>
7
+ License: MIT
8
+ License-File: LICENSE
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Framework :: Django
11
+ Classifier: Framework :: Django :: 3.2
12
+ Classifier: Framework :: Flask
13
+ Classifier: Framework :: Pytest
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Topic :: Software Development
17
+ Classifier: Topic :: Software Development :: Debuggers
18
+ Classifier: Topic :: Software Development :: Documentation
19
+ Requires-Python: >=3.8
20
+ Requires-Dist: importlib-resources>=5.4.0
21
+ Requires-Dist: inflection>=0.3.0
22
+ Requires-Dist: packaging>=19.0
23
+ Requires-Dist: pyyaml>=5.3.0
24
+ Provides-Extra: dev
25
+ Requires-Dist: asgiref<4.0,>=3.7.2; extra == 'dev'
26
+ Requires-Dist: black<25.0,>=24.2.0; extra == 'dev'
27
+ Requires-Dist: coverage<6.0,>=5.3; extra == 'dev'
28
+ Requires-Dist: django; extra == 'dev'
29
+ Requires-Dist: fastapi<1.0,>=0.110.0; extra == 'dev'
30
+ Requires-Dist: flake8<4.0,>=3.8.4; extra == 'dev'
31
+ Requires-Dist: flask; extra == 'dev'
32
+ Requires-Dist: httpretty<2.0,>=1.0.5; extra == 'dev'
33
+ Requires-Dist: httpx<1.0,>=0.27.0; extra == 'dev'
34
+ Requires-Dist: incremental<24.7.0; extra == 'dev'
35
+ Requires-Dist: isort<6.0,>=5.10.1; extra == 'dev'
36
+ Requires-Dist: numpy<2.0,>=1.24.4; (python_version < '3.9') and extra == 'dev'
37
+ Requires-Dist: numpy>=2.0; (python_version >= '3.9') and extra == 'dev'
38
+ Requires-Dist: pprintpp<1.0,>=0.4.0; extra == 'dev'
39
+ Requires-Dist: psutil<7.0,>=6.0.0; extra == 'dev'
40
+ Requires-Dist: pyfakefs<6.0,>=5.3.5; extra == 'dev'
41
+ Requires-Dist: pylint<4.0,>=3.0; extra == 'dev'
42
+ Requires-Dist: pytest-console-scripts<2.0,>=1.4.1; extra == 'dev'
43
+ Requires-Dist: pytest-django<5.0,>=4.7; extra == 'dev'
44
+ Requires-Dist: pytest-env<2.0,>=1.1.3; extra == 'dev'
45
+ Requires-Dist: pytest-mock<4.0,>=3.5.1; extra == 'dev'
46
+ Requires-Dist: pytest-randomly<4.0,>=3.5.0; extra == 'dev'
47
+ Requires-Dist: pytest-shell-utilities<2.0,>=1.8.0; extra == 'dev'
48
+ Requires-Dist: pytest-xdist<4.0,>=3.6.1; extra == 'dev'
49
+ Requires-Dist: pytest-xprocess<1.0,>=0.23.0; extra == 'dev'
50
+ Requires-Dist: pytest<8.0,>=7.3.2; extra == 'dev'
51
+ Requires-Dist: python-decouple<4.0,>=3.5; extra == 'dev'
52
+ Requires-Dist: requests<3.0,>=2.25.1; extra == 'dev'
53
+ Requires-Dist: ruff<1.0,>=0.5.3; extra == 'dev'
54
+ Requires-Dist: sqlalchemy; extra == 'dev'
55
+ Requires-Dist: tox-gh-actions<4.0,>=3.0; extra == 'dev'
56
+ Requires-Dist: tox-uv<2.0,>=1.0; extra == 'dev'
57
+ Requires-Dist: tox<5.0,>=4.0; extra == 'dev'
58
+ Requires-Dist: twisted<23.0,>=22.4.0; extra == 'dev'
59
+ Requires-Dist: urllib3<2,>=1; extra == 'dev'
60
+ Requires-Dist: uvicorn<1.0,>=0.27.1; extra == 'dev'
61
+ Provides-Extra: test
62
+ Requires-Dist: asgiref<4.0,>=3.7.2; extra == 'test'
63
+ Requires-Dist: django; extra == 'test'
64
+ Requires-Dist: fastapi<1.0,>=0.110.0; extra == 'test'
65
+ Requires-Dist: flask; extra == 'test'
66
+ Requires-Dist: httpretty<2.0,>=1.0.5; extra == 'test'
67
+ Requires-Dist: httpx<1.0,>=0.27.0; extra == 'test'
68
+ Requires-Dist: incremental<24.7.0; extra == 'test'
69
+ Requires-Dist: numpy<2.0,>=1.24.4; (python_version < '3.9') and extra == 'test'
70
+ Requires-Dist: numpy>=2.0; (python_version >= '3.9') and extra == 'test'
71
+ Requires-Dist: psutil<7.0,>=6.0.0; extra == 'test'
72
+ Requires-Dist: pyfakefs<6.0,>=5.3.5; extra == 'test'
73
+ Requires-Dist: pytest-console-scripts<2.0,>=1.4.1; extra == 'test'
74
+ Requires-Dist: pytest-django<5.0,>=4.7; extra == 'test'
75
+ Requires-Dist: pytest-env<2.0,>=1.1.3; extra == 'test'
76
+ Requires-Dist: pytest-mock<4.0,>=3.5.1; extra == 'test'
77
+ Requires-Dist: pytest-randomly<4.0,>=3.5.0; extra == 'test'
78
+ Requires-Dist: pytest-shell-utilities<2.0,>=1.8.0; extra == 'test'
79
+ Requires-Dist: pytest-xdist<4.0,>=3.6.1; extra == 'test'
80
+ Requires-Dist: pytest-xprocess<1.0,>=0.23.0; extra == 'test'
81
+ Requires-Dist: pytest<8.0,>=7.3.2; extra == 'test'
82
+ Requires-Dist: python-decouple<4.0,>=3.5; extra == 'test'
83
+ Requires-Dist: requests<3.0,>=2.25.1; extra == 'test'
84
+ Requires-Dist: sqlalchemy; extra == 'test'
85
+ Requires-Dist: twisted<23.0,>=22.4.0; extra == 'test'
86
+ Requires-Dist: urllib3<2,>=1; extra == 'test'
87
+ Requires-Dist: uvicorn<1.0,>=0.27.1; extra == 'test'
88
+ Description-Content-Type: text/markdown
89
+
90
+ - [About](#about)
91
+ - [Usage](#usage)
92
+ - [Development](#development)
93
+ - [Getting the code](#getting-the-code)
94
+ - [Python version support](#python-version-support)
95
+ - [Dependency management](#dependency-management)
96
+ - [wrapt](#wrapt)
97
+ - [Linting](#linting)
98
+ - [Testing](#testing)
99
+ - [pytest](#pytest)
100
+ - [tox](#tox)
101
+ - [Code Coverage](#code-coverage)
102
+
103
+ # About
104
+ `appmap-python` is a Python package for recording
105
+ [AppMaps](https://github.com/applandinc/appmap) of your code. "AppMap" is a data format
106
+ which records code structure (modules, classes, and methods), code execution events
107
+ (function calls and returns), and code metadata (repo name, repo URL, commit SHA, labels,
108
+ etc). It's more granular than a performance profile, but it's less granular than a full
109
+ debug trace. It's designed to be optimal for understanding the design intent and structure
110
+ of code and key data flows.
111
+
112
+ # Usage
113
+
114
+ Visit the [AppMap for Python](https://appland.com/docs/reference/appmap-python.html) reference page on AppLand.com for a complete reference guide.
115
+
116
+ # Development
117
+
118
+ [![Build Status](https://travis-ci.com/getappmap/appmap-python.svg?branch=master)](https://travis-ci.com/getappmap/appmap-python)
119
+
120
+ ## Getting the code
121
+ Clone the repo to begin development.
122
+
123
+ ```shell
124
+ % git clone https://github.com/applandinc/appmap-python.git
125
+ Cloning into 'appmap-python'...
126
+ remote: Enumerating objects: 167, done.
127
+ remote: Counting objects: 100% (167/167), done.
128
+ remote: Compressing objects: 100% (100/100), done.
129
+ remote: Total 962 (delta 95), reused 116 (delta 61), pack-reused 795
130
+ Receiving objects: 100% (962/962), 217.31 KiB | 4.62 MiB/s, done.
131
+ Resolving deltas: 100% (653/653), done.
132
+ ```
133
+
134
+ ## Python version support
135
+ As a package intended to be installed in as many environments as possible, `appmap-python`
136
+ needs to avoid using features of Python or the standard library that were added after the
137
+ oldest version currently supported (see the
138
+ [supported versions](https://appland.com/docs/reference/appmap-python.html#supported-versions)).
139
+
140
+ ## Dependency management
141
+
142
+ [uv](https://docs.astral.sh/uv/) is used for dependency management and provides fast package installation:
143
+
144
+ ```bash
145
+ # Install uv (macOS/Linux)
146
+ curl -LsSf https://astral.sh/uv/install.sh | sh
147
+
148
+ # Install dependencies
149
+ cd appmap-python
150
+ uv sync --all-extras
151
+ ```
152
+
153
+ ### wrapt
154
+ The one dependency that is not managed using `uv` is `wrapt`. Because it's possible that
155
+ projects that use `appmap` may also need an unmodified version of `wrapt` (e.g. `pylint` depends on
156
+ `astroid`, which in turn depends on `wrapt`), we use
157
+ [vendoring](https://github.com/pradyunsg/vendoring) to vendor `wrapt`.
158
+
159
+ To update `wrapt`, use `tox` (described below) to run the `vendoring` environment.
160
+
161
+ ## Linting
162
+ [pylint](https://www.pylint.org/) for linting:
163
+
164
+ ```bash
165
+ cd appmap-python
166
+ uv run tox -e lint
167
+
168
+ # Or run pylint directly
169
+ uv run pylint appmap
170
+
171
+ --------------------------------------------------------------------
172
+ Your code has been rated at 10.00/10 (previous run: 10.00/10, +0.00)
173
+ ```
174
+
175
+
176
+ ## Testing
177
+ ### pytest
178
+
179
+ [pytest](https://docs.pytest.org/en/stable/) for testing:
180
+
181
+ ```bash
182
+ cd appmap-python
183
+
184
+ # Run all tests
185
+ APPMAP_DISPLAY_PARAMS=true uv run appmap-python pytest
186
+
187
+ # Run tests with a specific Python version
188
+ APPMAP_DISPLAY_PARAMS=true uv run --python 3.9 appmap-python pytest
189
+
190
+ # Run tests in parallel
191
+ APPMAP_DISPLAY_PARAMS=true uv run appmap-python pytest -n auto
192
+ ```
193
+
194
+ ### tox
195
+ The `tox` configuration provides the ability to run the tests for all supported versions of Python and web frameworks (Django, Flask, SQLAlchemy).
196
+
197
+ With `uv`, you don't need to pre-install Python versions - `uv` will automatically download and manage them:
198
+
199
+ ```bash
200
+ cd appmap-python
201
+
202
+ # Run full test matrix (all Python versions and frameworks)
203
+ uv run tox
204
+
205
+ # Run tests for a specific Python version
206
+ uv run tox -e py312-web
207
+
208
+ # Run tests for specific framework
209
+ uv run tox -e py312-django5
210
+
211
+ # Update vendored wrapt dependency
212
+ uv run tox -e vendoring sync
213
+ ```
214
+
215
+ ## Code Coverage
216
+ [coverage](https://coverage.readthedocs.io/) for coverage:
217
+
218
+ ```bash
219
+ cd appmap-python
220
+ uv run coverage run -m pytest
221
+ uv run coverage html
222
+ open htmlcov/index.html
223
+ ```
@@ -50,16 +50,19 @@ oldest version currently supported (see the
50
50
 
51
51
  ## Dependency management
52
52
 
53
- [poetry](https://https://python-poetry.org/) for dependency management:
53
+ [uv](https://docs.astral.sh/uv/) is used for dependency management and provides fast package installation:
54
54
 
55
- ```
56
- % brew install poetry
57
- % cd appmap-python
58
- % poetry install
55
+ ```bash
56
+ # Install uv (macOS/Linux)
57
+ curl -LsSf https://astral.sh/uv/install.sh | sh
58
+
59
+ # Install dependencies
60
+ cd appmap-python
61
+ uv sync --all-extras
59
62
  ```
60
63
 
61
64
  ### wrapt
62
- The one dependency that is not managed using `poetry` is `wrapt`. Because it's possible that
65
+ The one dependency that is not managed using `uv` is `wrapt`. Because it's possible that
63
66
  projects that use `appmap` may also need an unmodified version of `wrapt` (e.g. `pylint` depends on
64
67
  `astroid`, which in turn depends on `wrapt`), we use
65
68
  [vendoring](https://github.com/pradyunsg/vendoring) to vendor `wrapt`.
@@ -69,64 +72,63 @@ To update `wrapt`, use `tox` (described below) to run the `vendoring` environmen
69
72
  ## Linting
70
73
  [pylint](https://www.pylint.org/) for linting:
71
74
 
72
- ```
73
- % cd appmap-python
74
- % poetry run pylint appmap
75
+ ```bash
76
+ cd appmap-python
77
+ uv run tox -e lint
78
+
79
+ # Or run pylint directly
80
+ uv run pylint appmap
75
81
 
76
82
  --------------------------------------------------------------------
77
83
  Your code has been rated at 10.00/10 (previous run: 10.00/10, +0.00)
78
-
79
84
  ```
80
85
 
81
- [Note that the current configuration has a threshold set which must be met for the Travis build to
82
- pass. To make this easier to achieve, a number of checks have both been disabled. They should be
83
- reenabled as soon as possible.]
84
-
85
86
 
86
87
  ## Testing
87
88
  ### pytest
88
89
 
89
- Note that you must install the dependencies contained in
90
- [requirements-dev.txt](requirements-dev.txt) before running tests. See the explanation in
91
- [pyproject.toml](pyproject.toml) for details.
90
+ [pytest](https://docs.pytest.org/en/stable/) for testing:
92
91
 
93
- Additionally, the tests currently require that you set `APPMAP=true` and
94
- `APPMAP_DISPLAY_PARAMS=true`.
92
+ ```bash
93
+ cd appmap-python
95
94
 
96
- [pytest](https://docs.pytest.org/en/stable/) for testing:
95
+ # Run all tests
96
+ APPMAP_DISPLAY_PARAMS=true uv run appmap-python pytest
97
97
 
98
- ```
99
- % cd appmap-python
100
- % pip install -r requirements-test.txt
101
- % APPMAP=true APPMAP_DISPLAY_PARAMS=true poetry run pytest
98
+ # Run tests with a specific Python version
99
+ APPMAP_DISPLAY_PARAMS=true uv run --python 3.9 appmap-python pytest
100
+
101
+ # Run tests in parallel
102
+ APPMAP_DISPLAY_PARAMS=true uv run appmap-python pytest -n auto
102
103
  ```
103
104
 
104
105
  ### tox
105
- Additionally, the `tox` configuration provides the ability to run the tests for all
106
- supported versions of Python and Django.
106
+ The `tox` configuration provides the ability to run the tests for all supported versions of Python and web frameworks (Django, Flask, SQLAlchemy).
107
107
 
108
- `tox` requires that all the correct versions of Python to be available to create
109
- the test environments. [pyenv](https://github.com/pyenv/pyenv) is an easy way to manage
110
- multiple versions of Python, and the [xxenv-latest
111
- plugin](https://github.com/momo-lab/xxenv-latest) can help get all the latest versions.
108
+ With `uv`, you don't need to pre-install Python versions - `uv` will automatically download and manage them:
112
109
 
110
+ ```bash
111
+ cd appmap-python
113
112
 
113
+ # Run full test matrix (all Python versions and frameworks)
114
+ uv run tox
114
115
 
115
- ```sh
116
- % brew install pyenv
117
- % git clone https://github.com/momo-lab/xxenv-latest.git "$(pyenv root)"/plugins/xxenv-latest
118
- % cd appmap-python
119
- % pyenv latest local 3.{9,6,7,8}
120
- % for v in 3.{9,6,7,8}; do pyenv latest install $v; done
121
- % poetry run tox
116
+ # Run tests for a specific Python version
117
+ uv run tox -e py312-web
118
+
119
+ # Run tests for specific framework
120
+ uv run tox -e py312-django5
121
+
122
+ # Update vendored wrapt dependency
123
+ uv run tox -e vendoring sync
122
124
  ```
123
125
 
124
126
  ## Code Coverage
125
127
  [coverage](https://coverage.readthedocs.io/) for coverage:
126
128
 
127
- ```
128
- % cd appmap-python
129
- % poetry run coverage run -m pytest
130
- % poetry run coverage html
131
- % open htmlcov/index.html
129
+ ```bash
130
+ cd appmap-python
131
+ uv run coverage run -m pytest
132
+ uv run coverage html
133
+ open htmlcov/index.html
132
134
  ```
@@ -45,8 +45,16 @@ class Env(metaclass=SingletonMeta):
45
45
  # them.
46
46
  enabled = self._env.get("_APPMAP", None)
47
47
  self._enabled = enabled is not None and enabled.lower() != "false"
48
- display_params = self._env.get("_APPMAP_DISPLAY_PARAMS", None)
49
- self._display_params = display_params is not None and display_params.lower() != "false"
48
+ display_params = self._env.get("_APPMAP_DISPLAY_PARAMS", "labeled").lower()
49
+ if display_params == "true":
50
+ self._display_params = True
51
+ self._display_labeled_params = True
52
+ elif display_params == "false":
53
+ self._display_params = False
54
+ self._display_labeled_params = False
55
+ else: # "labeled" or "auto" or anything else defaults to labeled
56
+ self._display_params = False
57
+ self._display_labeled_params = True
50
58
 
51
59
  logger = logging.getLogger(__name__)
52
60
  # The user shouldn't set APPMAP_OUTPUT_DIR, but some tests depend on being able to use it.
@@ -134,6 +142,10 @@ class Env(metaclass=SingletonMeta):
134
142
  def display_params(self):
135
143
  return self._display_params
136
144
 
145
+ @property
146
+ def display_labeled_params(self):
147
+ return self._display_labeled_params
148
+
137
149
  def getLogger(self, name) -> trace_logger.TraceLogger:
138
150
  return cast(trace_logger.TraceLogger, logging.getLogger(name))
139
151
 
@@ -45,13 +45,13 @@ class _EventIds:
45
45
  cls._next_thread_id = 0
46
46
 
47
47
 
48
- def display_string(val):
48
+ def display_string(val, display_value=False):
49
49
  # If we're asked to display parameters, make a best-effort attempt
50
50
  # to get a string value for the parameter using repr(). If parameter
51
51
  # display is disabled, or repr() has raised, just formulate a value
52
52
  # from the class and id.
53
53
  value = None
54
- if Env.current.display_params:
54
+ if display_value:
55
55
  try:
56
56
  value = repr(val)
57
57
  except Exception: # pylint: disable=broad-except
@@ -79,7 +79,7 @@ def _is_list_or_dict(val_type):
79
79
  return issubclass(val_type, list), issubclass(val_type, dict)
80
80
 
81
81
 
82
- def _describe_schema(name, val, depth, max_depth):
82
+ def _describe_schema(name, val, depth, max_depth, display_value=False):
83
83
 
84
84
  val_type = type(val)
85
85
 
@@ -88,6 +88,9 @@ def _describe_schema(name, val, depth, max_depth):
88
88
  ret["name"] = name
89
89
  ret["class"] = fqname(val_type)
90
90
 
91
+ if not display_value:
92
+ return ret
93
+
91
94
  islist, isdict = _is_list_or_dict(val_type)
92
95
  if not (islist or isdict) or (depth >= max_depth and isdict):
93
96
  return ret
@@ -100,7 +103,10 @@ def _describe_schema(name, val, depth, max_depth):
100
103
  elts = val.items()
101
104
  schema_key = "properties"
102
105
 
103
- schema = [_describe_schema(k, v, depth + 1, max_depth) for k, v in elts]
106
+ schema = [
107
+ _describe_schema(k, v, depth + 1, max_depth, display_value=display_value)
108
+ for k, v in elts
109
+ ]
104
110
  # schema will be [None] if depth is exceeded, don't use it
105
111
  if any(schema):
106
112
  ret[schema_key] = schema
@@ -108,15 +114,14 @@ def _describe_schema(name, val, depth, max_depth):
108
114
  return ret
109
115
 
110
116
 
111
- def describe_value(name, val, max_depth=5):
112
- ret = {
117
+ def describe_value(name, val, max_depth=5, display_value=False):
118
+ ret = _describe_schema(name, val, 0, max_depth, display_value=display_value)
119
+ ret.update({
113
120
  "object_id": id(val),
114
- "value": display_string(val),
115
- }
116
- if Env.current.display_params:
117
- ret.update(_describe_schema(name, val, 0, max_depth))
121
+ "value": display_string(val, display_value=display_value),
122
+ })
118
123
 
119
- if any(_is_list_or_dict(type(val))):
124
+ if display_value and any(_is_list_or_dict(type(val))):
120
125
  ret["size"] = len(val)
121
126
 
122
127
  return ret
@@ -170,9 +175,9 @@ class Param:
170
175
  def __repr__(self):
171
176
  return "<Param name: %s kind: %s>" % (self.name, self.kind)
172
177
 
173
- def to_dict(self, value):
178
+ def to_dict(self, value, display_value=False):
174
179
  ret = {"kind": self.kind}
175
- ret.update(describe_value(self.name, value))
180
+ ret.update(describe_value(self.name, value, display_value=display_value))
176
181
  return ret
177
182
 
178
183
  def _get_name_parts(filterable):
@@ -247,7 +252,7 @@ class CallEvent(Event):
247
252
  return [Param(p) for p in sig.parameters.values()]
248
253
 
249
254
  @staticmethod
250
- def set_params(params, instance, args, kwargs):
255
+ def set_params(params, instance, args, kwargs, display_value=False):
251
256
  # pylint: disable=too-many-branches
252
257
  # Note that set_params expects args and kwargs as a tuple and
253
258
  # dict, respectively. It operates on them as collections, so
@@ -295,7 +300,7 @@ class CallEvent(Event):
295
300
  # If all the parameter types are handled, this
296
301
  # shouldn't ever happen...
297
302
  raise RuntimeError("Unknown parameter with desc %s" % (repr(p)))
298
- ret.append(p.to_dict(value))
303
+ ret.append(p.to_dict(value, display_value=display_value))
299
304
  return ret
300
305
 
301
306
  @property
@@ -405,8 +410,9 @@ class MessageEvent(Event): # pylint: disable=too-few-public-methods
405
410
 
406
411
  @message_parameters.setter
407
412
  def message_parameters(self, params):
413
+ display_params = Env.current.display_params
408
414
  for name, value in params.items():
409
- message_object = describe_value(name, value)
415
+ message_object = describe_value(name, value, display_value=display_params)
410
416
  self.message.append(message_object)
411
417
 
412
418
 
@@ -497,13 +503,13 @@ class ReturnEvent(Event):
497
503
  class FuncReturnEvent(ReturnEvent):
498
504
  __slots__ = ["return_value"]
499
505
 
500
- def __init__(self, parent_id, elapsed, return_value):
506
+ def __init__(self, parent_id, elapsed, return_value, display_value=False):
501
507
  super().__init__(parent_id, elapsed)
502
508
  # Import here to prevent circular dependency
503
509
  # pylint: disable=import-outside-toplevel
504
510
  from _appmap.instrument import recording_disabled # noqa: F401
505
511
  with recording_disabled():
506
- self.return_value = describe_value(None, return_value)
512
+ self.return_value = describe_value(None, return_value, display_value=display_value)
507
513
 
508
514
 
509
515
  class HttpResponseEvent(ReturnEvent):
@@ -70,7 +70,7 @@ def saved_shallow_rule():
70
70
 
71
71
 
72
72
  _InstrumentedFn = namedtuple(
73
- "_InstrumentedFn", "fn fntype instrumented_fn make_call_event params"
73
+ "_InstrumentedFn", "fn fntype instrumented_fn make_call_event params display_params"
74
74
  )
75
75
 
76
76
 
@@ -84,7 +84,9 @@ def call_instrumented(f, instance, args, kwargs):
84
84
 
85
85
  with recording_disabled():
86
86
  logger.trace("%s args %s kwargs %s", f.fn, args, kwargs)
87
- params = CallEvent.set_params(f.params, instance, args, kwargs)
87
+ params = CallEvent.set_params(
88
+ f.params, instance, args, kwargs, display_value=f.display_params
89
+ )
88
90
  call_event = f.make_call_event(parameters=params)
89
91
  Recorder.add_event(call_event)
90
92
  call_event_id = call_event.id
@@ -95,7 +97,8 @@ def call_instrumented(f, instance, args, kwargs):
95
97
  elapsed_time = time.time() - start_time
96
98
 
97
99
  return_event = event.FuncReturnEvent(
98
- return_value=ret, parent_id=call_event_id, elapsed=elapsed_time
100
+ return_value=ret, parent_id=call_event_id, elapsed=elapsed_time,
101
+ display_value=f.display_params
99
102
  )
100
103
  Recorder.add_event(return_event)
101
104
  return ret
@@ -120,9 +123,16 @@ def instrument(filterable):
120
123
  """return an instrumented function"""
121
124
  logger.debug("hooking %s", filterable.fqname)
122
125
 
126
+ # note this has to happen before CallEvent.make, which clears this attribute
127
+ has_labels = hasattr(filterable.obj, "_appmap_labels")
128
+
123
129
  make_call_event = event.CallEvent.make(filterable)
124
130
  params = CallEvent.make_params(filterable)
125
131
 
132
+ display_params = Env.current.display_params or (
133
+ has_labels and Env.current.display_labeled_params
134
+ )
135
+
126
136
  # django depends on being able to find the cache_clear attribute
127
137
  # on functions. (You can see this by trying to map
128
138
  # https://github.com/chicagopython/chypi.org.) Make sure it gets
@@ -132,7 +142,8 @@ def instrument(filterable):
132
142
  def instrumented_fn(wrapped, instance, args, kwargs):
133
143
  with saved_shallow_rule():
134
144
  f = _InstrumentedFn(
135
- wrapped, filterable.fntype, instrumented_fn, make_call_event, params
145
+ wrapped, filterable.fntype, instrumented_fn, make_call_event, params,
146
+ display_params
136
147
  )
137
148
  return call_instrumented(f, instance, args, kwargs)
138
149
 
@@ -56,6 +56,10 @@ class ExampleClass(Super, ClassMethodMixin):
56
56
  def labeled_method(self):
57
57
  return "super important"
58
58
 
59
+ @appmap.labels("super", "important")
60
+ def labeled_method_with_param(self, p):
61
+ return p
62
+
59
63
  @staticmethod
60
64
  @wrap_fn
61
65
  def wrapped_static_method():
@@ -0,0 +1 @@
1
+ ../../unittest/expected/status_xsucceeded.metadata.json
@@ -24,7 +24,7 @@ class TestDictValue:
24
24
  return {"id": 1, "contents": "some text"}
25
25
 
26
26
  def test_one_level_schema(self, value):
27
- actual = describe_value(None, value)
27
+ actual = describe_value(None, value, display_value=True)
28
28
  assert actual == DictIncluding(
29
29
  {
30
30
  "properties": [
@@ -34,6 +34,13 @@ class TestDictValue:
34
34
  }
35
35
  )
36
36
 
37
+ def test_one_level_schema_display_false(self, value):
38
+ actual = describe_value(None, value, display_value=False)
39
+ assert "properties" not in actual
40
+ assert actual["class"] == "builtins.dict"
41
+ assert "builtins.dict object at" in actual["value"]
42
+ assert actual["object_id"] == id(value)
43
+
37
44
 
38
45
  class TestNestedDictValue:
39
46
  @pytest.fixture
@@ -41,7 +48,7 @@ class TestNestedDictValue:
41
48
  return {"page": {"page_number": 1, "page_size": 20, "total": 2383}}
42
49
 
43
50
  def test_two_level_schema(self, value):
44
- actual = describe_value(None, value)
51
+ actual = describe_value(None, value, display_value=True)
45
52
  assert actual == DictIncluding(
46
53
  {
47
54
  "properties": [
@@ -60,7 +67,7 @@ class TestNestedDictValue:
60
67
 
61
68
  def test_respects_max_depth(self, value):
62
69
  expected = {"properties": [{"name": "page", "class": "builtins.dict"}]}
63
- actual = describe_value(None, value, max_depth=1)
70
+ actual = describe_value(None, value, max_depth=1, display_value=True)
64
71
  assert actual == DictIncluding(expected)
65
72
 
66
73
 
@@ -70,7 +77,7 @@ class TestListOfDicts:
70
77
  return [{"id": 1, "contents": "some text"}, {"id": 2}]
71
78
 
72
79
  def test_an_array_containing_schema(self, value):
73
- actual = describe_value(None, value)
80
+ actual = describe_value(None, value, display_value=True)
74
81
  assert actual["class"] == "builtins.list"
75
82
  assert actual["items"][0] == DictIncluding(
76
83
  {
@@ -88,6 +95,13 @@ class TestListOfDicts:
88
95
  }
89
96
  )
90
97
 
98
+ def test_an_array_display_false(self, value):
99
+ actual = describe_value(None, value, display_value=False)
100
+ assert "items" not in actual
101
+ assert actual["class"] == "builtins.list"
102
+ assert "builtins.list object at" in actual["value"]
103
+ assert actual["object_id"] == id(value)
104
+
91
105
 
92
106
  class TestNestedArrays:
93
107
  @pytest.fixture
@@ -95,7 +109,7 @@ class TestNestedArrays:
95
109
  return [[["one"]]]
96
110
 
97
111
  def test_arrays_ignore_max_depth(self, value):
98
- actual = describe_value(None, value, max_depth=1)
112
+ actual = describe_value(None, value, max_depth=1, display_value=True)
99
113
  expected = {
100
114
  "class": "builtins.list",
101
115
  "items": [