appmap 3.0.1__tar.gz → 4.0.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-3.0.1 → appmap-4.0.0}/PKG-INFO +16 -8
- {appmap-3.0.1 → appmap-4.0.0}/README.md +1 -1
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/__init__.py +1 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/configuration.py +3 -6
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/event.py +20 -13
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/importer.py +31 -21
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/py_version_check.py +1 -1
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/params.py +7 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/test_command.py +3 -3
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/test_params.py +158 -4
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/test_properties.py +1 -2
- {appmap-3.0.1 → appmap-4.0.0}/appmap/command/runner.py +6 -23
- {appmap-3.0.1 → appmap-4.0.0}/pyproject.toml +13 -4
- {appmap-3.0.1 → appmap-4.0.0}/.gitignore +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/LICENSE +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/django.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/env.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/fastapi.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/flask.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/generation.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/instrument.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/labels.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/metadata.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/noappmap.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/recorder.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/recording.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/remote_recording.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/singleton.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/__init__.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/appmap_test_base.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/bin/server_runner +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/conftest.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/appmap-all-paths-malformed.yml +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/appmap-broken.yml +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/appmap-class.yml +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/appmap-empty-path.yml +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/appmap-exclude-fn.yml +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/appmap-func.yml +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/appmap-malformed-path.yml +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/appmap-no-pyyaml.yml +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/appmap.yml +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/appmap_testing/__init__.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/appmap_testing/django_simplelazyobject.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/config/src/package/__init__.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/config/test/__init__.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/config/test/foo.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/config-exclude/.hide/hidden_mod/__init__.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/config-exclude/node_modules/node_mod/__init__.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/config-exclude/src/package/__init__.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/config-exclude/test/__init__.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/config-exclude/venv/venv_mod/__init__.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/config-up/appmap.yml +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/config-up/project/p1/__init__.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/config-up/project/p2/sub1/__init__.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/django/appmap.yml +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/django/djangoapp/__init__.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/django/djangoapp/djangoapp.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/django/djangoapp/hello_world.html +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/django/djangoapp/middleware.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/django/djangoapp/settings.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/django/djangoapp/settings_dev.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/django/djangoapp/urls.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/django/init/sitecustomize.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/django/manage.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/django/pytest.ini +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/django/test/__init__.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/django/test/test_app.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/django/test/test_request.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/django/test/test_unittest_setup.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/example_class.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/expected.appmap.json +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/fastapi/appmap.yml +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/fastapi/fastapiapp/__init__.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/fastapi/fastapiapp/main.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/fastapi/init/sitecustomize.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/fastapi/test_app.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/flask/appmap.yml +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/flask/flaskapp.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/flask/init/sitecustomize.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/flask/templates/test.html +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/flask/test_app.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/flask-instrumented/appmap.yml +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/flask-instrumented/flaskapp.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/flask-instrumented/init/sitecustomize.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/flask-instrumented/test_app.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/package1/__init__.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/package1/package2/__init__.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/package1/package2/__main__.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/package1/package2/mod1.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/properties_class.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/pytest/appmap-no-test-cases.yml +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/pytest/appmap.yml +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/pytest/expected/pytest-numpy1-no-test-cases.appmap.json +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/pytest/expected/pytest-numpy1.appmap.json +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/pytest/expected/pytest-numpy2-no-test-cases.appmap.json +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/pytest/expected/pytest-numpy2.appmap.json +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/pytest/expected/status_errored.metadata.json +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/pytest/expected/status_failed.metadata.json +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/pytest/expected/status_xfailed.metadata.json +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/pytest/expected/status_xsucceeded.metadata.json +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/pytest/simple.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/pytest/tests/__init__.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/pytest/tests/test_noappmap.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/pytest/tests/test_simple.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/pytest-instrumented/appmap.yml +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/pytest-instrumented/init/sitecustomize.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/pytest-instrumented/test_instrumented.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/remote.appmap.json +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/trial/.gitignore +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/trial/appmap-no-test-cases.yml +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/trial/appmap.yml +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/trial/expected/pytest-no-test-cases.appmap.json +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/trial/expected/pytest.appmap.json +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/trial/init/sitecustomize.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/trial/test/__init__.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/trial/test/test_deferred.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/unittest/appmap-no-test-cases.yml +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/unittest/appmap.yml +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/unittest/expected/pytest.appmap.json +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/unittest/expected/status_errored.metadata.json +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/unittest/expected/status_failed.metadata.json +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/unittest/expected/status_xfailed.metadata.json +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/unittest/expected/status_xsucceeded.metadata.json +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/unittest/expected/unittest-no-test-cases.appmap.json +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/unittest/expected/unittest.appmap.json +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/unittest/init/sitecustomize.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/unittest/simple/__init__.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/unittest/simple/test_noappmap.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/data/unittest/simple/test_simple.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/helpers.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/normalize.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/test_configuration.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/test_describe_value.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/test_django.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/test_django_simplelazyobject.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/test_env.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/test_events.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/test_fastapi.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/test_flask.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/test_generation.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/test_http.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/test_importer.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/test_labels.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/test_metadata.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/test_recording.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/test_runner.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/test_sqlalchemy.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/test_test_frameworks.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/test_util.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/test/web_framework.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/testing_framework.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/trace_logger.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/unittest.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/utils.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/web_framework.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/wrapt/LICENSE +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/wrapt/__init__.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/wrapt/arguments.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/wrapt/decorators.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/wrapt/importer.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/_appmap/wrapt/wrappers.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/appmap/__init__.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/appmap/command/__init__.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/appmap/command/appmap_agent_init.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/appmap/command/appmap_agent_status.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/appmap/command/appmap_agent_validate.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/appmap/django.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/appmap/fastapi.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/appmap/flask.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/appmap/http.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/appmap/labeling/__init__.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/appmap/labeling/crypto.yml +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/appmap/labeling/django.yml +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/appmap/labeling/flask.yml +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/appmap/labeling/formats.yml +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/appmap/labeling/http.yml +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/appmap/labeling/jobs.yml +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/appmap/labeling/jwt.yml +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/appmap/labeling/logger.yml +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/appmap/labeling/random.yml +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/appmap/pytest.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/appmap/sqlalchemy.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/appmap/unittest.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/appmap/uvicorn.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/appmap.pth +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/vendor/_appmap/wrapt/LICENSE +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/vendor/_appmap/wrapt/__init__.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/vendor/_appmap/wrapt/arguments.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/vendor/_appmap/wrapt/decorators.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/vendor/_appmap/wrapt/importer.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/vendor/_appmap/wrapt/wrappers.py +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/vendor/patches/wrapt.patch +0 -0
- {appmap-3.0.1 → appmap-4.0.0}/vendor/vendor.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: appmap
|
|
3
|
-
Version:
|
|
3
|
+
Version: 4.0.0
|
|
4
4
|
Summary: Create AppMap files by recording a Python application.
|
|
5
5
|
Project-URL: Homepage, https://github.com/applandinc/appmap-python
|
|
6
6
|
Author-email: Alan Potter <alan@app.land>, Viraj Kanwade <viraj.kanwade@forgeahead.io>, Rafał Rzepecki <rafal@app.land>
|
|
@@ -9,14 +9,24 @@ License-File: LICENSE
|
|
|
9
9
|
Classifier: Development Status :: 4 - Beta
|
|
10
10
|
Classifier: Framework :: Django
|
|
11
11
|
Classifier: Framework :: Django :: 3.2
|
|
12
|
+
Classifier: Framework :: Django :: 4.2
|
|
13
|
+
Classifier: Framework :: Django :: 5.2
|
|
14
|
+
Classifier: Framework :: Django :: 6.0
|
|
12
15
|
Classifier: Framework :: Flask
|
|
13
16
|
Classifier: Framework :: Pytest
|
|
14
17
|
Classifier: Intended Audience :: Developers
|
|
15
18
|
Classifier: License :: OSI Approved :: MIT License
|
|
19
|
+
Classifier: Programming Language :: Python :: 3
|
|
20
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
16
26
|
Classifier: Topic :: Software Development
|
|
17
27
|
Classifier: Topic :: Software Development :: Debuggers
|
|
18
28
|
Classifier: Topic :: Software Development :: Documentation
|
|
19
|
-
Requires-Python: >=3.
|
|
29
|
+
Requires-Python: >=3.11
|
|
20
30
|
Requires-Dist: importlib-resources>=5.4.0
|
|
21
31
|
Requires-Dist: inflection>=0.3.0
|
|
22
32
|
Requires-Dist: packaging>=19.0
|
|
@@ -33,8 +43,7 @@ Requires-Dist: httpretty<2.0,>=1.0.5; extra == 'dev'
|
|
|
33
43
|
Requires-Dist: httpx<1.0,>=0.27.0; extra == 'dev'
|
|
34
44
|
Requires-Dist: incremental<24.7.0; extra == 'dev'
|
|
35
45
|
Requires-Dist: isort<6.0,>=5.10.1; extra == 'dev'
|
|
36
|
-
Requires-Dist: numpy
|
|
37
|
-
Requires-Dist: numpy>=2.0; (python_version >= '3.9') and extra == 'dev'
|
|
46
|
+
Requires-Dist: numpy>=2.0; extra == 'dev'
|
|
38
47
|
Requires-Dist: pprintpp<1.0,>=0.4.0; extra == 'dev'
|
|
39
48
|
Requires-Dist: psutil<7.0,>=6.0.0; extra == 'dev'
|
|
40
49
|
Requires-Dist: pyfakefs<6.0,>=5.3.5; extra == 'dev'
|
|
@@ -66,8 +75,7 @@ Requires-Dist: flask; extra == 'test'
|
|
|
66
75
|
Requires-Dist: httpretty<2.0,>=1.0.5; extra == 'test'
|
|
67
76
|
Requires-Dist: httpx<1.0,>=0.27.0; extra == 'test'
|
|
68
77
|
Requires-Dist: incremental<24.7.0; extra == 'test'
|
|
69
|
-
Requires-Dist: numpy
|
|
70
|
-
Requires-Dist: numpy>=2.0; (python_version >= '3.9') and extra == 'test'
|
|
78
|
+
Requires-Dist: numpy>=2.0; extra == 'test'
|
|
71
79
|
Requires-Dist: psutil<7.0,>=6.0.0; extra == 'test'
|
|
72
80
|
Requires-Dist: pyfakefs<6.0,>=5.3.5; extra == 'test'
|
|
73
81
|
Requires-Dist: pytest-console-scripts<2.0,>=1.4.1; extra == 'test'
|
|
@@ -185,7 +193,7 @@ cd appmap-python
|
|
|
185
193
|
APPMAP_DISPLAY_PARAMS=true uv run appmap-python pytest
|
|
186
194
|
|
|
187
195
|
# Run tests with a specific Python version
|
|
188
|
-
APPMAP_DISPLAY_PARAMS=true uv run --python 3.
|
|
196
|
+
APPMAP_DISPLAY_PARAMS=true uv run --python 3.11 appmap-python pytest
|
|
189
197
|
|
|
190
198
|
# Run tests in parallel
|
|
191
199
|
APPMAP_DISPLAY_PARAMS=true uv run appmap-python pytest -n auto
|
|
@@ -96,7 +96,7 @@ cd appmap-python
|
|
|
96
96
|
APPMAP_DISPLAY_PARAMS=true uv run appmap-python pytest
|
|
97
97
|
|
|
98
98
|
# Run tests with a specific Python version
|
|
99
|
-
APPMAP_DISPLAY_PARAMS=true uv run --python 3.
|
|
99
|
+
APPMAP_DISPLAY_PARAMS=true uv run --python 3.11 appmap-python pytest
|
|
100
100
|
|
|
101
101
|
# Run tests in parallel
|
|
102
102
|
APPMAP_DISPLAY_PARAMS=true uv run appmap-python pytest -n auto
|
|
@@ -12,6 +12,7 @@ def initialize(**kwargs):
|
|
|
12
12
|
importer.initialize()
|
|
13
13
|
recorder.initialize()
|
|
14
14
|
configuration.initialize() # needs to be initialized after recorder
|
|
15
|
+
importer.install() # needs the filters registered by configuration
|
|
15
16
|
metadata.initialize()
|
|
16
17
|
web_framework.initialize()
|
|
17
18
|
recording.initialize()
|
|
@@ -185,13 +185,10 @@ class Config(metaclass=SingletonMeta):
|
|
|
185
185
|
env = Env.current
|
|
186
186
|
output_dir = env.output_dir
|
|
187
187
|
root_dir = env.root_dir
|
|
188
|
-
|
|
188
|
+
# If output_dir isn't relative to root_dir, APPMAP_OUTPUT_DIR is set, and we've already
|
|
189
|
+
# logged a warning.
|
|
190
|
+
if output_dir.is_relative_to(root_dir):
|
|
189
191
|
ret["appmap_dir"] = str(output_dir.relative_to(root_dir))
|
|
190
|
-
except ValueError:
|
|
191
|
-
# The only way we can get here is if APPMAP_OUTPUT_DIR is set, and we've already logged
|
|
192
|
-
# a warning. (Note that PurePath.is_relative_to wasn't added till 3.9, so it can't be
|
|
193
|
-
# used here.)
|
|
194
|
-
pass
|
|
195
192
|
|
|
196
193
|
return ret
|
|
197
194
|
|
|
@@ -156,10 +156,11 @@ class Event:
|
|
|
156
156
|
|
|
157
157
|
|
|
158
158
|
class Param:
|
|
159
|
-
__slots__ = ["name", "kind", "default", "default_class"]
|
|
159
|
+
__slots__ = ["name", "kind", "positional_only", "default", "default_class"]
|
|
160
160
|
|
|
161
161
|
def __init__(self, sigp):
|
|
162
162
|
self.name = sigp.name
|
|
163
|
+
self.positional_only = sigp.kind == Parameter.POSITIONAL_ONLY
|
|
163
164
|
has_default = sigp.default is not Signature.empty
|
|
164
165
|
if sigp.kind in (Parameter.POSITIONAL_ONLY, Parameter.POSITIONAL_OR_KEYWORD):
|
|
165
166
|
self.kind = "opt" if has_default else "req"
|
|
@@ -275,28 +276,34 @@ class CallEvent(Event):
|
|
|
275
276
|
# we're popping the front repeatedly, lists are better at this
|
|
276
277
|
args = list(args)
|
|
277
278
|
|
|
279
|
+
# Names of keyword arguments bound to named parameters. Python
|
|
280
|
+
# doesn't include them in **kwargs, so neither do we.
|
|
281
|
+
bound = set()
|
|
278
282
|
for p in params:
|
|
279
|
-
if p.kind
|
|
280
|
-
#
|
|
281
|
-
# positional.
|
|
282
|
-
if p.name in kwargs:
|
|
283
|
+
if p.kind in ("req", "opt"):
|
|
284
|
+
# These can be either keyword or positional, unless
|
|
285
|
+
# they're positional-only.
|
|
286
|
+
if not p.positional_only and p.name in kwargs:
|
|
283
287
|
value = kwargs[p.name]
|
|
288
|
+
bound.add(p.name)
|
|
289
|
+
elif args:
|
|
290
|
+
value = args.pop(0)
|
|
291
|
+
elif p.kind == "opt":
|
|
292
|
+
value = p.default
|
|
284
293
|
else:
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
else:
|
|
288
|
-
continue # required argument missing
|
|
289
|
-
elif p.kind == "keyreq":
|
|
294
|
+
continue # required argument missing
|
|
295
|
+
elif p.kind in ("keyreq", "key"):
|
|
290
296
|
if p.name in kwargs:
|
|
291
297
|
value = kwargs[p.name]
|
|
298
|
+
bound.add(p.name)
|
|
299
|
+
elif p.kind == "key":
|
|
300
|
+
value = p.default
|
|
292
301
|
else:
|
|
293
302
|
continue # required argument missing
|
|
294
|
-
elif p.kind in ("opt", "key"):
|
|
295
|
-
value = kwargs.get(p.name, p.default)
|
|
296
303
|
elif p.kind == "rest":
|
|
297
304
|
value = tuple(args)
|
|
298
305
|
elif p.kind == "keyrest":
|
|
299
|
-
value = kwargs
|
|
306
|
+
value = {k: v for k, v in kwargs.items() if k not in bound} if bound else kwargs
|
|
300
307
|
else:
|
|
301
308
|
# If all the parameter types are handled, this
|
|
302
309
|
# shouldn't ever happen...
|
|
@@ -166,7 +166,7 @@ class Importer:
|
|
|
166
166
|
@classmethod
|
|
167
167
|
def initialize(cls):
|
|
168
168
|
cls.filter_stack = []
|
|
169
|
-
cls.filter_chain =
|
|
169
|
+
cls.filter_chain = None
|
|
170
170
|
cls._skip_instrumenting = ("appmap", "_appmap")
|
|
171
171
|
cls.instrument_properties = (
|
|
172
172
|
Env.current.get("APPMAP_INSTRUMENT_PROPERTIES", "true").lower() == "true"
|
|
@@ -176,6 +176,10 @@ class Importer:
|
|
|
176
176
|
def use_filter(cls, filter_class):
|
|
177
177
|
cls.filter_stack.append(filter_class)
|
|
178
178
|
|
|
179
|
+
@classmethod
|
|
180
|
+
def build_filter_chain(cls):
|
|
181
|
+
cls.filter_chain = reduce(lambda acc, e: e(acc), cls.filter_stack, NullFilter(None))
|
|
182
|
+
|
|
179
183
|
@classmethod
|
|
180
184
|
def instrument_function(cls, fn_name, filterableFn: FilterableFn, selected_functions=None):
|
|
181
185
|
# Only instrument the function if it was specifically called out for the package
|
|
@@ -194,8 +198,10 @@ class Importer:
|
|
|
194
198
|
return
|
|
195
199
|
|
|
196
200
|
logger.trace("do_import, mod %s args %s kwargs %s", mod, args, kwargs)
|
|
197
|
-
if
|
|
198
|
-
|
|
201
|
+
if cls.filter_chain is None:
|
|
202
|
+
# Only possible while _appmap is being (re)initialized, before install() has run.
|
|
203
|
+
logger.trace("no filter chain yet, not instrumenting %s", mod.__name__)
|
|
204
|
+
return
|
|
199
205
|
|
|
200
206
|
def instrument_functions(filterable, selected_functions=None):
|
|
201
207
|
# pylint: disable=too-many-locals
|
|
@@ -314,26 +320,18 @@ def wrapped_find_spec(find_spec, _, args, kwargs):
|
|
|
314
320
|
|
|
315
321
|
|
|
316
322
|
def wrap_finder_find_spec(finder):
|
|
317
|
-
#
|
|
318
|
-
#
|
|
319
|
-
#
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
323
|
+
# Builtin finders define find_spec as a classmethod or staticmethod, which wrapt has trouble
|
|
324
|
+
# identifying (see the comment in wrapped_find_spec above), so wrap the descriptor found in
|
|
325
|
+
# __dict__ instead.
|
|
326
|
+
find_spec = inspect.getattr_static(finder, "find_spec", None)
|
|
327
|
+
if find_spec is None:
|
|
328
|
+
logger.trace("no find_spec for finder %r", finder)
|
|
329
|
+
return
|
|
330
|
+
|
|
331
|
+
if isinstance(find_spec, (classmethod, staticmethod)):
|
|
326
332
|
finder.find_spec = wrap_finder_function(find_spec, wrapped_find_spec)
|
|
327
333
|
else:
|
|
328
|
-
find_spec =
|
|
329
|
-
if find_spec is None:
|
|
330
|
-
logger.trace("no find_spec for finder %r", finder)
|
|
331
|
-
return
|
|
332
|
-
|
|
333
|
-
if isinstance(find_spec, (classmethod, staticmethod)):
|
|
334
|
-
finder.find_spec = wrap_finder_function(find_spec, wrapped_find_spec)
|
|
335
|
-
else:
|
|
336
|
-
finder.find_spec = wrap_finder_function(finder.find_spec, wrapped_find_spec)
|
|
334
|
+
finder.find_spec = wrap_finder_function(finder.find_spec, wrapped_find_spec)
|
|
337
335
|
|
|
338
336
|
|
|
339
337
|
class MetapathObserver(MutableSequence):
|
|
@@ -362,6 +360,18 @@ class MetapathObserver(MutableSequence):
|
|
|
362
360
|
|
|
363
361
|
def initialize():
|
|
364
362
|
Importer.initialize()
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
def install():
|
|
366
|
+
"""
|
|
367
|
+
Build the filter chain and hook the finders. Must run after the filters have been registered
|
|
368
|
+
(i.e. after configuration.initialize()).
|
|
369
|
+
|
|
370
|
+
The chain is built before the finders are hooked because building it can import modules (e.g.
|
|
371
|
+
since 3.13, importlib.metadata.files imports csv lazily). If the hooks were already in place,
|
|
372
|
+
those imports would need the chain that's still being built.
|
|
373
|
+
"""
|
|
374
|
+
Importer.build_filter_chain()
|
|
365
375
|
# If we're not enabled, there's no reason to hook the finders.
|
|
366
376
|
if Env.current.enabled:
|
|
367
377
|
logger.trace("sys.metapath: %s", sys.meta_path)
|
|
@@ -22,6 +22,9 @@ class C:
|
|
|
22
22
|
def with_defaults(self, p1=1, p2=2):
|
|
23
23
|
return "%s %s" % (p1, p2)
|
|
24
24
|
|
|
25
|
+
def mixed(self, a, b=None, c="dflt", *args, d, e="e", **kwargs):
|
|
26
|
+
return "%s %s %s %s %s %s %s" % (a, b, c, args, d, e, kwargs)
|
|
27
|
+
|
|
25
28
|
|
|
26
29
|
if sys.version_info >= (3, 8):
|
|
27
30
|
exec(
|
|
@@ -33,5 +36,9 @@ C.positional_only = positional_only
|
|
|
33
36
|
def keyword_only(self, *, p1, p2):
|
|
34
37
|
return '%s %s' % (p1, p2)
|
|
35
38
|
C.keyword_only = keyword_only
|
|
39
|
+
|
|
40
|
+
def positional_only_kwargs(self, a, b="dflt", /, **kwargs):
|
|
41
|
+
return '%s %s %s' % (a, b, kwargs)
|
|
42
|
+
C.positional_only_kwargs = positional_only_kwargs
|
|
36
43
|
"""
|
|
37
44
|
)
|
|
@@ -115,14 +115,14 @@ class TestAgentValidate:
|
|
|
115
115
|
def test_python_version(self, capsys, mocker):
|
|
116
116
|
mocker.patch(
|
|
117
117
|
"_appmap.py_version_check._get_py_version",
|
|
118
|
-
return_value=(3,
|
|
118
|
+
return_value=(3, 10),
|
|
119
119
|
)
|
|
120
120
|
mocker.patch(
|
|
121
121
|
"_appmap.py_version_check._get_platform_version",
|
|
122
|
-
return_value="3.
|
|
122
|
+
return_value="3.10",
|
|
123
123
|
)
|
|
124
124
|
|
|
125
|
-
self.check_errors(capsys, 1, 1, r"Minimum Python version supported is \d
|
|
125
|
+
self.check_errors(capsys, 1, 1, r"Minimum Python version supported is \d+\.\d+, found")
|
|
126
126
|
|
|
127
127
|
def test_django_version(self, capsys, mocker):
|
|
128
128
|
mocker.patch(
|
|
@@ -266,9 +266,6 @@ class TestInstanceMethods(TestMethodBase):
|
|
|
266
266
|
},
|
|
267
267
|
)
|
|
268
268
|
|
|
269
|
-
@pytest.mark.skipif(
|
|
270
|
-
sys.version_info < (3, 8), reason="positional-only added in 3.8"
|
|
271
|
-
)
|
|
272
269
|
@pytest.mark.parametrize("params", ["positional_only"], indirect=True)
|
|
273
270
|
def test_positional_only(self, params):
|
|
274
271
|
evt = params.C().positional_only(1, 2)
|
|
@@ -282,7 +279,6 @@ class TestInstanceMethods(TestMethodBase):
|
|
|
282
279
|
evt, 1, {"class": "builtins.int", "kind": "req", "name": "p2", "value": "2"}
|
|
283
280
|
)
|
|
284
281
|
|
|
285
|
-
@pytest.mark.skipif(sys.version_info < (3, 8), reason="keyword-only added in 3.8")
|
|
286
282
|
@pytest.mark.parametrize("params", ["keyword_only"], indirect=True)
|
|
287
283
|
def test_keyword_only(self, params):
|
|
288
284
|
evt = params.C().keyword_only(p2=2, p1=1)
|
|
@@ -325,3 +321,161 @@ class TestInstanceMethods(TestMethodBase):
|
|
|
325
321
|
self.assert_parameter(
|
|
326
322
|
evt, 1, {"class": "builtins.int", "kind": "opt", "name": "p2", "value": "4"}
|
|
327
323
|
)
|
|
324
|
+
|
|
325
|
+
@pytest.mark.parametrize("params", ["with_defaults"], indirect=True)
|
|
326
|
+
def test_defaults_positional(self, params):
|
|
327
|
+
evt = params.C().with_defaults(3, 4)
|
|
328
|
+
assert len(evt.parameters) == 2
|
|
329
|
+
|
|
330
|
+
self.assert_parameter(
|
|
331
|
+
evt, 0, {"class": "builtins.int", "kind": "opt", "name": "p1", "value": "3"}
|
|
332
|
+
)
|
|
333
|
+
|
|
334
|
+
self.assert_parameter(
|
|
335
|
+
evt, 1, {"class": "builtins.int", "kind": "opt", "name": "p2", "value": "4"}
|
|
336
|
+
)
|
|
337
|
+
|
|
338
|
+
@pytest.mark.parametrize("params", ["with_defaults"], indirect=True)
|
|
339
|
+
def test_defaults_positional_and_keyword(self, params):
|
|
340
|
+
evt = params.C().with_defaults(3, p2=4)
|
|
341
|
+
assert len(evt.parameters) == 2
|
|
342
|
+
|
|
343
|
+
self.assert_parameter(
|
|
344
|
+
evt, 0, {"class": "builtins.int", "kind": "opt", "name": "p1", "value": "3"}
|
|
345
|
+
)
|
|
346
|
+
|
|
347
|
+
self.assert_parameter(
|
|
348
|
+
evt, 1, {"class": "builtins.int", "kind": "opt", "name": "p2", "value": "4"}
|
|
349
|
+
)
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
class TestMixedParams(TestMethodBase):
|
|
353
|
+
"""
|
|
354
|
+
C.mixed has the signature (self, a, b=None, c="dflt", *args, d, e="e", **kwargs),
|
|
355
|
+
covering every parameter kind.
|
|
356
|
+
"""
|
|
357
|
+
|
|
358
|
+
def assert_values(self, evt, expected):
|
|
359
|
+
actual = {p["name"]: (p["kind"], p["value"]) for p in evt.parameters}
|
|
360
|
+
assert actual == expected
|
|
361
|
+
|
|
362
|
+
@pytest.mark.parametrize("params", ["mixed"], indirect=True)
|
|
363
|
+
def test_positional_opt(self, params):
|
|
364
|
+
evt = params.C().mixed("A", "B", "C", d="D")
|
|
365
|
+
self.assert_values(
|
|
366
|
+
evt,
|
|
367
|
+
{
|
|
368
|
+
"a": ("req", "A"),
|
|
369
|
+
"b": ("opt", "B"),
|
|
370
|
+
"c": ("opt", "C"),
|
|
371
|
+
"args": ("rest", "()"),
|
|
372
|
+
"d": ("keyreq", "D"),
|
|
373
|
+
"e": ("key", "e"),
|
|
374
|
+
"kwargs": ("keyrest", "{}"),
|
|
375
|
+
},
|
|
376
|
+
)
|
|
377
|
+
|
|
378
|
+
@pytest.mark.parametrize("params", ["mixed"], indirect=True)
|
|
379
|
+
def test_partial_positional_opt(self, params):
|
|
380
|
+
evt = params.C().mixed("A", "B", d="D")
|
|
381
|
+
self.assert_values(
|
|
382
|
+
evt,
|
|
383
|
+
{
|
|
384
|
+
"a": ("req", "A"),
|
|
385
|
+
"b": ("opt", "B"),
|
|
386
|
+
"c": ("opt", "dflt"),
|
|
387
|
+
"args": ("rest", "()"),
|
|
388
|
+
"d": ("keyreq", "D"),
|
|
389
|
+
"e": ("key", "e"),
|
|
390
|
+
"kwargs": ("keyrest", "{}"),
|
|
391
|
+
},
|
|
392
|
+
)
|
|
393
|
+
|
|
394
|
+
@pytest.mark.parametrize("params", ["mixed"], indirect=True)
|
|
395
|
+
def test_keyword_opt(self, params):
|
|
396
|
+
evt = params.C().mixed("A", c="C", d="D")
|
|
397
|
+
self.assert_values(
|
|
398
|
+
evt,
|
|
399
|
+
{
|
|
400
|
+
"a": ("req", "A"),
|
|
401
|
+
"b": ("opt", "None"),
|
|
402
|
+
"c": ("opt", "C"),
|
|
403
|
+
"args": ("rest", "()"),
|
|
404
|
+
"d": ("keyreq", "D"),
|
|
405
|
+
"e": ("key", "e"),
|
|
406
|
+
"kwargs": ("keyrest", "{}"),
|
|
407
|
+
},
|
|
408
|
+
)
|
|
409
|
+
|
|
410
|
+
@pytest.mark.parametrize("params", ["mixed"], indirect=True)
|
|
411
|
+
def test_rest_after_opt(self, params):
|
|
412
|
+
evt = params.C().mixed("A", "B", "C", "X", "Y", d="D")
|
|
413
|
+
self.assert_values(
|
|
414
|
+
evt,
|
|
415
|
+
{
|
|
416
|
+
"a": ("req", "A"),
|
|
417
|
+
"b": ("opt", "B"),
|
|
418
|
+
"c": ("opt", "C"),
|
|
419
|
+
"args": ("rest", "('X', 'Y')"),
|
|
420
|
+
"d": ("keyreq", "D"),
|
|
421
|
+
"e": ("key", "e"),
|
|
422
|
+
"kwargs": ("keyrest", "{}"),
|
|
423
|
+
},
|
|
424
|
+
)
|
|
425
|
+
|
|
426
|
+
@pytest.mark.parametrize("params", ["mixed"], indirect=True)
|
|
427
|
+
def test_keyword_only(self, params):
|
|
428
|
+
evt = params.C().mixed("A", d="D", e="E", f="F")
|
|
429
|
+
self.assert_values(
|
|
430
|
+
evt,
|
|
431
|
+
{
|
|
432
|
+
"a": ("req", "A"),
|
|
433
|
+
"b": ("opt", "None"),
|
|
434
|
+
"c": ("opt", "dflt"),
|
|
435
|
+
"args": ("rest", "()"),
|
|
436
|
+
"d": ("keyreq", "D"),
|
|
437
|
+
"e": ("key", "E"),
|
|
438
|
+
"kwargs": ("keyrest", "{'f': 'F'}"),
|
|
439
|
+
},
|
|
440
|
+
)
|
|
441
|
+
|
|
442
|
+
@pytest.mark.parametrize("params", ["mixed"], indirect=True)
|
|
443
|
+
def test_keyword_req(self, params):
|
|
444
|
+
evt = params.C().mixed(a="A", d="D", f="F")
|
|
445
|
+
self.assert_values(
|
|
446
|
+
evt,
|
|
447
|
+
{
|
|
448
|
+
"a": ("req", "A"),
|
|
449
|
+
"b": ("opt", "None"),
|
|
450
|
+
"c": ("opt", "dflt"),
|
|
451
|
+
"args": ("rest", "()"),
|
|
452
|
+
"d": ("keyreq", "D"),
|
|
453
|
+
"e": ("key", "e"),
|
|
454
|
+
"kwargs": ("keyrest", "{'f': 'F'}"),
|
|
455
|
+
},
|
|
456
|
+
)
|
|
457
|
+
|
|
458
|
+
@pytest.mark.parametrize("params", ["positional_only_kwargs"], indirect=True)
|
|
459
|
+
def test_positional_only_name_in_kwargs(self, params):
|
|
460
|
+
# Keyword arguments named like positional-only parameters go to **kwargs
|
|
461
|
+
evt = params.C().positional_only_kwargs("A", "B", a="X", b="Y")
|
|
462
|
+
self.assert_values(
|
|
463
|
+
evt,
|
|
464
|
+
{
|
|
465
|
+
"a": ("req", "A"),
|
|
466
|
+
"b": ("opt", "B"),
|
|
467
|
+
"kwargs": ("keyrest", "{'a': 'X', 'b': 'Y'}"),
|
|
468
|
+
},
|
|
469
|
+
)
|
|
470
|
+
|
|
471
|
+
@pytest.mark.parametrize("params", ["positional_only_kwargs"], indirect=True)
|
|
472
|
+
def test_positional_only_default_name_in_kwargs(self, params):
|
|
473
|
+
evt = params.C().positional_only_kwargs("A", b="Y")
|
|
474
|
+
self.assert_values(
|
|
475
|
+
evt,
|
|
476
|
+
{
|
|
477
|
+
"a": ("req", "A"),
|
|
478
|
+
"b": ("opt", "dflt"),
|
|
479
|
+
"kwargs": ("keyrest", "{'b': 'Y'}"),
|
|
480
|
+
},
|
|
481
|
+
)
|
|
@@ -118,8 +118,7 @@ def test_operator_itemgetter(events):
|
|
|
118
118
|
assert len(events) == 2
|
|
119
119
|
assert events[0].to_dict() == DictIncluding({
|
|
120
120
|
"event": "call",
|
|
121
|
-
|
|
122
|
-
# "defined_class": "operator",
|
|
121
|
+
"defined_class": "operator",
|
|
123
122
|
"method_id": "itemgetter (get)",
|
|
124
123
|
})
|
|
125
124
|
|
|
@@ -53,29 +53,12 @@ _parser.add_argument(
|
|
|
53
53
|
default=argparse.SUPPRESS,
|
|
54
54
|
)
|
|
55
55
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
)
|
|
63
|
-
else:
|
|
64
|
-
# You can see why BooleanOptionalAction was added. This is close, though not
|
|
65
|
-
# really as good....
|
|
66
|
-
_enable_log_group = _parser.add_mutually_exclusive_group()
|
|
67
|
-
_enable_log_group.add_argument(
|
|
68
|
-
"--enable-log",
|
|
69
|
-
help="create a log file",
|
|
70
|
-
dest="enable_log",
|
|
71
|
-
action="store_true",
|
|
72
|
-
)
|
|
73
|
-
_enable_log_group.add_argument(
|
|
74
|
-
"--no-enable-log",
|
|
75
|
-
help="don't create a log file",
|
|
76
|
-
dest="enable_log",
|
|
77
|
-
action="store_false",
|
|
78
|
-
)
|
|
56
|
+
_parser.add_argument(
|
|
57
|
+
"--enable-log",
|
|
58
|
+
help="create a log file",
|
|
59
|
+
action=argparse.BooleanOptionalAction,
|
|
60
|
+
default=False,
|
|
61
|
+
)
|
|
79
62
|
|
|
80
63
|
_parser.add_argument(
|
|
81
64
|
"command",
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "appmap"
|
|
3
|
-
version = "
|
|
3
|
+
version = "4.0.0"
|
|
4
4
|
description = "Create AppMap files by recording a Python application."
|
|
5
5
|
readme = "README.md"
|
|
6
|
-
requires-python = ">=3.
|
|
6
|
+
requires-python = ">=3.11"
|
|
7
7
|
license = { text = "MIT" }
|
|
8
8
|
authors = [
|
|
9
9
|
{ name = "Alan Potter", email = "alan@app.land" },
|
|
@@ -14,10 +14,20 @@ classifiers = [
|
|
|
14
14
|
"Development Status :: 4 - Beta",
|
|
15
15
|
"Framework :: Django",
|
|
16
16
|
"Framework :: Django :: 3.2",
|
|
17
|
+
"Framework :: Django :: 4.2",
|
|
18
|
+
"Framework :: Django :: 5.2",
|
|
19
|
+
"Framework :: Django :: 6.0",
|
|
17
20
|
"Framework :: Flask",
|
|
18
21
|
"Framework :: Pytest",
|
|
19
22
|
"Intended Audience :: Developers",
|
|
20
23
|
"License :: OSI Approved :: MIT License",
|
|
24
|
+
"Programming Language :: Python :: 3",
|
|
25
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
26
|
+
"Programming Language :: Python :: 3.11",
|
|
27
|
+
"Programming Language :: Python :: 3.12",
|
|
28
|
+
"Programming Language :: Python :: 3.13",
|
|
29
|
+
"Programming Language :: Python :: 3.14",
|
|
30
|
+
"Programming Language :: Python :: 3.15",
|
|
21
31
|
"Topic :: Software Development",
|
|
22
32
|
"Topic :: Software Development :: Debuggers",
|
|
23
33
|
"Topic :: Software Development :: Documentation",
|
|
@@ -60,8 +70,7 @@ test = [
|
|
|
60
70
|
"Flask",
|
|
61
71
|
"sqlalchemy",
|
|
62
72
|
"pytest-django>=4.7,<5.0",
|
|
63
|
-
"numpy>=
|
|
64
|
-
"numpy>=2.0; python_version >= '3.9'",
|
|
73
|
+
"numpy>=2.0",
|
|
65
74
|
]
|
|
66
75
|
dev = [
|
|
67
76
|
"appmap[test]",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|