open-aea 2.2.6__tar.gz → 2.2.7__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 (262) hide show
  1. {open_aea-2.2.6 → open_aea-2.2.7}/PKG-INFO +1 -1
  2. {open_aea-2.2.6 → open_aea-2.2.7}/aea/__version__.py +1 -1
  3. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/generate_all_protocols.py +1 -1
  4. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/scaffold.py +11 -0
  5. {open_aea-2.2.6 → open_aea-2.2.7}/aea/configurations/loader.py +40 -5
  6. {open_aea-2.2.6 → open_aea-2.2.7}/aea/configurations/utils.py +25 -0
  7. {open_aea-2.2.6 → open_aea-2.2.7}/aea/connections/base.py +8 -2
  8. {open_aea-2.2.6 → open_aea-2.2.7}/aea/contracts/base.py +8 -1
  9. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/base.py +29 -1
  10. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/env_vars.py +83 -6
  11. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/logging.py +15 -1
  12. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/protocols.py +3 -2
  13. {open_aea-2.2.6 → open_aea-2.2.7}/aea/skills/base.py +71 -23
  14. {open_aea-2.2.6 → open_aea-2.2.7}/pyproject.toml +1 -1
  15. {open_aea-2.2.6 → open_aea-2.2.7}/AUTHORS.md +0 -0
  16. {open_aea-2.2.6 → open_aea-2.2.7}/LICENSE +0 -0
  17. {open_aea-2.2.6 → open_aea-2.2.7}/README.md +0 -0
  18. {open_aea-2.2.6 → open_aea-2.2.7}/aea/__init__.py +0 -0
  19. {open_aea-2.2.6 → open_aea-2.2.7}/aea/abstract_agent.py +0 -0
  20. {open_aea-2.2.6 → open_aea-2.2.7}/aea/aea.py +0 -0
  21. {open_aea-2.2.6 → open_aea-2.2.7}/aea/aea_builder.py +0 -0
  22. {open_aea-2.2.6 → open_aea-2.2.7}/aea/agent.py +0 -0
  23. {open_aea-2.2.6 → open_aea-2.2.7}/aea/agent_loop.py +0 -0
  24. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/__init__.py +0 -0
  25. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/__main__.py +0 -0
  26. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/add.py +0 -0
  27. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/add_key.py +0 -0
  28. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/build.py +0 -0
  29. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/check_packages.py +0 -0
  30. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/config.py +0 -0
  31. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/core.py +0 -0
  32. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/create.py +0 -0
  33. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/delete.py +0 -0
  34. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/eject.py +0 -0
  35. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/fetch.py +0 -0
  36. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/fingerprint.py +0 -0
  37. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/freeze.py +0 -0
  38. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/generate.py +0 -0
  39. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/generate_key.py +0 -0
  40. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/generate_wealth.py +0 -0
  41. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/get_address.py +0 -0
  42. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/get_multiaddress.py +0 -0
  43. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/get_public_key.py +0 -0
  44. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/get_wealth.py +0 -0
  45. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/init.py +0 -0
  46. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/install.py +0 -0
  47. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/ipfs_hash.py +0 -0
  48. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/issue_certificates.py +0 -0
  49. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/launch.py +0 -0
  50. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/list.py +0 -0
  51. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/local_registry_sync.py +0 -0
  52. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/login.py +0 -0
  53. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/logout.py +0 -0
  54. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/packages.py +0 -0
  55. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/plugin.py +0 -0
  56. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/publish.py +0 -0
  57. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/push.py +0 -0
  58. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/push_all.py +0 -0
  59. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/register.py +0 -0
  60. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/registry/__init__.py +0 -0
  61. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/registry/add.py +0 -0
  62. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/registry/fetch.py +0 -0
  63. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/registry/login.py +0 -0
  64. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/registry/logout.py +0 -0
  65. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/registry/publish.py +0 -0
  66. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/registry/push.py +0 -0
  67. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/registry/registration.py +0 -0
  68. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/registry/settings.py +0 -0
  69. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/registry/utils.py +0 -0
  70. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/remove.py +0 -0
  71. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/remove_key.py +0 -0
  72. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/reset_password.py +0 -0
  73. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/run.py +0 -0
  74. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/search.py +0 -0
  75. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/test.py +0 -0
  76. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/transfer.py +0 -0
  77. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/upgrade.py +0 -0
  78. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/utils/__init__.py +0 -0
  79. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/utils/click_utils.py +0 -0
  80. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/utils/config.py +0 -0
  81. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/utils/constants.py +0 -0
  82. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/utils/context.py +0 -0
  83. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/utils/decorators.py +0 -0
  84. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/utils/exceptions.py +0 -0
  85. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/utils/formatting.py +0 -0
  86. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/utils/generic.py +0 -0
  87. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/utils/loggers.py +0 -0
  88. {open_aea-2.2.6 → open_aea-2.2.7}/aea/cli/utils/package_utils.py +0 -0
  89. {open_aea-2.2.6 → open_aea-2.2.7}/aea/common.py +0 -0
  90. {open_aea-2.2.6 → open_aea-2.2.7}/aea/components/__init__.py +0 -0
  91. {open_aea-2.2.6 → open_aea-2.2.7}/aea/components/base.py +0 -0
  92. {open_aea-2.2.6 → open_aea-2.2.7}/aea/components/loader.py +0 -0
  93. {open_aea-2.2.6 → open_aea-2.2.7}/aea/components/utils.py +0 -0
  94. {open_aea-2.2.6 → open_aea-2.2.7}/aea/configurations/__init__.py +0 -0
  95. {open_aea-2.2.6 → open_aea-2.2.7}/aea/configurations/base.py +0 -0
  96. {open_aea-2.2.6 → open_aea-2.2.7}/aea/configurations/constants.py +0 -0
  97. {open_aea-2.2.6 → open_aea-2.2.7}/aea/configurations/data_types.py +0 -0
  98. {open_aea-2.2.6 → open_aea-2.2.7}/aea/configurations/manager.py +0 -0
  99. {open_aea-2.2.6 → open_aea-2.2.7}/aea/configurations/pypi.py +0 -0
  100. {open_aea-2.2.6 → open_aea-2.2.7}/aea/configurations/schemas/aea-config_schema.json +0 -0
  101. {open_aea-2.2.6 → open_aea-2.2.7}/aea/configurations/schemas/cli_config.json +0 -0
  102. {open_aea-2.2.6 → open_aea-2.2.7}/aea/configurations/schemas/configurable_parts/base-custom_config.json +0 -0
  103. {open_aea-2.2.6 → open_aea-2.2.7}/aea/configurations/schemas/configurable_parts/connection-custom_config.json +0 -0
  104. {open_aea-2.2.6 → open_aea-2.2.7}/aea/configurations/schemas/configurable_parts/contract-custom_config.json +0 -0
  105. {open_aea-2.2.6 → open_aea-2.2.7}/aea/configurations/schemas/configurable_parts/protocol-custom_config.json +0 -0
  106. {open_aea-2.2.6 → open_aea-2.2.7}/aea/configurations/schemas/configurable_parts/skill-custom_config.json +0 -0
  107. {open_aea-2.2.6 → open_aea-2.2.7}/aea/configurations/schemas/connection-config_schema.json +0 -0
  108. {open_aea-2.2.6 → open_aea-2.2.7}/aea/configurations/schemas/contract-config_schema.json +0 -0
  109. {open_aea-2.2.6 → open_aea-2.2.7}/aea/configurations/schemas/custom-config_schema.json +0 -0
  110. {open_aea-2.2.6 → open_aea-2.2.7}/aea/configurations/schemas/definitions.json +0 -0
  111. {open_aea-2.2.6 → open_aea-2.2.7}/aea/configurations/schemas/protocol-config_schema.json +0 -0
  112. {open_aea-2.2.6 → open_aea-2.2.7}/aea/configurations/schemas/protocol-specification_schema.json +0 -0
  113. {open_aea-2.2.6 → open_aea-2.2.7}/aea/configurations/schemas/skill-config_schema.json +0 -0
  114. {open_aea-2.2.6 → open_aea-2.2.7}/aea/configurations/validation.py +0 -0
  115. {open_aea-2.2.6 → open_aea-2.2.7}/aea/connections/__init__.py +0 -0
  116. {open_aea-2.2.6 → open_aea-2.2.7}/aea/connections/scaffold/__init__.py +0 -0
  117. {open_aea-2.2.6 → open_aea-2.2.7}/aea/connections/scaffold/connection.py +0 -0
  118. {open_aea-2.2.6 → open_aea-2.2.7}/aea/connections/scaffold/connection.yaml +0 -0
  119. {open_aea-2.2.6 → open_aea-2.2.7}/aea/connections/scaffold/readme.md +0 -0
  120. {open_aea-2.2.6 → open_aea-2.2.7}/aea/context/__init__.py +0 -0
  121. {open_aea-2.2.6 → open_aea-2.2.7}/aea/context/base.py +0 -0
  122. {open_aea-2.2.6 → open_aea-2.2.7}/aea/contracts/__init__.py +0 -0
  123. {open_aea-2.2.6 → open_aea-2.2.7}/aea/contracts/scaffold/__init__.py +0 -0
  124. {open_aea-2.2.6 → open_aea-2.2.7}/aea/contracts/scaffold/contract.py +0 -0
  125. {open_aea-2.2.6 → open_aea-2.2.7}/aea/contracts/scaffold/contract.yaml +0 -0
  126. {open_aea-2.2.6 → open_aea-2.2.7}/aea/crypto/__init__.py +0 -0
  127. {open_aea-2.2.6 → open_aea-2.2.7}/aea/crypto/base.py +0 -0
  128. {open_aea-2.2.6 → open_aea-2.2.7}/aea/crypto/helpers.py +0 -0
  129. {open_aea-2.2.6 → open_aea-2.2.7}/aea/crypto/ledger_apis.py +0 -0
  130. {open_aea-2.2.6 → open_aea-2.2.7}/aea/crypto/plugin.py +0 -0
  131. {open_aea-2.2.6 → open_aea-2.2.7}/aea/crypto/registries/__init__.py +0 -0
  132. {open_aea-2.2.6 → open_aea-2.2.7}/aea/crypto/registries/base.py +0 -0
  133. {open_aea-2.2.6 → open_aea-2.2.7}/aea/crypto/wallet.py +0 -0
  134. {open_aea-2.2.6 → open_aea-2.2.7}/aea/customs/__init__.py +0 -0
  135. {open_aea-2.2.6 → open_aea-2.2.7}/aea/customs/scaffold/__init__.py +0 -0
  136. {open_aea-2.2.6 → open_aea-2.2.7}/aea/customs/scaffold/component.yaml +0 -0
  137. {open_aea-2.2.6 → open_aea-2.2.7}/aea/decision_maker/__init__.py +0 -0
  138. {open_aea-2.2.6 → open_aea-2.2.7}/aea/decision_maker/base.py +0 -0
  139. {open_aea-2.2.6 → open_aea-2.2.7}/aea/decision_maker/default.py +0 -0
  140. {open_aea-2.2.6 → open_aea-2.2.7}/aea/decision_maker/scaffold.py +0 -0
  141. {open_aea-2.2.6 → open_aea-2.2.7}/aea/error_handler/__init__.py +0 -0
  142. {open_aea-2.2.6 → open_aea-2.2.7}/aea/error_handler/base.py +0 -0
  143. {open_aea-2.2.6 → open_aea-2.2.7}/aea/error_handler/default.py +0 -0
  144. {open_aea-2.2.6 → open_aea-2.2.7}/aea/error_handler/scaffold.py +0 -0
  145. {open_aea-2.2.6 → open_aea-2.2.7}/aea/exceptions.py +0 -0
  146. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/__init__.py +0 -0
  147. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/acn/__init__.py +0 -0
  148. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/acn/agent_record.py +0 -0
  149. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/acn/uri.py +0 -0
  150. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/async_friendly_queue.py +0 -0
  151. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/async_utils.py +0 -0
  152. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/cid.py +0 -0
  153. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/constants.py +0 -0
  154. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/dependency_tree.py +0 -0
  155. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/exception_policy.py +0 -0
  156. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/exec_timeout.py +0 -0
  157. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/file_io.py +0 -0
  158. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/file_lock.py +0 -0
  159. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/fingerprint.py +0 -0
  160. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/git.py +0 -0
  161. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/http_requests.py +0 -0
  162. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/install_dependency.py +0 -0
  163. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/io.py +0 -0
  164. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/ipfs/__init__.py +0 -0
  165. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/ipfs/base.py +0 -0
  166. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/ipfs/pb/__init__.py +0 -0
  167. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/ipfs/pb/merkledag.proto +0 -0
  168. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/ipfs/pb/merkledag_pb2.py +0 -0
  169. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/ipfs/pb/unixfs.proto +0 -0
  170. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/ipfs/pb/unixfs_pb2.py +0 -0
  171. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/ipfs/utils.py +0 -0
  172. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/json_schema.py +0 -0
  173. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/multiaddr/__init__.py +0 -0
  174. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/multiaddr/base.py +0 -0
  175. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/multiaddr/crypto.proto +0 -0
  176. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/multiaddr/crypto_pb2.py +0 -0
  177. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/multiformat.py +0 -0
  178. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/multiformat_codecs.py +0 -0
  179. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/multiple_executor.py +0 -0
  180. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/pipe.py +0 -0
  181. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/preference_representations/__init__.py +0 -0
  182. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/preference_representations/base.py +0 -0
  183. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/profiler_type_black_list.py +0 -0
  184. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/profiling.py +0 -0
  185. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/search/__init__.py +0 -0
  186. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/search/generic.py +0 -0
  187. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/search/models.proto +0 -0
  188. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/search/models.py +0 -0
  189. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/search/models_pb2.py +0 -0
  190. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/secp256k1.py +0 -0
  191. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/serializers.py +0 -0
  192. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/storage/__init__.py +0 -0
  193. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/storage/backends/__init__.py +0 -0
  194. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/storage/backends/base.py +0 -0
  195. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/storage/backends/binaries/README.txt +0 -0
  196. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/storage/backends/binaries/json1.dll +0 -0
  197. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/storage/backends/sqlite.py +0 -0
  198. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/storage/generic_storage.py +0 -0
  199. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/sym_link.py +0 -0
  200. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/transaction/__init__.py +0 -0
  201. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/transaction/base.py +0 -0
  202. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/win32.py +0 -0
  203. {open_aea-2.2.6 → open_aea-2.2.7}/aea/helpers/yaml_utils.py +0 -0
  204. {open_aea-2.2.6 → open_aea-2.2.7}/aea/identity/__init__.py +0 -0
  205. {open_aea-2.2.6 → open_aea-2.2.7}/aea/identity/base.py +0 -0
  206. {open_aea-2.2.6 → open_aea-2.2.7}/aea/launcher.py +0 -0
  207. {open_aea-2.2.6 → open_aea-2.2.7}/aea/mail/__init__.py +0 -0
  208. {open_aea-2.2.6 → open_aea-2.2.7}/aea/mail/base.proto +0 -0
  209. {open_aea-2.2.6 → open_aea-2.2.7}/aea/mail/base.py +0 -0
  210. {open_aea-2.2.6 → open_aea-2.2.7}/aea/mail/base_pb2.py +0 -0
  211. {open_aea-2.2.6 → open_aea-2.2.7}/aea/manager/__init__.py +0 -0
  212. {open_aea-2.2.6 → open_aea-2.2.7}/aea/manager/helpers.py +0 -0
  213. {open_aea-2.2.6 → open_aea-2.2.7}/aea/manager/manager.py +0 -0
  214. {open_aea-2.2.6 → open_aea-2.2.7}/aea/manager/project.py +0 -0
  215. {open_aea-2.2.6 → open_aea-2.2.7}/aea/manager/utils.py +0 -0
  216. {open_aea-2.2.6 → open_aea-2.2.7}/aea/multiplexer.py +0 -0
  217. {open_aea-2.2.6 → open_aea-2.2.7}/aea/package_manager/__init__.py +0 -0
  218. {open_aea-2.2.6 → open_aea-2.2.7}/aea/package_manager/base.py +0 -0
  219. {open_aea-2.2.6 → open_aea-2.2.7}/aea/package_manager/v0.py +0 -0
  220. {open_aea-2.2.6 → open_aea-2.2.7}/aea/package_manager/v1.py +0 -0
  221. {open_aea-2.2.6 → open_aea-2.2.7}/aea/protocols/__init__.py +0 -0
  222. {open_aea-2.2.6 → open_aea-2.2.7}/aea/protocols/base.py +0 -0
  223. {open_aea-2.2.6 → open_aea-2.2.7}/aea/protocols/dialogue/__init__.py +0 -0
  224. {open_aea-2.2.6 → open_aea-2.2.7}/aea/protocols/dialogue/base.py +0 -0
  225. {open_aea-2.2.6 → open_aea-2.2.7}/aea/protocols/generator/__init__.py +0 -0
  226. {open_aea-2.2.6 → open_aea-2.2.7}/aea/protocols/generator/base.py +0 -0
  227. {open_aea-2.2.6 → open_aea-2.2.7}/aea/protocols/generator/common.py +0 -0
  228. {open_aea-2.2.6 → open_aea-2.2.7}/aea/protocols/generator/extract_specification.py +0 -0
  229. {open_aea-2.2.6 → open_aea-2.2.7}/aea/protocols/generator/isort.cfg +0 -0
  230. {open_aea-2.2.6 → open_aea-2.2.7}/aea/protocols/generator/validate.py +0 -0
  231. {open_aea-2.2.6 → open_aea-2.2.7}/aea/protocols/scaffold/__init__.py +0 -0
  232. {open_aea-2.2.6 → open_aea-2.2.7}/aea/protocols/scaffold/message.py +0 -0
  233. {open_aea-2.2.6 → open_aea-2.2.7}/aea/protocols/scaffold/protocol.yaml +0 -0
  234. {open_aea-2.2.6 → open_aea-2.2.7}/aea/protocols/scaffold/serialization.py +0 -0
  235. {open_aea-2.2.6 → open_aea-2.2.7}/aea/py.typed +0 -0
  236. {open_aea-2.2.6 → open_aea-2.2.7}/aea/registries/__init__.py +0 -0
  237. {open_aea-2.2.6 → open_aea-2.2.7}/aea/registries/base.py +0 -0
  238. {open_aea-2.2.6 → open_aea-2.2.7}/aea/registries/filter.py +0 -0
  239. {open_aea-2.2.6 → open_aea-2.2.7}/aea/registries/resources.py +0 -0
  240. {open_aea-2.2.6 → open_aea-2.2.7}/aea/runner.py +0 -0
  241. {open_aea-2.2.6 → open_aea-2.2.7}/aea/runtime.py +0 -0
  242. {open_aea-2.2.6 → open_aea-2.2.7}/aea/skills/__init__.py +0 -0
  243. {open_aea-2.2.6 → open_aea-2.2.7}/aea/skills/behaviours.py +0 -0
  244. {open_aea-2.2.6 → open_aea-2.2.7}/aea/skills/scaffold/__init__.py +0 -0
  245. {open_aea-2.2.6 → open_aea-2.2.7}/aea/skills/scaffold/behaviours.py +0 -0
  246. {open_aea-2.2.6 → open_aea-2.2.7}/aea/skills/scaffold/handlers.py +0 -0
  247. {open_aea-2.2.6 → open_aea-2.2.7}/aea/skills/scaffold/my_model.py +0 -0
  248. {open_aea-2.2.6 → open_aea-2.2.7}/aea/skills/scaffold/skill.yaml +0 -0
  249. {open_aea-2.2.6 → open_aea-2.2.7}/aea/skills/tasks.py +0 -0
  250. {open_aea-2.2.6 → open_aea-2.2.7}/aea/test_tools/__init__.py +0 -0
  251. {open_aea-2.2.6 → open_aea-2.2.7}/aea/test_tools/click_testing.py +0 -0
  252. {open_aea-2.2.6 → open_aea-2.2.7}/aea/test_tools/constants.py +0 -0
  253. {open_aea-2.2.6 → open_aea-2.2.7}/aea/test_tools/docker_image.py +0 -0
  254. {open_aea-2.2.6 → open_aea-2.2.7}/aea/test_tools/exceptions.py +0 -0
  255. {open_aea-2.2.6 → open_aea-2.2.7}/aea/test_tools/generic.py +0 -0
  256. {open_aea-2.2.6 → open_aea-2.2.7}/aea/test_tools/mocks.py +0 -0
  257. {open_aea-2.2.6 → open_aea-2.2.7}/aea/test_tools/network.py +0 -0
  258. {open_aea-2.2.6 → open_aea-2.2.7}/aea/test_tools/test_cases.py +0 -0
  259. {open_aea-2.2.6 → open_aea-2.2.7}/aea/test_tools/test_contract.py +0 -0
  260. {open_aea-2.2.6 → open_aea-2.2.7}/aea/test_tools/test_protocol.py +0 -0
  261. {open_aea-2.2.6 → open_aea-2.2.7}/aea/test_tools/test_skill.py +0 -0
  262. {open_aea-2.2.6 → open_aea-2.2.7}/aea/test_tools/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: open-aea
