programgarden-core 1.14.4__tar.gz → 1.14.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 (82) hide show
  1. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/PKG-INFO +1 -1
  2. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/expression/evaluator.py +64 -10
  3. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/pyproject.toml +1 -1
  4. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/README.md +0 -0
  5. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/__init__.py +0 -0
  6. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/bases/__init__.py +0 -0
  7. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/bases/client.py +0 -0
  8. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/bases/components.py +0 -0
  9. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/bases/listener.py +0 -0
  10. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/bases/mixins.py +0 -0
  11. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/bases/products.py +0 -0
  12. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/bases/sql.py +0 -0
  13. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/bases/storage.py +0 -0
  14. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/exceptions.py +0 -0
  15. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/expression/__init__.py +0 -0
  16. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/i18n/__init__.py +0 -0
  17. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/i18n/locales/en.json +0 -0
  18. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/i18n/locales/ko.json +0 -0
  19. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/i18n/translator.py +0 -0
  20. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/korea_alias.py +0 -0
  21. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/models/__init__.py +0 -0
  22. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/models/connection_rule.py +0 -0
  23. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/models/credential.py +0 -0
  24. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/models/edge.py +0 -0
  25. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/models/event.py +0 -0
  26. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/models/exchange.py +0 -0
  27. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/models/field_binding.py +0 -0
  28. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/models/job.py +0 -0
  29. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/models/plugin_resource.py +0 -0
  30. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/models/resilience.py +0 -0
  31. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/models/resource.py +0 -0
  32. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/models/validation.py +0 -0
  33. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/models/workflow.py +0 -0
  34. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/nodes/__init__.py +0 -0
  35. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/nodes/account_futures.py +0 -0
  36. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/nodes/account_korea_stock.py +0 -0
  37. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/nodes/account_stock.py +0 -0
  38. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/nodes/ai.py +0 -0
  39. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/nodes/backtest.py +0 -0
  40. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/nodes/backtest_futures.py +0 -0
  41. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/nodes/backtest_korea_stock.py +0 -0
  42. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/nodes/backtest_stock.py +0 -0
  43. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/nodes/base.py +0 -0
  44. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/nodes/broker.py +0 -0
  45. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/nodes/calculation.py +0 -0
  46. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/nodes/condition.py +0 -0
  47. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/nodes/data.py +0 -0
  48. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/nodes/data_futures.py +0 -0
  49. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/nodes/data_korea_stock.py +0 -0
  50. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/nodes/data_stock.py +0 -0
  51. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/nodes/display.py +0 -0
  52. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/nodes/event.py +0 -0
  53. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/nodes/fundamental_korea_stock.py +0 -0
  54. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/nodes/fundamental_stock.py +0 -0
  55. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/nodes/infra.py +0 -0
  56. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/nodes/market_external.py +0 -0
  57. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/nodes/market_status.py +0 -0
  58. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/nodes/open_orders_futures.py +0 -0
  59. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/nodes/open_orders_korea_stock.py +0 -0
  60. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/nodes/open_orders_stock.py +0 -0
  61. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/nodes/order.py +0 -0
  62. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/nodes/portfolio.py +0 -0
  63. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/nodes/realtime_futures.py +0 -0
  64. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/nodes/realtime_korea_stock.py +0 -0
  65. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/nodes/realtime_stock.py +0 -0
  66. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/nodes/risk.py +0 -0
  67. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/nodes/symbol.py +0 -0
  68. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/nodes/symbol_futures.py +0 -0
  69. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/nodes/symbol_korea_stock.py +0 -0
  70. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/nodes/symbol_stock.py +0 -0
  71. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/nodes/trigger.py +0 -0
  72. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/presets/__init__.py +0 -0
  73. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/presets/news_analyst.json +0 -0
  74. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/presets/risk_manager.json +0 -0
  75. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/presets/strategist.json +0 -0
  76. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/presets/technical_analyst.json +0 -0
  77. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/registry/__init__.py +0 -0
  78. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/registry/credential_registry.py +0 -0
  79. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/registry/dynamic_node_registry.py +0 -0
  80. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/registry/node_registry.py +0 -0
  81. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/registry/plugin_registry.py +0 -0
  82. {programgarden_core-1.14.4 → programgarden_core-1.14.5}/programgarden_core/retry_executor.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: programgarden-core
3
- Version: 1.14.4
3
+ Version: 1.14.5
4
4
  Summary: ProgramGarden Core - 노드 기반 DSL 핵심 타입 정의
5
5
  Author: 프로그램동산
6
6
  Author-email: coding@programgarden.com
@@ -24,7 +24,7 @@ Jinja2 스타일 {{ }} 표현식 평가기
24
24
  - 파일/네트워크 접근 차단
25
25
  """
26
26
 
27
- from typing import Any, Dict, Optional, List, Set
27
+ from typing import Any, Callable, Dict, Optional, List, Set
28
28
  import re
29
29
  import ast
30
30
  import operator
@@ -1004,28 +1004,82 @@ class ExpressionEvaluator:
1004
1004
 
1005
1005
  return self.EXPRESSION_PATTERN.sub(replace_expr, value)
1006
1006
 
1007
- def evaluate_fields(self, fields: Dict[str, Any]) -> Dict[str, Any]:
1007
+ def evaluate_fields(
1008
+ self,
1009
+ fields: Dict[str, Any],
1010
+ on_error: Optional[Callable[[str, Exception], None]] = None,
1011
+ ) -> Dict[str, Any]:
1008
1012
  """
