code-node-graph 0.3.0__tar.gz → 0.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (186) hide show
  1. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/CHANGELOG.md +24 -1
  2. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/PKG-INFO +1 -1
  3. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/__init__.py +1 -1
  4. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/analysis/graph.py +148 -7
  5. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/analysis/reader.py +20 -3
  6. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/build.py +5 -3
  7. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/graph.py +232 -52
  8. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/style.py +14 -0
  9. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/serve.py +2 -2
  10. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/tests/test_code_node.py +79 -4
  11. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/.gitignore +0 -0
  12. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/LICENSE +0 -0
  13. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/README.md +0 -0
  14. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/examples/books-api/README.md +0 -0
  15. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/examples/cart-service/README.md +0 -0
  16. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/examples/orders-service/README.md +0 -0
  17. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/pyproject.toml +0 -0
  18. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/__main__.py +0 -0
  19. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/analysis/__init__.py +0 -0
  20. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/analysis/aws_model.py +0 -0
  21. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/analysis/findings.py +0 -0
  22. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/analysis/mapping.py +0 -0
  23. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/analysis/model.py +0 -0
  24. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/analysis/syntax.py +0 -0
  25. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/analysis/terms.py +0 -0
  26. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/cli.py +0 -0
  27. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/deploys/__init__.py +0 -0
  28. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/deploys/sam.py +0 -0
  29. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/deploys/serverless.py +0 -0
  30. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/kit/__init__.py +0 -0
  31. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/kit/blocks.py +0 -0
  32. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/kit/fmt.py +0 -0
  33. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/kit/highlight.py +0 -0
  34. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/kit/render.py +0 -0
  35. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/kit/text.py +0 -0
  36. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/libraries/__init__.py +0 -0
  37. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/libraries/llm.py +0 -0
  38. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/libraries/mongo.py +0 -0
  39. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/libraries/redis.py +0 -0
  40. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/libraries/sql.py +0 -0
  41. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/pages.py +0 -0
  42. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/platforms/__init__.py +0 -0
  43. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/platforms/aws_lambda.py +0 -0
  44. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/platforms/web.py +0 -0
  45. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/project.py +0 -0
  46. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/__init__.py +0 -0
  47. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/brands.py +0 -0
  48. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/editor.py +0 -0
  49. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/README.md +0 -0
  50. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/anthropic-icon.svg +0 -0
  51. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-amplify.svg +0 -0
  52. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-api-gateway.svg +0 -0
  53. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-appflow.svg +0 -0
  54. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-appsync.svg +0 -0
  55. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-athena.svg +0 -0
  56. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-backup.svg +0 -0
  57. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-batch.svg +0 -0
  58. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-certificate-manager.svg +0 -0
  59. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-cloudformation.svg +0 -0
  60. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-cloudfront.svg +0 -0
  61. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-cloudtrail.svg +0 -0
  62. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-cloudwatch.svg +0 -0
  63. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-codebuild.svg +0 -0
  64. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-codecommit.svg +0 -0
  65. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-codedeploy.svg +0 -0
  66. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-codepipeline.svg +0 -0
  67. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-cognito.svg +0 -0
  68. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-config.svg +0 -0
  69. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-documentdb.svg +0 -0
  70. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-dynamodb.svg +0 -0
  71. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-ec2.svg +0 -0
  72. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-ecs.svg +0 -0
  73. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-eks.svg +0 -0
  74. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-elasticache.svg +0 -0
  75. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-elb.svg +0 -0
  76. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-eventbridge.svg +0 -0
  77. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-glacier.svg +0 -0
  78. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-glue.svg +0 -0
  79. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-iam.svg +0 -0
  80. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-keyspaces.svg +0 -0
  81. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-kinesis.svg +0 -0
  82. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-kms.svg +0 -0
  83. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-lake-formation.svg +0 -0
  84. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-lambda.svg +0 -0
  85. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-lightsail.svg +0 -0
  86. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-mq.svg +0 -0
  87. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-msk.svg +0 -0
  88. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-neptune.svg +0 -0
  89. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-open-search.svg +0 -0
  90. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-quicksight.svg +0 -0
  91. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-rds.svg +0 -0
  92. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-redshift.svg +0 -0
  93. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-route53.svg +0 -0
  94. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-s3.svg +0 -0
  95. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-secrets-manager.svg +0 -0
  96. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-ses.svg +0 -0
  97. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-shield.svg +0 -0
  98. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-sns.svg +0 -0
  99. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-sqs.svg +0 -0
  100. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-step-functions.svg +0 -0
  101. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-systems-manager.svg +0 -0
  102. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-timestream.svg +0 -0
  103. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-waf.svg +0 -0
  104. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws-xray.svg +0 -0
  105. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/aws.svg +0 -0
  106. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/azure-icon.svg +0 -0
  107. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/django-icon.svg +0 -0
  108. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/elasticsearch.svg +0 -0
  109. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/fastapi-icon.svg +0 -0
  110. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/firebase-icon.svg +0 -0
  111. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/flask.svg +0 -0
  112. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/google-cloud.svg +0 -0
  113. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/kafka-icon.svg +0 -0
  114. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/mariadb-icon.svg +0 -0
  115. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/mongodb-icon.svg +0 -0
  116. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/mysql-icon.svg +0 -0
  117. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/openai-icon.svg +0 -0
  118. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/postgresql.svg +0 -0
  119. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/python.svg +0 -0
  120. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/rabbitmq-icon.svg +0 -0
  121. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/redis.svg +0 -0
  122. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/serverless.svg +0 -0
  123. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/slack-icon.svg +0 -0
  124. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/small/aws-api-gateway.svg +0 -0
  125. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/small/aws-appflow.svg +0 -0
  126. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/small/aws-appsync.svg +0 -0
  127. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/small/aws-athena.svg +0 -0
  128. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/small/aws-backup.svg +0 -0
  129. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/small/aws-batch.svg +0 -0
  130. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/small/aws-certificate-manager.svg +0 -0
  131. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/small/aws-cloudformation.svg +0 -0
  132. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/small/aws-cloudfront.svg +0 -0
  133. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/small/aws-cloudtrail.svg +0 -0
  134. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/small/aws-cloudwatch.svg +0 -0
  135. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/small/aws-codebuild.svg +0 -0
  136. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/small/aws-codecommit.svg +0 -0
  137. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/small/aws-codedeploy.svg +0 -0
  138. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/small/aws-codepipeline.svg +0 -0
  139. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/small/aws-cognito.svg +0 -0
  140. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/small/aws-config.svg +0 -0
  141. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/small/aws-documentdb.svg +0 -0
  142. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/small/aws-dynamodb.svg +0 -0
  143. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/small/aws-ec2.svg +0 -0
  144. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/small/aws-ecs.svg +0 -0
  145. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/small/aws-eks.svg +0 -0
  146. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/small/aws-elasticache.svg +0 -0
  147. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/small/aws-elb.svg +0 -0
  148. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/small/aws-eventbridge.svg +0 -0
  149. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/small/aws-glacier.svg +0 -0
  150. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/small/aws-glue.svg +0 -0
  151. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/small/aws-iam.svg +0 -0
  152. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/small/aws-keyspaces.svg +0 -0
  153. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/small/aws-kinesis.svg +0 -0
  154. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/small/aws-kms.svg +0 -0
  155. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/small/aws-lake-formation.svg +0 -0
  156. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/small/aws-lambda.svg +0 -0
  157. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/small/aws-mq.svg +0 -0
  158. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/small/aws-msk.svg +0 -0
  159. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/small/aws-neptune.svg +0 -0
  160. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/small/aws-open-search.svg +0 -0
  161. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/small/aws-quicksight.svg +0 -0
  162. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/small/aws-rds.svg +0 -0
  163. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/small/aws-redshift.svg +0 -0
  164. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/small/aws-route53.svg +0 -0
  165. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/small/aws-s3.svg +0 -0
  166. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/small/aws-secrets-manager.svg +0 -0
  167. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/small/aws-ses.svg +0 -0
  168. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/small/aws-shield.svg +0 -0
  169. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/small/aws-sns.svg +0 -0
  170. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/small/aws-sqs.svg +0 -0
  171. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/small/aws-step-functions.svg +0 -0
  172. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/small/aws-systems-manager.svg +0 -0
  173. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/small/aws-timestream.svg +0 -0
  174. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/small/aws-waf.svg +0 -0
  175. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/small/aws-xray.svg +0 -0
  176. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/snowflake-icon.svg +0 -0
  177. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/sqlite.svg +0 -0
  178. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/stripe.svg +0 -0
  179. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/supabase-icon.svg +0 -0
  180. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/logos/twilio-icon.svg +0 -0
  181. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/outline.py +0 -0
  182. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/tabs.py +0 -0
  183. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/src/code_node/report/walk.py +0 -0
  184. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/tests/snapshots/books-api.txt +0 -0
  185. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/tests/snapshots/cart-service.txt +0 -0
  186. {code_node_graph-0.3.0 → code_node_graph-0.4.0}/tests/snapshots/orders-service.txt +0 -0