3
- Version: 2.2.6
3
+ Version: 2.2.7
4
4
  Summary: Open AEA Framework
5
5
  License: Apache-2.0
6
6
  License-File: AUTHORS.md
@@ -23,7 +23,7 @@
23
23
  __title__ = "open-aea"
24
24
  __description__ = "Open Autonomous Economic Agent framework (without vendor lock-in)"
25
25
  __url__ = "https://github.com/valory-xyz/open-aea.git"
26
- __version__ = "2.2.6"
26
+ __version__ = "2.2.7"
27
27
  __author__ = "Valory AG"
28
28
  __license__ = "Apache-2.0"
29
29
  __copyright__ = "2021 Valory AG, 2019 Fetch.AI Limited"
@@ -66,7 +66,6 @@ LIBPROTOC_VERSION = "libprotoc 24.3"
66
66
  CUSTOM_TYPE_MODULE_NAME = "custom_types.py"
67
67
  PROTOCOL_GENERATOR_DOCSTRING_REGEX = "It was created with protocol buffer compiler version `libprotoc .*` and aea protocol generator version `.*`."
68
68
 
69
- logging.basicConfig(format="[%(asctime)s][%(levelname)s] %(message)s")
70
69
  logger = logging.getLogger("generate_all_protocols")
71
70
  logger.setLevel(logging.INFO)
