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.
- appmap-2.2.0/.gitignore +26 -0
- appmap-2.2.0/PKG-INFO +223 -0
- {appmap-2.1.9 → appmap-2.2.0}/README.md +44 -42
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/env.py +14 -2
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/event.py +24 -18
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/instrument.py +15 -4
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/example_class.py +4 -0
- appmap-2.2.0/_appmap/test/data/pytest/expected/status_xsucceeded.metadata.json +1 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/test_describe_value.py +19 -5
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/test_events.py +56 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/test_params.py +3 -1
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/web_framework.py +1 -1
- {appmap-2.1.9 → appmap-2.2.0}/appmap/__init__.py +2 -2
- appmap-2.2.0/pyproject.toml +139 -0
- appmap-2.2.0/vendor/_appmap/wrapt/LICENSE +24 -0
- appmap-2.2.0/vendor/_appmap/wrapt/__init__.py +27 -0
- appmap-2.2.0/vendor/_appmap/wrapt/arguments.py +38 -0
- appmap-2.2.0/vendor/_appmap/wrapt/decorators.py +541 -0
- appmap-2.2.0/vendor/_appmap/wrapt/importer.py +293 -0
- appmap-2.2.0/vendor/_appmap/wrapt/wrappers.py +1100 -0
- appmap-2.2.0/vendor/patches/wrapt.patch +297 -0
- appmap-2.2.0/vendor/vendor.txt +1 -0
- appmap-2.1.9/PKG-INFO +0 -167
- appmap-2.1.9/pyproject.toml +0 -126
- {appmap-2.1.9 → appmap-2.2.0}/LICENSE +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/__init__.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/configuration.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/django.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/fastapi.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/flask.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/generation.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/importer.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/labels.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/metadata.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/noappmap.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/py_version_check.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/recorder.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/recording.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/remote_recording.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/singleton.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/__init__.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/appmap_test_base.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/bin/server_runner +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/conftest.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/appmap-all-paths-malformed.yml +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/appmap-broken.yml +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/appmap-class.yml +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/appmap-empty-path.yml +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/appmap-exclude-fn.yml +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/appmap-func.yml +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/appmap-malformed-path.yml +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/appmap-no-pyyaml.yml +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/appmap.yml +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/appmap_testing/__init__.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/appmap_testing/django_simplelazyobject.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/config/src/package/__init__.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/config/test/__init__.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/config/test/foo.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/config-exclude/.hide/hidden_mod/__init__.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/config-exclude/node_modules/node_mod/__init__.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/config-exclude/src/package/__init__.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/config-exclude/test/__init__.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/config-exclude/venv/venv_mod/__init__.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/config-up/appmap.yml +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/config-up/project/p1/__init__.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/config-up/project/p2/sub1/__init__.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/django/appmap.yml +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/django/djangoapp/__init__.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/django/djangoapp/djangoapp.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/django/djangoapp/hello_world.html +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/django/djangoapp/middleware.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/django/djangoapp/settings.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/django/djangoapp/settings_dev.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/django/djangoapp/urls.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/django/init/sitecustomize.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/django/manage.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/django/pytest.ini +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/django/test/__init__.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/django/test/test_app.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/django/test/test_request.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/django/test/test_unittest_setup.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/expected.appmap.json +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/fastapi/appmap.yml +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/fastapi/fastapiapp/__init__.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/fastapi/fastapiapp/main.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/fastapi/init/sitecustomize.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/fastapi/test_app.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/flask/appmap.yml +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/flask/flaskapp.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/flask/init/sitecustomize.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/flask/templates/test.html +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/flask/test_app.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/flask-instrumented/appmap.yml +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/flask-instrumented/flaskapp.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/flask-instrumented/init/sitecustomize.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/flask-instrumented/test_app.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/package1/__init__.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/package1/package2/__init__.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/package1/package2/__main__.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/package1/package2/mod1.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/params.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/properties_class.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/pytest/appmap-no-test-cases.yml +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/pytest/appmap.yml +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/pytest/expected/pytest-numpy1-no-test-cases.appmap.json +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/pytest/expected/pytest-numpy1.appmap.json +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/pytest/expected/pytest-numpy2-no-test-cases.appmap.json +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/pytest/expected/pytest-numpy2.appmap.json +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/pytest/expected/status_errored.metadata.json +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/pytest/expected/status_failed.metadata.json +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/pytest/expected/status_xfailed.metadata.json +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/pytest/simple.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/pytest/tests/__init__.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/pytest/tests/test_noappmap.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/pytest/tests/test_simple.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/pytest-instrumented/appmap.yml +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/pytest-instrumented/init/sitecustomize.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/pytest-instrumented/test_instrumented.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/remote.appmap.json +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/trial/.gitignore +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/trial/appmap-no-test-cases.yml +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/trial/appmap.yml +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/trial/expected/pytest-no-test-cases.appmap.json +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/trial/expected/pytest.appmap.json +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/trial/init/sitecustomize.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/trial/test/__init__.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/trial/test/test_deferred.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/unittest/appmap-no-test-cases.yml +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/unittest/appmap.yml +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/unittest/expected/pytest.appmap.json +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/unittest/expected/status_errored.metadata.json +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/unittest/expected/status_failed.metadata.json +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/unittest/expected/status_xfailed.metadata.json +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/unittest/expected/status_xsucceeded.metadata.json +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/unittest/expected/unittest-no-test-cases.appmap.json +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/unittest/expected/unittest.appmap.json +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/unittest/init/sitecustomize.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/unittest/simple/__init__.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/unittest/simple/test_noappmap.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/data/unittest/simple/test_simple.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/helpers.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/normalize.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/test_command.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/test_configuration.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/test_django.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/test_django_simplelazyobject.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/test_env.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/test_fastapi.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/test_flask.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/test_generation.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/test_http.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/test_importer.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/test_labels.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/test_metadata.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/test_properties.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/test_recording.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/test_runner.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/test_sqlalchemy.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/test_test_frameworks.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/test_util.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/test/web_framework.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/testing_framework.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/trace_logger.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/unittest.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/_appmap/utils.py +0 -0
- {appmap-2.1.9/vendor → appmap-2.2.0}/_appmap/wrapt/LICENSE +0 -0
- {appmap-2.1.9/vendor → appmap-2.2.0}/_appmap/wrapt/__init__.py +0 -0
- {appmap-2.1.9/vendor → appmap-2.2.0}/_appmap/wrapt/arguments.py +0 -0
- {appmap-2.1.9/vendor → appmap-2.2.0}/_appmap/wrapt/decorators.py +0 -0
- {appmap-2.1.9/vendor → appmap-2.2.0}/_appmap/wrapt/importer.py +0 -0
- {appmap-2.1.9/vendor → appmap-2.2.0}/_appmap/wrapt/wrappers.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/appmap/command/__init__.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/appmap/command/appmap_agent_init.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/appmap/command/appmap_agent_status.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/appmap/command/appmap_agent_validate.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/appmap/command/runner.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/appmap/django.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/appmap/fastapi.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/appmap/flask.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/appmap/http.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/appmap/labeling/__init__.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/appmap/labeling/crypto.yml +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/appmap/labeling/django.yml +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/appmap/labeling/flask.yml +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/appmap/labeling/formats.yml +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/appmap/labeling/http.yml +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/appmap/labeling/jobs.yml +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/appmap/labeling/jwt.yml +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/appmap/labeling/logger.yml +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/appmap/labeling/random.yml +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/appmap/pytest.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/appmap/sqlalchemy.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/appmap/unittest.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/appmap/uvicorn.py +0 -0
- {appmap-2.1.9 → appmap-2.2.0}/appmap.pth +0 -0
appmap-2.2.0/.gitignore
ADDED
|
@@ -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
|
+
[](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
|
-
[
|
|
53
|
+
[uv](https://docs.astral.sh/uv/) is used for dependency management and provides fast package installation:
|
|
54
54
|
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
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 `
|
|
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
|
-
|
|
74
|
-
|
|
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
|
-
|
|
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
|
-
|
|
94
|
-
|
|
92
|
+
```bash
|
|
93
|
+
cd appmap-python
|
|
95
94
|
|
|
96
|
-
|
|
95
|
+
# Run all tests
|
|
96
|
+
APPMAP_DISPLAY_PARAMS=true uv run appmap-python pytest
|
|
97
97
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
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
|
-
|
|
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
|
-
`
|
|
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
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
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
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
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",
|
|
49
|
-
|
|
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
|
|
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 = [
|
|
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(
|
|
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": [
|