appmap 2.0.3__tar.gz → 2.0.5__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 (164) hide show
  1. {appmap-2.0.3 → appmap-2.0.5}/PKG-INFO +1 -1
  2. {appmap-2.0.3 → appmap-2.0.5}/_appmap/instrument.py +3 -1
  3. {appmap-2.0.3 → appmap-2.0.5}/_appmap/recorder.py +20 -0
  4. {appmap-2.0.3 → appmap-2.0.5}/_appmap/recording.py +27 -0
  5. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/pytest/expected/pytest.appmap.json +81 -37
  6. appmap-2.0.5/_appmap/test/data/pytest/simple.py +18 -0
  7. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/test_generation.py +20 -0
  8. {appmap-2.0.3 → appmap-2.0.5}/appmap/__init__.py +10 -1
  9. {appmap-2.0.3 → appmap-2.0.5}/pyproject.toml +1 -1
  10. appmap-2.0.3/_appmap/test/data/pytest/simple.py +0 -9
  11. {appmap-2.0.3 → appmap-2.0.5}/LICENSE +0 -0
  12. {appmap-2.0.3 → appmap-2.0.5}/README.md +0 -0
  13. {appmap-2.0.3 → appmap-2.0.5}/_appmap/__init__.py +0 -0
  14. {appmap-2.0.3 → appmap-2.0.5}/_appmap/configuration.py +0 -0
  15. {appmap-2.0.3 → appmap-2.0.5}/_appmap/django.py +0 -0
  16. {appmap-2.0.3 → appmap-2.0.5}/_appmap/env.py +0 -0
  17. {appmap-2.0.3 → appmap-2.0.5}/_appmap/event.py +0 -0
  18. {appmap-2.0.3 → appmap-2.0.5}/_appmap/fastapi.py +0 -0
  19. {appmap-2.0.3 → appmap-2.0.5}/_appmap/flask.py +0 -0
  20. {appmap-2.0.3 → appmap-2.0.5}/_appmap/generation.py +0 -0
  21. {appmap-2.0.3 → appmap-2.0.5}/_appmap/importer.py +0 -0
  22. {appmap-2.0.3 → appmap-2.0.5}/_appmap/labels.py +0 -0
  23. {appmap-2.0.3 → appmap-2.0.5}/_appmap/metadata.py +0 -0
  24. {appmap-2.0.3 → appmap-2.0.5}/_appmap/noappmap.py +0 -0
  25. {appmap-2.0.3 → appmap-2.0.5}/_appmap/py_version_check.py +0 -0
  26. {appmap-2.0.3 → appmap-2.0.5}/_appmap/remote_recording.py +0 -0
  27. {appmap-2.0.3 → appmap-2.0.5}/_appmap/singleton.py +0 -0
  28. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/__init__.py +0 -0
  29. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/appmap_test_base.py +0 -0
  30. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/bin/server_runner +0 -0
  31. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/conftest.py +0 -0
  32. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/appmap-all-paths-malformed.yml +0 -0
  33. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/appmap-broken.yml +0 -0
  34. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/appmap-class.yml +0 -0
  35. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/appmap-empty-path.yml +0 -0
  36. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/appmap-exclude-fn.yml +0 -0
  37. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/appmap-func.yml +0 -0
  38. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/appmap-malformed-path.yml +0 -0
  39. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/appmap-no-pyyaml.yml +0 -0
  40. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/appmap.yml +0 -0
  41. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/appmap_testing/__init__.py +0 -0
  42. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/appmap_testing/django_simplelazyobject.py +0 -0
  43. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/config/src/package/__init__.py +0 -0
  44. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/config/test/__init__.py +0 -0
  45. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/config/test/foo.py +0 -0
  46. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/config-exclude/.hide/hidden_mod/__init__.py +0 -0
  47. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/config-exclude/node_modules/node_mod/__init__.py +0 -0
  48. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/config-exclude/src/package/__init__.py +0 -0
  49. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/config-exclude/test/__init__.py +0 -0
  50. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/config-exclude/venv/venv_mod/__init__.py +0 -0
  51. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/config-up/appmap.yml +0 -0
  52. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/config-up/project/p1/__init__.py +0 -0
  53. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/config-up/project/p2/sub1/__init__.py +0 -0
  54. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/django/appmap.yml +0 -0
  55. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/django/djangoapp/__init__.py +0 -0
  56. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/django/djangoapp/djangoapp.py +0 -0
  57. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/django/djangoapp/hello_world.html +0 -0
  58. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/django/djangoapp/middleware.py +0 -0
  59. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/django/djangoapp/settings.py +0 -0
  60. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/django/djangoapp/settings_dev.py +0 -0
  61. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/django/djangoapp/urls.py +0 -0
  62. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/django/init/sitecustomize.py +0 -0
  63. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/django/manage.py +0 -0
  64. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/django/pytest.ini +0 -0
  65. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/django/test/__init__.py +0 -0
  66. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/django/test/test_app.py +0 -0
  67. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/example_class.py +0 -0
  68. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/expected.appmap.json +0 -0
  69. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/fastapi/appmap.yml +0 -0
  70. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/fastapi/fastapiapp/__init__.py +0 -0
  71. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/fastapi/fastapiapp/main.py +0 -0
  72. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/fastapi/init/sitecustomize.py +0 -0
  73. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/fastapi/test_app.py +0 -0
  74. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/flask/appmap.yml +0 -0
  75. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/flask/flaskapp.py +0 -0
  76. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/flask/init/sitecustomize.py +0 -0
  77. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/flask/templates/test.html +0 -0
  78. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/flask/test_app.py +0 -0
  79. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/package1/__init__.py +0 -0
  80. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/package1/package2/__init__.py +0 -0
  81. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/package1/package2/__main__.py +0 -0
  82. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/package1/package2/mod1.py +0 -0
  83. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/params.py +0 -0
  84. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/pytest/appmap.yml +0 -0
  85. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/pytest/expected/status_errored.metadata.json +0 -0
  86. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/pytest/expected/status_failed.metadata.json +0 -0
  87. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/pytest/expected/status_xfailed.metadata.json +0 -0
  88. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/pytest/test_noappmap.py +0 -0
  89. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/pytest/test_simple.py +0 -0
  90. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/remote.appmap.json +0 -0
  91. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/trial/.gitignore +0 -0
  92. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/trial/appmap.yml +0 -0
  93. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/trial/expected/pytest.appmap.json +0 -0
  94. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/trial/init/sitecustomize.py +0 -0
  95. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/trial/test/__init__.py +0 -0
  96. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/trial/test/test_deferred.py +0 -0
  97. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/unittest/appmap.yml +0 -0
  98. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/unittest/expected/pytest.appmap.json +0 -0
  99. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/unittest/expected/status_errored.metadata.json +0 -0
  100. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/unittest/expected/status_failed.metadata.json +0 -0
  101. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/unittest/expected/status_xfailed.metadata.json +0 -0
  102. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/unittest/expected/status_xsucceeded.metadata.json +0 -0
  103. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/unittest/expected/unittest.appmap.json +0 -0
  104. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/unittest/init/sitecustomize.py +0 -0
  105. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/unittest/simple/__init__.py +0 -0
  106. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/unittest/simple/test_noappmap.py +0 -0
  107. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/data/unittest/simple/test_simple.py +0 -0
  108. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/helpers.py +0 -0
  109. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/normalize.py +0 -0
  110. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/test_command.py +0 -0
  111. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/test_configuration.py +0 -0
  112. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/test_describe_value.py +0 -0
  113. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/test_django.py +0 -0
  114. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/test_django_simplelazyobject.py +0 -0
  115. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/test_env.py +0 -0
  116. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/test_events.py +0 -0
  117. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/test_fastapi.py +0 -0
  118. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/test_flask.py +0 -0
  119. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/test_http.py +0 -0
  120. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/test_importer.py +0 -0
  121. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/test_labels.py +0 -0
  122. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/test_metadata.py +0 -0
  123. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/test_params.py +0 -0
  124. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/test_recording.py +0 -0
  125. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/test_runner.py +0 -0
  126. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/test_sqlalchemy.py +0 -0
  127. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/test_test_frameworks.py +0 -0
  128. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/test_util.py +0 -0
  129. {appmap-2.0.3 → appmap-2.0.5}/_appmap/test/web_framework.py +0 -0
  130. {appmap-2.0.3 → appmap-2.0.5}/_appmap/testing_framework.py +0 -0
  131. {appmap-2.0.3 → appmap-2.0.5}/_appmap/trace_logger.py +0 -0
  132. {appmap-2.0.3 → appmap-2.0.5}/_appmap/unittest.py +0 -0
  133. {appmap-2.0.3 → appmap-2.0.5}/_appmap/utils.py +0 -0
  134. {appmap-2.0.3 → appmap-2.0.5}/_appmap/web_framework.py +0 -0
  135. {appmap-2.0.3 → appmap-2.0.5}/appmap/command/__init__.py +0 -0
  136. {appmap-2.0.3 → appmap-2.0.5}/appmap/command/appmap_agent_init.py +0 -0
  137. {appmap-2.0.3 → appmap-2.0.5}/appmap/command/appmap_agent_status.py +0 -0
  138. {appmap-2.0.3 → appmap-2.0.5}/appmap/command/appmap_agent_validate.py +0 -0
  139. {appmap-2.0.3 → appmap-2.0.5}/appmap/command/runner.py +0 -0
  140. {appmap-2.0.3 → appmap-2.0.5}/appmap/django.py +0 -0
  141. {appmap-2.0.3 → appmap-2.0.5}/appmap/fastapi.py +0 -0
  142. {appmap-2.0.3 → appmap-2.0.5}/appmap/flask.py +0 -0
  143. {appmap-2.0.3 → appmap-2.0.5}/appmap/http.py +0 -0
  144. {appmap-2.0.3 → appmap-2.0.5}/appmap/labeling/__init__.py +0 -0
  145. {appmap-2.0.3 → appmap-2.0.5}/appmap/labeling/crypto.yml +0 -0
  146. {appmap-2.0.3 → appmap-2.0.5}/appmap/labeling/django.yml +0 -0
  147. {appmap-2.0.3 → appmap-2.0.5}/appmap/labeling/flask.yml +0 -0
  148. {appmap-2.0.3 → appmap-2.0.5}/appmap/labeling/formats.yml +0 -0
  149. {appmap-2.0.3 → appmap-2.0.5}/appmap/labeling/http.yml +0 -0
  150. {appmap-2.0.3 → appmap-2.0.5}/appmap/labeling/jobs.yml +0 -0
  151. {appmap-2.0.3 → appmap-2.0.5}/appmap/labeling/jwt.yml +0 -0
  152. {appmap-2.0.3 → appmap-2.0.5}/appmap/labeling/logger.yml +0 -0
  153. {appmap-2.0.3 → appmap-2.0.5}/appmap/labeling/random.yml +0 -0
  154. {appmap-2.0.3 → appmap-2.0.5}/appmap/pytest.py +0 -0
  155. {appmap-2.0.3 → appmap-2.0.5}/appmap/sqlalchemy.py +0 -0
  156. {appmap-2.0.3 → appmap-2.0.5}/appmap/unittest.py +0 -0
  157. {appmap-2.0.3 → appmap-2.0.5}/appmap/uvicorn.py +0 -0
  158. {appmap-2.0.3 → appmap-2.0.5}/appmap.pth +0 -0
  159. {appmap-2.0.3 → appmap-2.0.5}/vendor/_appmap/wrapt/LICENSE +0 -0
  160. {appmap-2.0.3 → appmap-2.0.5}/vendor/_appmap/wrapt/__init__.py +0 -0
  161. {appmap-2.0.3 → appmap-2.0.5}/vendor/_appmap/wrapt/arguments.py +0 -0
  162. {appmap-2.0.3 → appmap-2.0.5}/vendor/_appmap/wrapt/decorators.py +0 -0
  163. {appmap-2.0.3 → appmap-2.0.5}/vendor/_appmap/wrapt/importer.py +0 -0
  164. {appmap-2.0.3 → appmap-2.0.5}/vendor/_appmap/wrapt/wrappers.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: appmap
