Better glom path

This commit is contained in:
Fang-Pen Lin
2025-10-30 19:19:23 -07:00
parent cb62ed86a5
commit 9bc22f8b3c
2 changed files with 57 additions and 3 deletions

View File

@@ -16,4 +16,5 @@ Feature: Order
Then I create a RSA private key pair as cert_key
Then I sign the certificate signing request csr with private key cert_key and output it as csr_pem in PEM format
Then I submit the certificate signing request PEM csr_pem certificate order to the ACME server as order
Then the value order.authorizations[0].uri with jq . should match pattern {BASE_URL}/api/v1/pki/acme/profiles/{acme_profile.id}/authorizations/(.+)
Then the value order.authorizations[0] with jq .uri should match pattern {BASE_URL}/api/v1/pki/acme/profiles/{acme_profile.id}/authorizations/(.+)
Then the value order.authorizations[0] with jq . should be equal to {}

View File

@@ -3,13 +3,13 @@ import re
import jq
import requests
import glom
from acme import client
from acme import messages
from behave.runner import Context
from behave import given
from behave import when
from behave import then
import glom
from josepy.jwk import JWKRSA
from josepy import JSONObjectWithFields
from cryptography.hazmat.primitives import serialization
@@ -41,11 +41,64 @@ def replace_vars(payload: dict | list | int | float | str, vars: dict):
return payload
def parse_glom_path(path_str: str):
"""
Parse a glom path string with 'attr[index]' syntax into a Path object.
Examples:
>>> parse_glom_path('authorizations[0].name')
Path('authorizations', 0, 'name')
>>> parse_glom_path('items[1].user[0].id')
Path('items', 1, 'user', 0, 'id')
>>> parse_glom_path('simple_attr')
Path('simple_attr')
>>> parse_glom_path('nested.attr')
Path('nested', 'attr')
"""
# Pattern to match attr[index] or just attr
# Groups: (attr_name)(?:\[(index)\])?
pattern = r"([a-zA-Z_][a-zA-Z0-9_]*)(?:\[(\d+)\])?"
# Split on dots, but preserve the parts
parts = []
current_pos = 0
# Find all matches in the string
for match in re.finditer(pattern, path_str):
# Add any literal text before this match
if match.start() > current_pos:
before = path_str[current_pos : match.start()]
raise ValueError(f"Invalid path syntax: unexpected text '{before}'")
attr_name = match.group(1)
index = match.group(2)
# Add the attribute name
parts.append(attr_name)
# Add index if present
if index is not None:
parts.append(int(index))
current_pos = match.end()
# Check for trailing text
if current_pos < len(path_str):
after = path_str[current_pos:]
if after != ".":
raise ValueError(f"Invalid path syntax: unexpected text '{after}'")
return glom.Path(*parts)
def eval_var(context: Context, var_path: str, as_json: bool = True):
parts = var_path.split(".", 1)
value = context.vars[parts[0]]
if len(parts) == 2:
value = glom.glom(value, parts[1])
value = glom.glom(value, parse_glom_path(parts[1]))
if as_json:
if isinstance(value, JSONObjectWithFields):
value = value.to_json()