1009
1013
  필드 딕셔너리의 모든 값 평가
1010
1014
 
1011
1015
  Args:
1012
1016
  fields: 노드의 fields 딕셔너리
1017
+ on_error: (선택) leaf 표현식 평가 실패 시 호출되는 콜백
1018
+ ``(expression_text, exception)``. 기본값 None.
1019
+
1020
+ - None 이면 leaf 실패 시 **기존대로 예외를 raise** 한다
1021
+ (정상 runtime/dry_run 동작 불변 — 이 메서드의 default 시맨틱).
1022
+ - 콜백이 주어지면 raise 하지 않고 ``on_error(value, exc)`` 를
1023
+ 호출한 뒤 **원본 leaf 값을 그대로 유지**한다. 이는
1024
+ ``evaluate_all_bindings`` 와 동일한 leaf 단위(per-leaf)
1025
+ try/except 시맨틱으로, deep_validate 가 미해결 binding 을
1026
+ leaf 단위로 수집할 수 있게 한다.
1027
+
1028
+ dict/list 재귀 시 콜백은 그대로 전파된다.
1013
1029
 
1014
1030
  Returns:
1015
1031
  평가된 필드 딕셔너리
1016
1032
  """
1017
1033
  result = {}
1018
1034
  for key, value in fields.items():
1019
- if isinstance(value, dict):
1020
- # 중첩 딕셔너리 재귀 처리
1021
- result[key] = self.evaluate_fields(value)
1022
- elif isinstance(value, list):
1023
- # 리스트 내 표현식 처리
1024
- result[key] = [self.evaluate(item) for item in value]
1025
- else:
1026
- result[key] = self.evaluate(value)
1035
+ result[key] = self._evaluate_field_value(value, on_error)
1027
1036
  return result
1028
1037
 
1038
+ def _evaluate_field_value(
1039
+ self,
1040
+ value: Any,
1041
+ on_error: Optional[Callable[[str, Exception], None]],
1042
+ ) -> Any:
1043
+ """evaluate_fields 의 단일 값 평가.
1044
+
1045
+ 재귀 깊이는 정상 모드(``on_error is None``)와 deep 모드(콜백 주어짐)에서
1046
+ **동일**하다 — 기존 ``evaluate_fields`` 시맨틱과 100% 일치시킨다:
1047
+
1048
+ - dict 값 → ``evaluate_fields`` 재귀 (콜백 전파)
1049
+ - list 값 → ``[self.evaluate(item) for item in value]`` (각 item 을
1050
+ ``self.evaluate`` 로만 평가; **list 내부 dict/nested list 는 재귀하지
1051
+ 않는다** — 기존 동작). deep 모드면 item 단위 on_error try/except 적용.
1052
+ - 그 외(leaf) → ``self.evaluate(value)`` (deep 모드면 leaf 단위 on_error)
1053
+
1054
+ ``on_error`` 가 주어진 경우(deep 모드)에만 평가 실패를 raise 하지 않고
1055
+ 콜백을 호출한 뒤 원본 값을 유지한다.
1056
+ """
1057
+ if isinstance(value, dict):
1058
+ # 중첩 딕셔너리 재귀 처리 — 콜백 전파 (기존 동작)
1059
+ return self.evaluate_fields(value, on_error)
1060
+ if isinstance(value, list):
1061
+ # 리스트는 각 item 을 self.evaluate 로만 평가 (기존 동작 — dict 재귀 안 함)
1062
+ return [self._evaluate_leaf(item, on_error) for item in value]
1063
+ # leaf 값
1064
+ return self._evaluate_leaf(value, on_error)
1065
+
1066
+ def _evaluate_leaf(
1067
+ self,
1068
+ value: Any,
1069
+ on_error: Optional[Callable[[str, Exception], None]],
1070
+ ) -> Any:
1071
+ """단일 leaf 값 평가 (dict/list 재귀 없음). deep 모드면 leaf 단위 on_error."""
1072
+ if on_error is None or not self.is_expression(value):
1073
+ # 기존 경로: on_error 없으면 실패 시 raise (동작 불변),
1074
+ # 표현식이 아니면 그대로 반환.
1075
+ return self.evaluate(value)
1076
+ # on_error 모드 + 표현식 leaf: leaf 단위 try/except (evaluate_all_bindings 시맨틱)
1077
+ try:
1078
+ return self.evaluate(value)
1079
+ except Exception as exc: # noqa: BLE001 - leaf 단위로 사유를 콜백에 전달
1080
+ on_error(value, exc)
1081
+ return value
1082
+
1029
1083
  def _eval_expression(self, expression: str) -> Any:
1030
1084
  """단일 표현식 평가"""
1031
1085
  evaluator = SafeEvaluator(self._context_dict)
@@ -5,7 +5,7 @@ authors = [
5
5
  homepage = "https://programgarden.com"
6
6
  requires-python = ">=3.12"
7
7
  name = "programgarden-core"
8
- version = "1.14.4"
8
+ version = "1.14.5"
9
9
  description = "ProgramGarden Core - 노드 기반 DSL 핵심 타입 정의"
10
10
  readme = "README.md"
11
11