3
- Version: 2.0.3
3
+ Version: 2.0.5
4
4
  Summary: Create AppMap files by recording a Python application.
5
5
  Home-page: https://github.com/applandinc/appmap-python
6
6
  License: MIT
@@ -6,7 +6,7 @@ from contextlib import contextmanager
6
6
  from . import event
7
7
  from .env import Env
8
8
  from .event import CallEvent
9
- from .recorder import Recorder
9
+ from .recorder import Recorder, AppMapTooManyEvents
10
10
  from .utils import appmap_tls
11
11
 
12
12
  logger = Env.current.getLogger(__name__)
@@ -97,6 +97,8 @@ def call_instrumented(f, instance, args, kwargs):
97
97
  )
98
98
  Recorder.add_event(return_event)
99
99
  return ret
100
+ except AppMapTooManyEvents:
101
+ raise
100
102
  except Exception: # noqa: E722
101
103
  elapsed_time = time.time() - start_time
102
104
  Recorder.add_event(
@@ -10,6 +10,17 @@ logger = Env.current.getLogger(__name__)
10
10
  # pylint: disable=global-statement
11
11
  _default_recorder = None
12
12
 
13
+ # Allow the user to suggest a limit on the number of events that should be added to a Recorder.
14
+ # Depending on how exceptions get processed by the framework, there may be some more added, but it
15
+ # shouldn't be an enormous number.
16
+ _MAX_EVENTS = Env.current.get("APPMAP_MAX_EVENTS")
17
+ if _MAX_EVENTS is not None:
18
+ _MAX_EVENTS = int(_MAX_EVENTS)
19
+
20
+
21
+ class AppMapTooManyEvents(RuntimeError):
22
+ """Thrown when a recorder has more than APPMAP_MAX_EVENTS"""
23
+
13
24
 
14
25
  class Recorder(ABC):
15
26
  """
@@ -18,6 +29,8 @@ class Recorder(ABC):
18
29
  Note that the abstract methods have implementations for use by subclasses.
19
30
  """
20
31
 
32
+ _aborting = False
33
+
21
34
  @property
22
35
  @abstractmethod
23
36
  def events(self):
@@ -104,6 +117,7 @@ class Recorder(ABC):
104
117
  return [perthread, _default_recorder]
105
118
 
106
119
  def clear(self):
120
+ Recorder._aborting = False
107
121
  self._events = []
108
122
 
109
123
  def __init__(self, enabled=False):
@@ -130,7 +144,13 @@ class Recorder(ABC):
130
144
 
131
145
  @abstractmethod
132
146
  def _add_event(self, event):
147
+ if Recorder._aborting:
148
+ return
149
+
133
150
  self._events.append(event)
151
+ if _MAX_EVENTS is not None and len(self._events) > _MAX_EVENTS:
152
+ Recorder._aborting = True
153
+ raise AppMapTooManyEvents()
134
154
 
135
155
  @staticmethod
136
156
  def _initialize():
@@ -54,6 +54,33 @@ class Recording:
54
54
  return False
55
55
 
56
56
 
57
+ class NoopRecording:
58
+ """
59
+ A noop context manager to export as "Recording" instead of class
60
+ Recording when not Env.current.enabled.
61
+ """
62
+
63
+ def __init__(self, exit_hook=None):
64
+ self.exit_hook = exit_hook
65
+
66
+ def start(self):
67
+ pass
68
+
69
+ def stop(self):
70
+ pass
71
+
72
+ def is_running(self):
73
+ return False
74
+
75
+ def __enter__(self):
76
+ pass
77
+
78
+ def __exit__(self, exc_type, exc_value, tb):
79
+ if self.exit_hook is not None:
80
+ self.exit_hook(self)
81
+ return False
82
+
83
+
57
84
  def write_appmap(
58
85
  appmap, appmap_fname, recorder_type, metadata=None, basedir=Env.current.output_dir
59
86
  ):
@@ -8,95 +8,133 @@
8
8
  "name": "appmap",
9
9
  "url": "https://github.com/applandinc/appmap-python"
10
10
  },