@@ -4,6 +4,28 @@ Every change a user would notice, newest first ([Keep a Changelog](https://keepa
4
4
  follow [Semantic Versioning](https://semver.org/); before 1.0, a minor version may change what a command does.
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.4.0] - 2026-10-20
8
+
9
+ ### Fixed
10
+
11
+ - Modules beside the entry point's file are read as its own code when it imports them by their own names, as a
12
+ Lambda function's folder does (`from helpers import x` in `src/app/handler.py`). They were taken for installed
13
+ libraries, so their functions, AWS calls and environment variables were missing, even when the folder is also a
14
+ package from the project's root.
15
+
16
+ ### Added
17
+
18
+ - A box's "+12 calls not drawn" line opens them: click it and the graph starts from that function, with every call it
19
+ makes, a path above it back up to the whole graph, and the browser's Back button to return. **All** in the graph's
20
+ bar draws every function at once, for up to 150. This needs JavaScript; without it the page works as before.
21
+ - A box's code panel closes when you click anywhere outside it, or press Escape, as well as with its ×. Clicking
22
+ another box still opens that one's code.
23
+
24
+ ### Changed
25
+
26
+ - The graph says why functions are left out: too many to draw at once, or too deep, instead of always "too deep or
27
+ too many".
28
+
7
29
  ## [0.3.0] - 2026-10-20
8
30
 
9
31
  ### Changed
@@ -171,7 +193,8 @@ follow [Semantic Versioning](https://semver.org/); before 1.0, a minor version m
171
193
  - `--platform NAME` runs a platform's checks whatever the entry point is; `--lambda` is short for
172
194
  `--platform lambda`. `EntryPoint.is_lambda` and `PageOptions.is_lambda` are now `platform` (`"lambda"` or `""`).
173
195
 
174
- [Unreleased]: https://github.com/utkarsh5026/code-node/compare/v0.3.0...HEAD
196
+ [Unreleased]: https://github.com/utkarsh5026/code-node/compare/v0.4.0...HEAD
197
+ [0.4.0]: https://github.com/utkarsh5026/code-node/compare/v0.3.0...v0.4.0
175
198
  [0.3.0]: https://github.com/utkarsh5026/code-node/compare/v0.2.0...v0.3.0
176
199
  [0.2.0]: https://github.com/utkarsh5026/code-node/compare/v0.1.0...v0.2.0
177
200
  [0.1.0]: https://github.com/utkarsh5026/code-node/releases/tag/v0.1.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: code-node-graph
3
- Version: 0.3.0
3
+ Version: 0.4.0
4
4
  Summary: See how Python code works without running it: a graph of who calls whom from an entry point, and what each path reaches.
5
5
  Project-URL: Homepage, https://github.com/utkarsh5026/code-node
6
6
  Project-URL: Documentation, https://utkarsh5026.github.io/code-node/
@@ -13,7 +13,7 @@ from .libraries import Library, register_library
13
13
  from .platforms import Platform, get_platform, register_platform
14
14
  from .project import EntryPoint, Project, entry_points, read_project
15
15
 
16
- __version__ = "0.3.0"
16
+ __version__ = "0.4.0"
17
17
 
18
18
  __all__ = [
19
19
  "CodeGraph",
@@ -8,7 +8,7 @@ from __future__ import annotations
8
8
  import heapq
9
9
  import re
10
10
  from collections import defaultdict
11
- from dataclasses import dataclass, field
11
+ from dataclasses import dataclass, field, replace
12
12
 
13
13
  from ..kit.fmt import _plural
14
14
  from ..kit.text import _clip
@@ -55,6 +55,7 @@ class GraphNode:
55
55
  when: str = "" # a function called only under an if, everywhere it's called: 'check(order)'
56
56
  icon: str = "" # a service's icon, when its plugin names one: 'database', 'queue', 'spark'; or the entry
57
57
  # point's logo, when its platform names one: 'fastapi-icon'
58
+ name: str = "" # a function's box: the function, as module.name ('orders.repo.save')
58
59
 
59
60
 
60
61
  @dataclass
@@ -85,6 +86,7 @@ class CodeGraph:
85
86
  nodes: list[GraphNode] = field(default_factory=list)
86
87
  edges: list[GraphEdge] = field(default_factory=list)
87
88
  hidden: int = 0 # functions left out to keep the graph readable (too deep, or too many)
89
+ too_deep: int = 0 # ...of them, the ones deeper than it draws
88
90
 
89
91
  def node(self, node_id: str) -> GraphNode | None:
90
92
  return next((n for n in self.nodes if n.id == node_id), None)
@@ -256,11 +258,13 @@ def _pick(
256
258
  order: dict[str, int],
257
259
  room: int,
258
260
  max_depth: int,
261
+ first: bool = False,
259
262
  ) -> list[str]:
260
263
  """
261
264
  The functions the graph draws besides the entry point, at most `room` of them and max_depth calls deep: grown out
262
265
  from the entry point (and what runs at import), each time taking the one the drawn boxes call that leads to the
263
- most code, so the boxes are the ones that do the work and each is joined to one above it.
266
+ most code, so the boxes are the ones that do the work and each is joined to one above it. first takes every
267
+ function the entry point calls before the rest.
264
268
  """
265
269
 
266
270
  def depth(name: str) -> int:
@@ -283,6 +287,14 @@ def _pick(
283
287
  if name not in level:
284
288
  offer(name)
285
289
  picked: list[str] = []
290
+ if first:
291
+ for child, _ in children.get(entry, []):
292
+ if child in by_name and child != entry and child not in picked and depth(child) <= max_depth:
293
+ picked.append(child)
294
+ for name in list(picked):
295
+ for child, _ in children.get(name, []):
296
+ if child not in picked:
297
+ offer(child)
286
298
  while queue and len(picked) < room:
287
299
  name = heapq.heappop(queue)[3]
288
300
  if name in picked:
@@ -294,7 +306,46 @@ def _pick(
294
306
  return picked
295
307
 
296
308
 
297
- def code_graph(cmap: CodeMap, *, max_functions: int = _GRAPH_FUNCTIONS, max_depth: int = _GRAPH_DEPTH) -> CodeGraph:
309
+ def _focused(cmap: CodeMap, focus: str) -> CodeMap:
310
+ """
311
+ The map cut down to one of its functions and what it calls, however deep, as if the code started there: its
312
+ calls in from elsewhere, what runs at import and the entry point's input left out.
313
+ """
314
+ children: dict[str, list[str]] = defaultdict(list)
315
+ for f in cmap.functions:
316
+ for where in f.called_from:
317
+ children[where.rpartition(" line ")[0]].append(f.name)
318
+ scope, todo = {focus}, [focus]
319
+ while todo:
320
+ for child in children.get(todo.pop(), []):
321
+ if child not in scope:
322
+ scope.add(child)
323
+ todo.append(child)
324
+ root = next(f for f in cmap.functions if f.name == focus)
325
+ functions = []
326
+ for f in cmap.functions:
327
+ if f.name in scope:
328
+ kept = [] if f.name == focus else [w for w in f.called_from if w.rpartition(" line ")[0] in scope]
329
+ functions.append(replace(f, called_from=kept, when={w: t for w, t in f.when.items() if w in kept}))
330
+ return replace(
331
+ cmap,
332
+ entry=focus,
333
+ handler_file=root.file,
334
+ entry_line=root.line,
335
+ startup=[],
336
+ event=[],
337
+ functions=functions,
338
+ aws=[c for c in cmap.aws if c.function in scope],
339
+ library_calls=[c for c in cmap.library_calls if c.function in scope],
340
+ env=[e for e in cmap.env if e.function in scope],
341
+ spots=[s for s in cmap.spots if s.function in scope and not s.startup],
342
+ routes=[r for r in cmap.routes if r[2] in scope],
343
+ )
344
+
345
+
346
+ def code_graph(
347
+ cmap: CodeMap, *, max_functions: int = _GRAPH_FUNCTIONS, max_depth: int = _GRAPH_DEPTH, focus: str = ""
348
+ ) -> CodeGraph:
298
349
  """
299
350
  How the code fits together, as boxes and arrows, from a CodeMap: on the left what comes in (the event, with the
300
351
  fields it reads, and the environment variables), then the handler, what runs at start-up, and its own functions
@@ -304,10 +355,16 @@ def code_graph(cmap: CodeMap, *, max_functions: int = _GRAPH_FUNCTIONS, max_dept
304
355
  they do is drawn from the nearest box above them that is.
305
356
  The functions drawn are grown out from the entry point, each time the one that leads to the most code (and to AWS,
306
357
  the web and the environment), so the boxes are the ones that do the work, not the nearest helpers.
358
+ focus draws the graph from one of its functions instead (module.name): it and what it calls, every call it makes
359
+ drawn even past max_functions, and nothing from what comes in or what runs at import.
307
360
  """
308
361
  graph = CodeGraph()
309
362
  if cmap.note or cmap.entry is None:
310
363
  return graph
364
+ if focus:
365
+ if not any(f.name == focus for f in cmap.functions):
366
+ return graph
367
+ cmap = _focused(cmap, focus)
311
368
  platform = get_platform(cmap.platform)
312
369
  entry = cmap.entry
313
370
  by_name = {f.name: f for f in cmap.functions}
@@ -342,11 +399,15 @@ def code_graph(cmap: CodeMap, *, max_functions: int = _GRAPH_FUNCTIONS, max_dept
342
399
  todo.append(child)
343
400
  order = {f.name: i for i, f in enumerate(cmap.functions)}
344
401
  weight = _weights(cmap, children)
345
- picked = _pick(cmap, entry, start_key, children, level, weight, order, max_functions - entry_is_function, max_depth)
402
+ room = max_functions - entry_is_function
403
+ if focus: # a function opened on its own shows every call it makes
404
+ room = max(room, len({child for child, _ in children.get(entry, [])}))
405
+ picked = _pick(cmap, entry, start_key, children, level, weight, order, room, max_depth, first=bool(focus))
346
406
  shown = ([by_name[entry]] if entry_is_function else []) + sorted(
347
407
  (by_name[name] for name in picked), key=lambda f: (level.get(f.name, f.depth + 1), order[f.name])
348
408
  )
349
409
  graph.hidden = len(cmap.functions) - len(shown)
410
+ graph.too_deep = sum(1 for f in cmap.functions if level.get(f.name, f.depth + 1) > max_depth)
350
411
  ids = {f.name: f"f{i}" for i, f in enumerate(shown)}
351
412
  drawn_level = {entry: 0, start_key: 0} # calls from the entry point through the boxes drawn: each box's column
352
413
  todo = [entry, start_key]
@@ -408,7 +469,9 @@ def code_graph(cmap: CodeMap, *, max_functions: int = _GRAPH_FUNCTIONS, max_dept
408
469
  reasons[call.function].append(f"{call.label} isn't allowed: {denied[call.permission]} (line {call.line})")
409
470
  for function, why in platform.marks(cmap).items():
410
471
  reasons[function] += why
411
- handler_reasons = [m.split(":")[0] for level_, m in platform.entry_findings(cmap) if level_ == "warn"]
472
+ handler_reasons = (
473
+ [] if focus else [m.split(":")[0] for level_, m in platform.entry_findings(cmap) if level_ == "warn"]
474
+ )
412
475
  unset = platform.unset_env(cmap)
413
476
 
414
477
  # the lines in each function worth pointing at: where it calls, reads or sends what the graph draws
@@ -455,7 +518,7 @@ def code_graph(cmap: CodeMap, *, max_functions: int = _GRAPH_FUNCTIONS, max_dept
455
518
  when=_when(f, [where for where in f.called_from if where.rpartition(" line ")[0] == caller]),
456
519
  )
457
520
  )
458
- has_input = bool(cmap.event) or platform.draws_input
521
+ has_input = not focus and (bool(cmap.event) or platform.draws_input)
459
522
  if has_input:
460
523
  edges.insert(0, GraphEdge("event", entry_id, "event", "its input"))
461
524
 
@@ -769,7 +832,8 @@ def code_graph(cmap: CodeMap, *, max_functions: int = _GRAPH_FUNCTIONS, max_dept
769
832
  ],
770
833
  more=more,
771
834
  when=_when(f, f.called_from),
772
- icon=platform.entry_icon(cmap) if is_entry else "",
835
+ icon=platform.entry_icon(cmap) if is_entry and not focus else "",
836
+ name=f.name,
773
837
  )
774
838
  )
775
839
  out_column = 1 + max([n.column for n in graph.nodes if n.kind in ("handler", "function", "start")] + [1])
@@ -778,3 +842,80 @@ def code_graph(cmap: CodeMap, *, max_functions: int = _GRAPH_FUNCTIONS, max_dept
778
842
  graph.nodes += reach
779
843
  graph.edges = edges
780
844
  return graph
845
+
846
+
847
+ _GRAPH_VIEWS = 120 # functions opened on their own, at most: past that a box's calls left out stay in the steps
848
+
849
+ _GRAPH_EVERYTHING = 150 # functions, at most, for a graph of all of them besides the one drawn
850
+
851
+
852
+ @dataclass
853
+ class GraphView:
854
+ """
855
+ The graph from one of the functions a graph leaves calls out of: the function and what it calls (`graph`), and the
856
+ calls from the entry point down to it (`path`, module.name each, the entry point first and the function last).
857
+ """
858
+
859
+ name: str
860
+ graph: CodeGraph
861
+ path: list[str] = field(default_factory=list)
862
+
863
+
864
+ def _call_path(cmap: CodeMap, name: str) -> list[str]:
865
+ """
866
+ The fewest calls from the entry point to a function: [entry, ..., name]. [name] when the entry point isn't above it.
867
+ """
868
+ known = {f.name for f in cmap.functions} | {cmap.entry or ""}
869
+ parents: dict[str, list[str]] = defaultdict(list)
870
+ for f in cmap.functions:
871
+ for where in f.called_from:
872
+ caller = where.rpartition(" line ")[0]
873
+ if caller in known:
874
+ parents[f.name].append(caller)
875
+ came: dict[str, str] = {name: ""}
876
+ todo = [name]
877
+ while todo:
878
+ key = todo.pop(0)
879
+ if key == cmap.entry:
880
+ path = [key]
881
+ while came[path[-1]]:
882
+ path.append(came[path[-1]])
883
+ return path
884
+ for parent in parents.get(key, []):
885
+ if parent not in came:
886
+ came[parent] = key
887
+ todo.append(parent)
888
+ return [name]
889
+
890
+
891
+ def graph_views(
892
+ cmap: CodeMap,
893
+ graph: CodeGraph,
894
+ *,
895
+ max_functions: int = _GRAPH_FUNCTIONS,
896
+ max_depth: int = _GRAPH_DEPTH,
897
+ most: int = _GRAPH_VIEWS,
898
+ ) -> list[GraphView]:
899
+ """
900
+ A graph from each function whose calls `graph` leaves out, and from each such function in those, so that from any
901
+ box with calls not drawn, its own graph has them: at most `most`, nearest the entry point first.
902
+ """
903
+ views: dict[str, GraphView] = {}
904
+ todo = [graph]
905
+ while todo and len(views) < most:
906
+ for n in todo.pop(0).nodes:
907
+ if not (n.more and n.name) or n.name in views or len(views) >= most:
908
+ continue
909
+ opened = code_graph(cmap, max_functions=max_functions, max_depth=max_depth, focus=n.name)
910
+ views[n.name] = GraphView(n.name, opened, _call_path(cmap, n.name))
911
+ todo.append(opened)
912
+ return list(views.values())
913
+
914
+
915
+ def everything_graph(cmap: CodeMap, graph: CodeGraph, most: int = _GRAPH_EVERYTHING) -> CodeGraph | None:
916
+ """
917
+ Every function in one graph, when `graph` leaves some out and there are at most `most` of them; else None.
918
+ """
919
+ if not graph.hidden or len(cmap.functions) > most:
920
+ return None
921
+ return code_graph(cmap, max_functions=len(cmap.functions) + 1, max_depth=len(cmap.functions) + 1)
@@ -203,6 +203,22 @@ class _CodeReader:
203
203
  module = module[: -len(".__init__")] if module.endswith(".__init__") else module
204
204
  if module and module != "__init__":
205
205
  self.sources[module] = path
206
+ here = (cmap.handler_file or "").rpartition("/")[0]
207
+ here = here + "/" if here else ""
208
+ if here.startswith(root) and here != root:
209
+ # the entry point's own folder is on sys.path too, as a script's is and a Lambda function's code is:
210
+ # `from helpers import x` beside it is its own code, though the folder is also a package from the root
211
+ beside: set[str] = set()
212
+ for path in texts:
213
+ if not path.startswith(here) or not path.endswith(".py") or "site-packages" in path:
214
+ continue
215
+ module = path[len(here) : -3].replace("/", ".")
216
+ module = module[: -len(".__init__")] if module.endswith(".__init__") else module
217
+ if module and module != "__init__" and "-" not in module and module not in self.sources:
218
+ self.sources[module] = path
219
+ beside.add(module.split(".")[0])
220
+ self.tops |= beside
221
+ self.libraries = libraries - beside
206
222
  self.modules: dict[str, _Module] = {}
207
223
  self.defs: dict[str, tuple[str, Any, str | None]] = {} # key -> (module, node, class key)
208
224
  self.classes: dict[str, dict[str, Any]] = {}
@@ -311,8 +327,9 @@ class _CodeReader:
311
327
  cmap.event = list(self.event_reads.values())
312
328
  cmap.routes = [(method, path, key) for method, path, key, _ in self.routes]
313
329
  loaded = [m for m in self.modules.values() if m.tree is not None]
314
- cmap.other_files = sum(
315
- 1 for name, path in self.sources.items() if name not in self.modules and not _JUNK_RE.search(path)
330
+ read = {path for name, path in self.sources.items() if name in self.modules} # a file has two names, at most
331
+ cmap.other_files = len(
332
+ {path for path in self.sources.values() if path not in read and not _JUNK_RE.search(path)}
316
333
  )
317
334
  for m in loaded:
318
335
  for node in m.tree.body:
@@ -324,7 +341,7 @@ class _CodeReader:
324
341
  if isinstance(f, (ast.FunctionDef, ast.AsyncFunctionDef)) and prefix + f.name not in self.reached
325
342
  )
326
343
  self._secrets(m)
327
- for name, path in self.sources.items():
344
+ for path, name in {path: name for name, path in reversed(self.sources.items())}.items():
328
345
  for match in _AWS_KEY_RE.finditer(self.texts[path]):
329
346
  line = self.texts[path].count("\n", 0, match.start()) + 1
330
347
  self._spot("secret", path, line, name, "", "an AWS access key", ok=False)
@@ -10,7 +10,7 @@ from ..kit.blocks import _Note, _Text
10
10
  from ..kit.fmt import _plural
11
11
 
12
12
  from ..analysis.findings import _listed, _short_name
13
- from ..analysis.graph import CodeGraph, code_graph
13
+ from ..analysis.graph import CodeGraph, code_graph, everything_graph, graph_views
14
14
  from ..analysis.model import CodeMap
15
15
  from .graph import _Graph
16
16
  from .tabs import _Tabs
@@ -34,8 +34,8 @@ def _closing_note(cmap: CodeMap, graph: CodeGraph) -> str:
34
34
  said.append(f"Calls to {_listed(services, 4)} are read by code-node's library plugins.")
35
35
  if graph.hidden:
36
36
  said.append(
37
- f"The graph leaves out {_plural(graph.hidden, 'function')} to stay readable: run with --all to "
38
- "draw every one."
37
+ f"The graph leaves out {_plural(graph.hidden, 'function')} to stay readable: a box's line of calls not "
38
+ "drawn opens them, and --all draws every one."
39
39
  )
40
40
  if cmap.other_files:
41
41
  said.append(
@@ -99,6 +99,8 @@ def page_blocks(
99
99
  "How it fits together: what comes in, who calls whom, and what it reaches",
100
100
  sources=sources or {},
101
101
  editor=editor,
102
+ views=graph_views(cmap, graph, max_functions=max_functions, max_depth=max_depth),
103
+ everything=everything_graph(cmap, graph),
102
104
  ),
103
105
  _Text(
104
106
  graph.mermaid(),