From 2c273fc690057fa366fdd28f3847be9321b9891f Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Mon, 5 Oct 2026 19:01:08 +0000 Subject: [PATCH] =?UTF-8?q?=EC=84=B1=EB=8A=A5=20=EA=B0=9C=EC=84=A0:=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=EC=9E=90=20=EC=A0=9C=EB=84=88=EB=A0=88?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=EB=A5=BC=20=EC=BB=B4=ED=94=84=EB=A6=AC?= =?UTF-8?q?=ED=97=A8=EC=85=98=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= =?UTF-8?q?=ED=95=98=EC=97=AC=20=EC=86=8D=EB=8F=84=20=EC=B5=9C=EC=A0=81?= =?UTF-8?q?=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Python의 `tuple()` 생성자와 `dict.fromkeys()` 메서드에 제너레이터 표현식을 전달할 때 발생하는 반복 및 함수 호출 오버헤드를 줄이기 위해 리스트 및 딕셔너리 컴프리헨션으로 수정함. 이를 통해 인터프리터의 C 레벨에서 루프를 처리하도록 유도하여 실행 속도를 향상시킴. --- .jules/bolt.md | 4 ++++ appguardrail_core/findings.py | 4 ++-- appguardrail_core/rules.py | 19 ++++++++----------- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/.jules/bolt.md b/.jules/bolt.md index 8ce7ce8f7..4c65605a4 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -77,3 +77,7 @@ ## 2024-11-20 - Optimize multiple tuple generation from a single collection **Learning:** `build_rule_metadata` derives exactly two collections, `owasp` and `cwe`, from the same references. Replacing its two generator traversals with one explicit loop reduces element visits from about 2N to N. Both versions remain O(N), so this is a constant-factor optimization rather than an asymptotic complexity improvement. **Action:** Combine repeated traversal when fixed derived collections share one source, while preserving ordering and classification semantics. Benchmark the production hot path before claiming a material wall-clock improvement. + +## 2026-10-05 - 제너레이터 대신 컴프리헨션 사용 최적화 +**Learning:** Python에서 tuple()이나 dict.fromkeys()에 제너레이터를 전달하면 오버헤드가 크므로, 리스트나 딕셔너리 컴프리헨션을 사용하여 C 속도로 처리해야 한다. +**Action:** Hot path에서는 제너레이터 대신 [ ]나 { }로 감싼 컴프리헨션을 tuple() 생성자 등에 전달한다. diff --git a/appguardrail_core/findings.py b/appguardrail_core/findings.py index 5e0c28b43..87c563d36 100644 --- a/appguardrail_core/findings.py +++ b/appguardrail_core/findings.py @@ -106,10 +106,10 @@ def normalize_findings( snippet_max_len: int = 400, ) -> tuple[dict[str, Any], ...]: """Normalize a finding collection into a stable tuple.""" - return tuple( + return tuple([ normalize_finding(finding, snippet_max_len=snippet_max_len) for finding in findings - ) + ]) def severity_counts(findings: Iterable[dict[str, Any]]) -> dict[str, int]: diff --git a/appguardrail_core/rules.py b/appguardrail_core/rules.py index c06ea203a..a616f1794 100644 --- a/appguardrail_core/rules.py +++ b/appguardrail_core/rules.py @@ -106,12 +106,10 @@ def as_dict(self) -> dict[str, Any]: def extract_public_references(message: str) -> tuple[str, ...]: """Extract OWASP, CWE, and CVE references already embedded in rule copy.""" - return tuple( - dict.fromkeys( - " ".join(match.group(1).split()) - for match in REFERENCE_RE.finditer(message or "") - ) - ) + return tuple({ + " ".join(match.group(1).split()): None + for match in REFERENCE_RE.finditer(message or "") + }) def _category_for_references(references: tuple[str, ...], fallback: str) -> str: @@ -174,8 +172,7 @@ def validate_rule_metadata(metadata: RuleMetadata | dict[str, Any]) -> list[str] def _merge_references(*groups: tuple[str, ...]) -> tuple[str, ...]: - return tuple( - dict.fromkeys( - reference for group in groups for reference in group if reference - ) - ) + return tuple({ + reference: None + for group in groups for reference in group if reference + })