72
71
 
@@ -460,6 +459,7 @@ def generate_all_protocols(
460
459
  check_clean: bool,
461
460
  ) -> None:
462
461
  """Generate all protocols."""
462
+ logging.basicConfig(format="[%(asctime)s][%(levelname)s] %(message)s")
463
463
 
464
464
  _check_preliminaries()
465
465
 
@@ -244,6 +244,9 @@ def scaffold_item(ctx: Context, item_type: str, item_name: str) -> None:
244
244
  )
245
245
 
246
246
  ctx.clean_paths.append(str(dest))
247
+ # Save ctx.cwd so the local-registry path swap below does not leak out
248
+ # of this call.
249
+ preserve_cwd = ctx.cwd
247
250
  try:
248
251
  # copy the item package into the agent project.
249
252
  src = Path(os.path.join(AEA_DIR, item_type_plural, "scaffold"))
@@ -283,6 +286,12 @@ def scaffold_item(ctx: Context, item_type: str, item_name: str) -> None:
283
286
  if to_local_registry:
284
287
  ctx.cwd = str(registry_path / author_name)
285
288
  fingerprint_item(ctx, item_type, new_public_id)
289
+ # Restore now (not just in the `finally` below) so the
290
+ # `--with-symlinks` calls to `create_symlink_vendor_to_local` /
291
+ # `create_symlink_packages_to_vendor` further down — both of
292
+ # which read `ctx.cwd` — see the original agent directory
293
+ # instead of the registry author path.
294
+ ctx.cwd = preserve_cwd
286
295
  else:
287
296
  fingerprint_item(ctx, item_type, new_public_id)
288
297
 
@@ -314,6 +323,8 @@ def scaffold_item(ctx: Context, item_type: str, item_name: str) -> None:
314
323
  )
315
324
  except Exception as e:
316
325
  raise click.ClickException(str(e))
326
+ finally:
327
+ ctx.cwd = preserve_cwd
317
328
 
318
329
 
319
330
  def _scaffold_dm_handler(ctx: Context) -> None:
@@ -29,6 +29,7 @@ from typing import (
29
29
  List,
30
30
  Optional,
31
31
  TextIO,
32
+ Tuple,
32
33
  Type,
33
34
  TypeVar,
34
35
  Union,
@@ -320,11 +321,7 @@ class ConfigLoader(Generic[T], BaseConfigLoader):
320
321
 
321
322
  def _load_service_config(self, file_pointer: TextIO) -> PackageConfiguration:
322
323
  """Load a service configuration."""
323
- configuration_data = yaml_load_all(file_pointer)
324
- if not configuration_data:
325
- raise ValueError("Service configuration file was empty.")
326
-
327
- service_config, *overrides = configuration_data
324
+ service_config, overrides = parse_service_yaml(file_pointer)
328
325
  self.validate(service_config)
329
326
  key_order = list(service_config.keys())
330
327
  service = self.configuration_class.from_json(service_config)
@@ -384,6 +381,44 @@ class ConfigLoader(Generic[T], BaseConfigLoader):
384
381
  return component_id
385
382
 
386
383
 
384
+ def parse_service_yaml(
385
+ file_pointer: TextIO,
386
+ ) -> Tuple[Dict[str, Any], List[Dict[str, Any]]]:
387
+ """
388
+ Parse a service configuration YAML stream into its raw documents.
389
+
390
+ Returns the head service configuration document and any override
391
+ documents without applying schema validation or constructing a
392
+ typed configuration object. Callers that need to apply additional
393
+ transformations (e.g. environment variable substitution) before
394
+ validation can use this helper as the parse step.
395
+
396
+ :param file_pointer: an open text stream pointing at a service.yaml.
397
+ :return: a ``(service_config, overrides)`` tuple where ``service_config``
398
+ is the head document and ``overrides`` is the list of trailing
399
+ documents.
400
+ :raises ValueError: if the stream is empty, or if the head document is
401
+ not a YAML mapping (e.g. a bare ``---``, a scalar, or a sequence).
402
+ :raises yaml.YAMLError: if the stream contains malformed YAML and the underlying parser fails (propagated as-is so callers can handle parse errors and shape errors distinctly). # noqa: DAR402
403
+ """
404
+ configuration_data = yaml_load_all(file_pointer)
405
+ if not configuration_data:
406
+ raise ValueError("Service configuration file was empty.")
407
+ service_config, *overrides = configuration_data
408
+ # The head document must be a mapping. `yaml_load_all` happily returns
409
+ # `[None]` / `[False]` / `[0]` / `[""]` / `[[]]` for malformed YAML
410
+ # (bare `---`, a scalar, a sequence, etc.) — surface those at parse
411
+ # time rather than as opaque AttributeErrors from the downstream
412
+ # validator. Distinct from the empty-stream message so an operator
413
+ # reading the traceback can tell the two cases apart.
414
+ if not isinstance(service_config, dict):
415
+ raise ValueError(
416
+ "Service configuration head document must be a YAML mapping, "
417
+ f"got {type(service_config).__name__}."
418
+ )
419
+ return service_config, overrides
420
+
421
+
387
422
  class ConfigLoaders:
388
423
  """Configuration Loader class to load any package type."""
389
424
 
@@ -34,9 +34,34 @@ from aea.configurations.base import (
34
34
  PublicId,
35
35
  SkillConfig,
36
36
  )
37
+ from aea.configurations.constants import PACKAGES
37
38
  from aea.configurations.data_types import PackageIdPrefix
38
39
 
39
40
 
41
+ def package_dotted_path(
42
+ author: str,
43
+ package_type_plural: str,
44
+ package_name: str,
45
+ file_stem: str,
46
+ ) -> str:
47
+ """
48
+ Compose the canonical dotted path string for a file inside an AEA package.
49
+
50
+ Returns a string of the form ``packages.<author>.<plural>.<name>.<stem>``.
51
+ Has no side effects; the loaded module is registered in
52
+ ``sys.modules`` by ``aea.helpers.base.load_module``.
53
+
54
+ :param author: package author (e.g. ``"valory"``).
55
+ :param package_type_plural: plural package-type token (``"skills"`` /
56
+ ``"contracts"`` / ``"connections"`` / ``"protocols"``).
57
+ :param package_name: the package's local name.
58
+ :param file_stem: source file stem without the ``.py`` suffix
59
+ (``"contract"`` / ``"connection"`` / ``"behaviours"`` / ...).
60
+ :return: the composed packages-prefixed dotted path string.
61
+ """
62
+ return f"{PACKAGES}.{author}.{package_type_plural}.{package_name}.{file_stem}"
63
+
64
+
40
65
  @singledispatch
41
66
  def replace_component_ids(
42
67
  _arg: PackageConfiguration,
@@ -30,8 +30,10 @@ from typing import Any, Callable, Generator, Optional, Set, TYPE_CHECKING, cast
30
30
 
31
31
  from aea.components.base import Component, load_aea_package
32
32
  from aea.configurations.base import ComponentType, ConnectionConfig
33
+ from aea.configurations.constants import CONNECTIONS
33
34
  from aea.configurations.data_types import PublicId
34
35
  from aea.configurations.loader import load_component_configuration
36
+ from aea.configurations.utils import package_dotted_path
35
37
  from aea.crypto.wallet import CryptoStore
36
38
  from aea.exceptions import (
37
39
  AEAComponentLoadException,
@@ -284,9 +286,13 @@ class Connection(Component, ABC):
284
286
  "Connection module '{}' not found.".format(connection_module_path)
285
287
  )
286
288
  load_aea_package(configuration)
287
- connection_module = load_module(
288
- "connection_module", directory / "connection.py"
289
+ dotted_path = package_dotted_path(
290
+ configuration.public_id.author,
291
+ CONNECTIONS,
292
+ configuration.public_id.name,
293
+ "connection",
289
294
  )
295
+ connection_module = load_module(dotted_path, directory / "connection.py")
290
296
  classes = inspect.getmembers(connection_module, inspect.isclass)
291
297
  connection_class_name = cast(str, configuration.class_name)
292
298
  connection_classes = list(
@@ -30,6 +30,7 @@ from aea.components.base import Component, load_aea_package
30
30
  from aea.configurations.base import ComponentType, ContractConfig, PublicId
31
31
  from aea.configurations.constants import CONTRACTS
32
32
  from aea.configurations.loader import load_component_configuration
33
+ from aea.configurations.utils import package_dotted_path
33
34
  from aea.crypto.base import LedgerApi
34
35
  from aea.crypto.registries import Registry, ledger_apis_registry, make_ledger_api_cls
35
36
  from aea.exceptions import AEAComponentLoadException, AEAException
@@ -123,7 +124,13 @@ class Contract(Component):
123
124
  raise ValueError("Configuration must be associated with a directory.")
124
125
  directory = configuration.directory
125
126
  load_aea_package(configuration)
126
- contract_module = load_module(CONTRACTS, directory / "contract.py")
127
+ dotted_path = package_dotted_path(
128
+ configuration.public_id.author,
129
+ CONTRACTS,
130
+ configuration.public_id.name,
131
+ "contract",
132
+ )
133
+ contract_module = load_module(dotted_path, directory / "contract.py")
127
134
  classes = inspect.getmembers(contract_module, inspect.isclass)
128
135
  contract_class_name = cast(str, configuration.class_name)
129
136
  contract_classes = list(filter(lambda x: x[0] == contract_class_name, classes))
@@ -127,9 +127,37 @@ def load_module(dotted_path: str, filepath: Path) -> types.ModuleType:
127
127
  :raises ValueError: if the filepath provided is not a module. # noqa: DAR402
128
128
  :raises Exception: if the execution of the module raises exception. # noqa: DAR402
129
129
  """
130
+ # If the dotted path is already in ``sys.modules``, reuse it instead
131
+ # of re-executing the file. Re-execution creates a duplicate copy of
132
+ # every class defined in the source, breaking class identity for
133
+ # callers that already hold a reference (e.g. via an earlier
134
+ # ``from ... import X``). ``__file__`` is intentionally NOT compared
135
+ # — in test fixtures the same logical package may be reached
136
+ # through different physical files (vendor copy in a tmpdir vs the
137
+ # source tree) but both register the same dotted path and must
138
+ # resolve to the same module object across the whole process. An
139
+ # explicit ``None`` entry is CPython's block-import sentinel: raise
140
+ # ``ImportError`` to match the standard import semantics rather
141
+ # than silently overwriting it with a fresh exec.
142
+ if dotted_path in sys.modules:
143
+ existing = sys.modules[dotted_path]
144
+ if existing is None:
145
+ raise ImportError(f"import of {dotted_path!r} halted; None in sys.modules")
146
+ return existing
130
147
  spec = importlib.util.spec_from_file_location(dotted_path, str(filepath))
131
148
  module = importlib.util.module_from_spec(cast(ModuleSpec, spec))
132
- spec.loader.exec_module(module) # type: ignore
149
+ # Register before exec so a downstream `import` of the same dotted
150
+ # path during exec resolves to this module. We only reach this point
151
+ # when the key was absent (the cache-hit and block-import branches
152
+ # above covered the other two cases), so on exec failure we pop the
153
+ # half-built stub rather than restoring a prior entry that, by
154
+ # construction, did not exist.
155
+ sys.modules[dotted_path] = module
156
+ try:
157
+ spec.loader.exec_module(module) # type: ignore
158
+ except BaseException: # pylint: disable=broad-except
159
+ sys.modules.pop(dotted_path, None)
160
+ raise
133
161
  return module
134
162
 
135
163
 
@@ -21,6 +21,7 @@
21
21
  """Implementation of the environment variables support."""
22
22
 
23
23
  import json
24
+ import logging
24
25
  import re
25
26
  from collections.abc import Mapping as MappingType
26
27
  from typing import Any, Dict, List, Mapping, Optional, Tuple, Union, cast
@@ -33,6 +34,8 @@ from aea.helpers.constants import (
33
34
  NULL_EQUIVALENTS,
34
35
  )
35
36
 
37
+ _logger = logging.getLogger(__name__)
38
+
36
39
  ENV_VARIABLE_RE = re.compile(r"^\$\{(([A-Z0-9_]+):?)?([a-z]+)?(:(.+))?}$")
37
40
  MODELS = "models"
38
41
  ARGS = "args"
@@ -272,6 +275,30 @@ def is_strict_list(data: Union[List, Tuple]) -> bool:
272
275
  return is_strict
273
276
 
274
277
 
278
+ _BASH_SAFE_KEY_RE = re.compile(r"^[A-Za-z_][A-Za-z0-9_]*$")
279
+
280
+
281
+ def has_env_safe_keys(data: dict) -> bool:
282
+ """
283
+ Check if a dict can be safely flattened into per-key env vars.
284
+
285
+ Returns True only when every key is a string matching the bash
286
+ identifier rule `[A-Za-z_][A-Za-z0-9_]*`. An empty dict is
287
+ vacuously safe (True). When this returns False, flattening would
288
+ produce env var names that bash refuses to set (notably containing
289
+ `.`), so callers should JSON-encode the whole dict as a single env
290
+ var instead.
291
+
292
+ For example, `{"timeout": 30, "retries": 5}` returns True; while
293
+ `{"0.0": 0, "1.0": 100}` and `{1: "v"}` return False.
294
+
295
+ :param data: Data dict
296
+ :return: True if every key is a valid bash identifier, or the
297
+ dict is empty.
298
+ """
299
+ return all(isinstance(k, str) and _BASH_SAFE_KEY_RE.match(k) for k in data)
300
+
301
+
275
302
  def list_to_nested_dict(lst: list, val: Any) -> dict:
276
303
  """Convert a list to a nested dict."""
277
304
  nested_dict = val
@@ -280,6 +307,37 @@ def list_to_nested_dict(lst: list, val: Any) -> dict:
280
307
  return nested_dict
281
308
 
282
309
 
310
+ def _encode_as_json_env_var(
311
+ data: JSON_TYPES, export_path: List[str]
312
+ ) -> Tuple[str, str]:
313
+ """
314
+ Encode data as a single JSON-string env var.
315
+
316
+ Used when a value cannot be flattened per-leaf (e.g. a list with
317
+ non-scalar elements, or a dict with bash-unsafe keys). Honours
318
+ `restrict_model_args`: if the export path is truncated by the model
319
+ arg restriction, the data is nested under the restricted suffix
320
+ (the deeper path keys) before encoding so they are not lost.
321
+
322
+ :param data: JSON-encodable value to encode.
323
+ :param export_path: Path keys leading to the value, from
324
+ `generate_env_vars_recursively`.
325
+ :return: (env_var_name, json_value) pair.
326
+ :raises ValueError: if ``data`` contains a value ``json.dumps`` cannot
327
+ serialise. The export path is included in the message so the
328
+ operator can locate the offending config key.
329
+ """
330
+ restricted, path = export_path_to_env_var_string(export_path=export_path)
331
+ payload = list_to_nested_dict(restricted, data) if restricted else data
332
+ try:
333
+ encoded = json.dumps(payload, separators=(",", ":"))
334
+ except TypeError as e:
335
+ raise ValueError(
336
+ f"Cannot JSON-encode value at export path {export_path}: {e}"
337
+ ) from e
338
+ return path, encoded
339
+
340
+
283
341
  def ensure_dict(dict_: Dict[str, Union[dict, str]]) -> dict:
284
342
  """Return the given dictionary converting any values which are json strings as dicts."""
285
343
  return {k: json.loads(v) for k, v in dict_.items() if isinstance(v, str)}
@@ -312,6 +370,26 @@ def generate_env_vars_recursively(
312
370
  env_var_dict: Dict[str, Any] = {}
313
371
 
314
372
  if isinstance(data, dict):
373
+ if not has_env_safe_keys(data):
374
+ safe_keys = [
375
+ k for k in data if isinstance(k, str) and _BASH_SAFE_KEY_RE.match(k)
376
+ ]
377
+ if safe_keys:
378
+ # Mixed-key dict: per-key env var overrides for the safe
379
+ # keys silently stop applying once the whole dict is
380
+ # JSON-encoded. Warn so the operator can see why their
381
+ # override does not take effect.
382
+ _logger.warning(
383
+ "Collapsing mixed-key dict at export path %s to a "
384
+ "single JSON env var because of bash-unsafe keys; "
385
+ "per-key overrides for safe keys %s will no longer "
386
+ "apply. Set the whole-dict env var instead.",
387
+ export_path,
388
+ safe_keys,
389
+ )
390
+ path, value = _encode_as_json_env_var(data, export_path)
391
+ env_var_dict[path] = value
392
+ return env_var_dict
315
393
  for key, value in data.items():
316
394
  res = generate_env_vars_recursively(
317
395
  data=value,
@@ -325,11 +403,8 @@ def generate_env_vars_recursively(
325
403
  env_var_dict.update(res)
326
404
  elif isinstance(data, list):
327
405
  if is_strict_list(data=data):
328
- restricted, path = export_path_to_env_var_string(export_path=export_path)
329
- if restricted:
330
- env_var_dict[path] = json.dumps(list_to_nested_dict(restricted, data))
331
- else:
332
- env_var_dict[path] = json.dumps(data, separators=(",", ":"))
406
+ path, value = _encode_as_json_env_var(data, export_path)
407
+ env_var_dict[path] = value
333
408
  else:
334
409
  for key, value in enumerate(data):
335
410
  res = generate_env_vars_recursively(
@@ -340,7 +415,9 @@ def generate_env_vars_recursively(
340
415
  else:
341
416
  restricted, path = export_path_to_env_var_string(export_path=export_path)
342
417
  if restricted:
343
- env_var_dict[path] = json.dumps(list_to_nested_dict(restricted, data))
418
+ env_var_dict[path] = json.dumps(
419
+ list_to_nested_dict(restricted, data), separators=(",", ":")
420
+ )
344
421
  else:
345
422
  env_var_dict[path] = data
346
423
 
@@ -31,7 +31,21 @@ DEFAULT_FORMAT = "[%(asctime)s][%(levelname)s] %(message)s"
31
31
  def setup_logger(
32
32
  name: str, level: int = logging.INFO, log_format: str = DEFAULT_FORMAT
33
33
  ) -> Logger:
34
- """Set up the logger."""
34
+ """Set up the logger.
35
+
36
+ Kept as a public helper for downstream consumers outside this repo;
37
+ new in-repo callers should prefer ``logging.getLogger(name)`` and set
38
+ the level directly. Calling ``logging.basicConfig`` at module-import
39
+ time pollutes the root logger and was the cause of the duplicate-log
40
+ bug fixed in #914 (PR #917).
41
+
42
+ :param name: logger name.
43
+ :param level: log level applied to the returned logger.
44
+ :param log_format: format string passed to ``logging.basicConfig``.
45
+ Only takes effect on the first call when the root logger has no
46
+ handlers yet; subsequent calls are a no-op for the format.
47
+ :return: the configured logger.
48
+ """
35
49
  logging.basicConfig(format=log_format)
36
50
  logger = logging.getLogger(name)
37
51
  logger.setLevel(level)
@@ -19,20 +19,21 @@
19
19
 
20
20
  """Protocol helpers."""
21
21
 
22
+ import logging
22
23
  import re
23
24
  from pathlib import Path
24
25
  from typing import Match, cast
25
26
 
26
27
  from aea.configurations.loader import load_protocol_specification_from_string
27
28
  from aea.exceptions import enforce
28
- from aea.helpers.logging import setup_logger
29
29
 
30
30
  SPECIFICATION_REGEX = re.compile(r"(---\nname.*\.\.\.)", re.DOTALL)
31
31
  PROTOCOL_SPECIFICATION_ID_IN_SPECIFICATION_REGEX = re.compile(
32
32
  "^protocol_specification_id: (.*)$", re.MULTILINE
33
33
  )
34
34
 
35
- _logger = setup_logger(__name__)
35
+ _logger = logging.getLogger(__name__)
36
+ _logger.setLevel(logging.INFO)
36
37
 
37
38
 
38
39
  def get_protocol_specification_from_readme(package_path: Path) -> str:
@@ -41,7 +41,9 @@ from aea.configurations.base import (
41
41
  SkillComponentConfiguration,
42
42
  SkillConfig,
43
43
  )
44
+ from aea.configurations.constants import SKILLS
44
45
  from aea.configurations.loader import load_component_configuration
46
+ from aea.configurations.utils import package_dotted_path
45
47
  from aea.context.base import AgentContext
46
48
  from aea.exceptions import (
47
49
  AEAActException,
@@ -759,17 +761,44 @@ def _parse_module(
759
761
  if component_configs == {}:
760
762
  return components
761
763
  component_names = set(config.class_name for _, config in component_configs.items())
762
- component_module = load_module(component_type_name_plural, Path(path))
764
+ # Build the same canonical dotted key the main loader uses for the
765
+ # same physical file (including subpackage files such as
766
+ # `<skill>/subpkg/behaviours.py`) so `sys.modules` cache hits across
767
+ # both load paths. `SkillContext` stores the Skill on the private
768
+ # `_skill` attribute (no public `skill` property — see the
769
+ # ``self._skill_context._skill = self`` assignment in ``Skill.__init__``),
770
+ # so we walk that explicitly. The `relative_to` call's narrow
771
+ # exceptions are caught only at the point they can fire.
772
+ file_stem = Path(path).stem
773
+ parent_parts: Tuple[str, ...] = ()
774
+ skill_dir = getattr(
775
+ getattr(getattr(skill_context, "_skill", None), "configuration", None),
776
+ "directory",
777
+ None,
778
+ )
779
+ if skill_dir is not None:
780
+ try:
781
+ relative = Path(path).resolve().relative_to(Path(skill_dir).resolve())
782
+ parent_parts = relative.parent.parts
783
+ except (ValueError, OSError):
784
+ pass
785
+ dotted_path = package_dotted_path(
786
+ skill_context.skill_id.author,
787
+ SKILLS,
788
+ skill_context.skill_id.name,
789
+ ".".join(parent_parts + (file_stem,)),
790
+ )
791
+ component_module = load_module(dotted_path, Path(path))
763
792
  classes = inspect.getmembers(component_module, inspect.isclass)
793
+ # Keep `SkillComponent` subclasses except those provided by the
794
+ # framework (`aea.*`). Cross-skill re-exports (composition idiom)
795
+ # have a `__module__` from another skill, not `aea.`, and are kept
796
+ # by design.
764
797
  component_classes = list(
765
798
  filter(
766
799
  lambda x: x[0] in component_names
767
800
  and issubclass(x[1], component_class)
768
- and not str.startswith(x[1].__module__, "aea.")
769
- and not str.startswith(
770
- x[1].__module__,
771
- f"packages.{skill_context.skill_id.author}.skills.{skill_context.skill_id.name}",
772
- ),
801
+ and not str.startswith(x[1].__module__, "aea."),
773
802
  classes,
774
803
  )
775
804
  )
@@ -924,11 +953,25 @@ class _SkillComponentLoader:
924
953
  )
925
954
  return module_paths
926
955
 
927
- @classmethod
928
- def _compute_module_dotted_path(cls, module_path: Path) -> str:
929
- """Compute the dotted path for a skill module."""
956
+ def _compute_module_dotted_path(self, module_path: Path) -> str:
957
+ """Compute the dotted path for a skill module.
958
+
959
+ ``__init__.py`` files are registered by ``load_aea_package``
960
+ under the parent package's dotted path (no ``.__init__``
961
+ suffix). Return that exact key so ``load_module`` cache-hits
962
+ on the already-loaded module instead of re-executing the file
963
+ (which would create duplicate class objects).
964
+
965
+ :param module_path: the module path, relative to the skill directory.
966
+ :return: the canonical dotted import path for that module.
967
+ """
968
+ if module_path.name == "__init__.py":
969
+ parent_parts = module_path.parent.parts
970
+ if not parent_parts:
971
+ return self.skill_dotted_path
972
+ return f"{self.skill_dotted_path}.{'.'.join(parent_parts)}"
930
973
  suffix = ".".join(module_path.with_name(module_path.stem).parts)
931
- return suffix
974
+ return f"{self.skill_dotted_path}.{suffix}"
932
975
 
933
976
  def _filter_classes(
934
977
  self, classes: List[Tuple[str, Type]]
@@ -937,23 +980,24 @@ class _SkillComponentLoader:
937
980
  Filter classes of skill components.
938
981
 
939
982
  The following filters are applied:
940
- - the class must be a subclass of "SkillComponent";
941
- - its __module__ attribute must not start with 'aea.' (we exclude classes provided by the framework)
942
- - its __module__ attribute starts with the expected dotted path of this skill.
943
- In particular, it should not be imported from another skill.
983
+ - the class must be a subclass of ``SkillComponent``;
984
+ - its ``__module__`` attribute must not start with ``aea.``
985
+ (classes provided by the framework are excluded).
986
+
987
+ Cross-skill re-exports (composition skills binding another skill's
988
+ ``Handler``, ``Model``, etc. as their own — including the
989
+ ``Model``-wrapped dialogues classes such as ``AbciDialogues``) are
990
+ kept by design: such classes have a ``__module__`` from another
991
+ skill and pass the filter. Framework dialogue base classes from
992
+ ``aea.protocols.dialogue.base`` are not ``SkillComponent``
993
+ subclasses and are filtered out by the first condition anyway.
944
994
 
945
995
  :param classes: a list of pairs (class name, class object)
946
996
  :return: a list of the same kind, but filtered with only skill component classes.
947
997
  """
948
998
  filtered_classes = filter(
949
999
  lambda name_and_class: issubclass(name_and_class[1], SkillComponent)
950
- # the following condition filters out classes imported from 'aea'
951
- and not str.startswith(name_and_class[1].__module__, "aea.")
952
- # the following condition filters out classes imported
953
- # from other skills
954
- and not str.startswith(
955
- name_and_class[1].__module__, self.skill_dotted_path + "."
956
- ),
1000
+ and not str.startswith(name_and_class[1].__module__, "aea."),
957
1001
  classes,
958
1002
  )
959
1003
  classes = list(filtered_classes)
@@ -1186,10 +1230,14 @@ class _SkillComponentLoader:
1186
1230
  set_of_unused_classes = set(
1187
1231
  filter(lambda x: x not in used_classes, set_of_classes)
1188
1232
  )
1189
- # filter out classes that are from other packages
1233
+ # Filter out classes that are from other packages. Match both
1234
+ # submodule classes (`packages.<a>.skills.<n>.foo.Bar`) and
1235
+ # classes defined at the skill's `__init__.py` level (whose
1236
+ # `__module__` equals `self.skill_dotted_path` exactly).
1190
1237
  set_of_unused_classes = set(
1191
1238
  filter(
1192
- lambda x: not str.startswith(x.__module__, "packages."),
1239
+ lambda x: x.__module__ == self.skill_dotted_path
1240
+ or str.startswith(x.__module__, self.skill_dotted_path + "."),
1193
1241
  set_of_unused_classes,
1194
1242
  )
1195
1243
  )
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "open-aea"
3
- version = "2.2.6"
3
+ version = "2.2.7"
4
4
  description = "Open AEA Framework"
5
5
  authors = ["developer-valory <develope@valory.xyz>"]
6
6
  license = "Apache-2.0"
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