11
+ "source_location": "test_simple.py:5",
12
+ "name": "hello world",
13
+ "feature": "Hello world",
11
14
  "app": "Simple",
12
15
  "recorder": {
13
16
  "name": "pytest",
14
17
  "type": "tests"
15
18
  },
16
- "source_location": "test_simple.py:5",
17
- "name": "hello world",
18
- "feature": "Hello world",
19
19
  "test_status": "succeeded"
20
20
  },
21
21
  "events": [
22
22
  {
23
- "defined_class": "simple.Simple",
24
- "method_id": "hello_world",
25
- "path": "simple.py",
26
- "lineno": 8,
27
23
  "static": false,
28
24
  "receiver": {
29
- "class": "simple.Simple",
30
25
  "kind": "req",
26
+ "value": "<simple.Simple object at 0xabcdef>",
31
27
  "name": "self",
32
- "value": "<simple.Simple object at 0xabcdef>"
28
+ "class": "simple.Simple"
33
29
  },
34
30
  "parameters": [],
35
31
  "id": 1,
36
32
  "event": "call",
37
- "thread_id": 1
33
+ "thread_id": 1,
34
+ "defined_class": "simple.Simple",
35
+ "method_id": "hello_world",
36
+ "path": "simple.py",
37
+ "lineno": 16
38
38
  },
39
39
  {
40
+ "static": false,
41
+ "receiver": {
42
+ "kind": "req",
43
+ "value": "<simple.Simple object at 0xabcdef>",
44
+ "name": "self",
45
+ "class": "simple.Simple"
46
+ },
47
+ "parameters": [],
48
+ "id": 2,
49
+ "event": "call",
50
+ "thread_id": 1,
40
51
  "defined_class": "simple.Simple",
41
- "method_id": "hello",
52
+ "method_id": "get_non_json_serializable",
42
53
  "path": "simple.py",
43
- "lineno": 2,
54
+ "lineno": 13
55
+ },
56
+ {
44
57
  "static": false,
45
58
  "receiver": {
46
- "class": "simple.Simple",
47
59
  "kind": "req",
60
+ "value": "<simple.Simple object at 0xabcdef>",
48
61
  "name": "self",
49
- "value": "<simple.Simple object at 0xabcdef>"
62
+ "class": "simple.Simple"
50
63
  },
51
64
  "parameters": [],
52
- "id": 2,
65
+ "id": 3,
53
66
  "event": "call",
54
- "thread_id": 1
67
+ "thread_id": 1,
68
+ "defined_class": "simple.Simple",
69
+ "method_id": "hello",
70
+ "path": "simple.py",
71
+ "lineno": 7
55
72
  },
56
73
  {
57
74
  "return_value": {
58
- "class": "builtins.str",
59
- "value": "'Hello'"
75
+ "value": "'Hello'",
76
+ "class": "builtins.str"
60
77
  },
61
- "parent_id": 2,
62
- "id": 3,
78
+ "parent_id": 3,
79
+ "id": 4,
63
80
  "event": "return",
64
81
  "thread_id": 1
65
82
  },
66
83
  {
67
- "defined_class": "simple.Simple",
68
- "method_id": "world",
69
- "path": "simple.py",
70
- "lineno": 5,
71
84
  "static": false,
72
85
  "receiver": {
73
- "class": "simple.Simple",
74
86
  "kind": "req",
87
+ "value": "<simple.Simple object at 0xabcdef>",
75
88
  "name": "self",
76
- "value": "<simple.Simple object at 0xabcdef>"
89
+ "class": "simple.Simple"
77
90
  },
78
91
  "parameters": [],
79
- "id": 4,
92
+ "id": 5,
80
93
  "event": "call",
94
+ "thread_id": 1,
95
+ "defined_class": "simple.Simple",
96
+ "method_id": "world",
97
+ "path": "simple.py",
98
+ "lineno": 10
99
+ },
100
+ {
101
+ "return_value": {
102
+ "value": "'world!'",
103
+ "class": "builtins.str"
104
+ },
105
+ "parent_id": 5,
106
+ "id": 6,
107
+ "event": "return",
81
108
  "thread_id": 1
82
109
  },
83
110
  {
84
111
  "return_value": {
85
- "class": "builtins.str",
86
- "value": "'world!'"
112
+ "value": "{0: 'Hello', 1: 'world!'}",
113
+ "class": "builtins.dict",
114
+ "properties": [
115
+ {
116
+ "name": "0",
117
+ "class": "builtins.str"
118
+ },
119
+ {
120
+ "name": "1",
121
+ "class": "builtins.str"
122
+ }
123
+ ],
124
+ "size": 2
87
125
  },
88
- "parent_id": 4,
89
- "id": 5,
126
+ "parent_id": 2,
127
+ "id": 7,
90
128
  "event": "return",
91
129
  "thread_id": 1
92
130
  },
93
131
  {
94
132
  "return_value": {
95
- "class": "builtins.str",
96
- "value": "'Hello world!'"
133
+ "value": "'Hello world!'",
134
+ "class": "builtins.str"
97
135
  },
98
136
  "parent_id": 1,
99
- "id": 6,
137
+ "id": 8,
100
138
  "event": "return",
101
139
  "thread_id": 1
102
140
  }
@@ -110,22 +148,28 @@
110
148
  "name": "Simple",
111
149
  "type": "class",
112
150
  "children": [
151
+ {
152
+ "name": "get_non_json_serializable",
153
+ "type": "function",
154
+ "location": "simple.py:13",
155
+ "static": false
156
+ },
113
157
  {
114
158
  "name": "hello",
115
159
  "type": "function",
116
- "location": "simple.py:2",
160
+ "location": "simple.py:7",
117
161
  "static": false
118
162
  },
119
163
  {
120
164
  "name": "hello_world",
121
165
  "type": "function",
122
- "location": "simple.py:8",
166
+ "location": "simple.py:16",
123
167
  "static": false
124
168
  },
125
169
  {
126
170
  "name": "world",
127
171
  "type": "function",
128
- "location": "simple.py:5",
172
+ "location": "simple.py:10",
129
173
  "static": false
130
174
  }
131
175
  ]
@@ -0,0 +1,18 @@
1
+ import numpy
2
+
3
+ zero = numpy.int64(0)
4
+ one = numpy.int64(1)
5
+
6
+ class Simple:
7
+ def hello(self):
8
+ return "Hello"
9
+
10
+ def world(self):
11
+ return "world!"
12
+
13
+ def get_non_json_serializable(self):
14
+ return { zero: self.hello(), one: self.world() }
15
+
16
+ def hello_world(self):
17
+ result = self.get_non_json_serializable()
18
+ return "%s %s" % (result[zero], result[one])
@@ -1,5 +1,10 @@
1
+ import json
1
2
  import pytest
2
3
 
4
+ import numpy as np
5
+
6
+ from _appmap.generation import AppMapEncoder
7
+
3
8
 
4
9
  @pytest.mark.appmap_enabled
5
10
  @pytest.mark.usefixtures("with_data_dir")
@@ -48,3 +53,18 @@ class TestGeneration:
48
53
  return ret
49
54
 
50
55
  verify_example_appmap(check_comment, "instance_method")
56
+
57
+ class TestAppMapEncoder:
58
+ def test_np_int64_type(self):
59
+ data = {
60
+ "value": np.int64(42),
61
+ }
62
+ json_str = json.dumps(data, cls=AppMapEncoder)
63
+ assert '{"value": "42"}' == json_str
64
+
65
+ def test_np_array_type(self):
66
+ data = {
67
+ "value": np.array([0, 1, 2, 3])
68
+ }
69
+ json_str = json.dumps(data, cls=AppMapEncoder)
70
+ assert '{"value": "[0 1 2 3]"}' == json_str
@@ -8,6 +8,7 @@ import os
8
8
  # execute the imports in a function, the modules all get put into the funtion's
9
9
  # globals, rather than into appmap's globals.
10
10
  _enabled = os.environ.get("APPMAP", None)
11
+ _recording_exported = False
11
12
  if _enabled is None or _enabled.upper() == "TRUE":
12
13
  if _enabled is not None:
13
14
  # Use setdefault so tests can manage _APPMAP as necessary
@@ -18,6 +19,7 @@ if _enabled is None or _enabled.upper() == "TRUE":
18
19
  from _appmap.labels import labels # noqa: F401
19
20
  from _appmap.noappmap import decorator as noappmap # noqa: F401
20
21
  from _appmap.recording import Recording # noqa: F401
22
+ _recording_exported = True
21
23
 
22
24
  try:
23
25
  from . import django # noqa: F401
@@ -51,4 +53,11 @@ if _enabled is None or _enabled.upper() == "TRUE":
51
53
  else:
52
54
  os.environ.pop("_APPMAP", None)
53
55
  else:
54
- os.environ.setdefault("_APPMAP", "false")
56
+ os.environ.setdefault("_APPMAP", "false")
57
+
58
+ if not _recording_exported:
59
+ # Client code that imports appmap.Recording should run correctly
60
+ # even when not Env.current.enabled (not APPMAP=true).
61
+ # This prevents:
62
+ # ImportError: cannot import name 'Recording' from 'appmap'...
63
+ from _appmap.recording import NoopRecording as Recording # noqa: F401
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "appmap"
3
- version = "2.0.3"
3
+ version = "2.0.5"
4
4
  description = "Create AppMap files by recording a Python application."
5
5
  readme = "README.md"
6
6
  authors = [
@@ -1,9 +0,0 @@
1
- class Simple:
2
- def hello(self):
3
- return "Hello"
4
-
5
- def world(self):
6
- return "world!"
7
-
8
- def hello_world(self):
9
- return "%s %s" % (self.hello(), self.world())
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
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes