PyYaml事件结构中不必要的子键引用和通过主键的迭代
Unnecessary quotation of subkey and iteration through primary key in PyYaml event structure
我有下一个代码:
import gnupg
import re
import textwrap
from pprint import pprint
import yaml
from yaml.events import *
class AppendableEvents:
def __init__(self, path, events):
self.path = path
self.events = events
def correct_position(self, levels):
if len(self.path) != len(levels):
return False
for index, expected in enumerate(self.path):
if expected != levels[index].cur_id:
return False
return True
class Level:
def __init__(self, mode):
self.mode = mode
self.cur_id = -1 if mode == "item" else ""
def append_to_yaml(yamlFile, targetFile, items):
events = []
levels = []
with open(yamlFile, 'r') as handle:
for event in yaml.parse(handle):
if isinstance(event, StreamStartEvent) or \
isinstance(event, StreamEndEvent) or \
isinstance(event, DocumentStartEvent) or \
isinstance(event, DocumentEndEvent):
pass
elif isinstance(event, CollectionStartEvent):
if len(levels) > 0:
if levels[-1].mode == "key":
# we can only handle scalar keys
raise ValueError("encountered complex key!")
else:
if levels[-1].mode == "value":
levels[-1].mode = "key"
if isinstance(event, MappingStartEvent):
levels.append(Level("key"))
else: # SequenceStartEvent
levels.append(Level("item"))
elif isinstance(event, ScalarEvent):
if len(levels) > 0:
if levels[-1].mode == "item":
levels[-1].cur_id += 1
elif levels[-1].mode == "key":
levels[-1].cur_id = event.value
levels[-1].mode = "value"
else: # mode == "value"
levels[-1].mode = "key"
elif isinstance(event, CollectionEndEvent):
# here we check whether we want to append anything
levels.pop()
for item in items:
if item.correct_position(levels):
for additional_event in item.events:
events.append(additional_event)
events.append(event)
with open(targetFile, mode="w") as handle:
yaml.emit(events, handle,line_break=True)
def key(name):
return ScalarEvent(None, None, (True, True), name)
def literal_value(content):
return ScalarEvent(None, None, (False, True), content, style="|")
def map(*scalarValues):
return [MappingStartEvent(None, None, True)] + \
[ScalarEvent(None, None, (False, True), v, style="|") for v in scalarValues] + \
[MappingEndEvent()]
gpg = gnupg.GPG(gnupghome='~/.gnupg')
gpg.encoding = 'utf-8'
def ExistingFile():
with open(creds) as sensitive_data:
for line in sensitive_data:
encrypted_value = gpg.encrypt(
re.sub(r'^( +?|[A-Za-z0-9]|[A-Za]|[0-9])+( +)?' + '=' + '( +)?', '', line, 1),
recipients="test", always_trust=True)
if not encrypted_value.ok:
print(encrypted_value.status, '\n', encrypted_value.stderr)
break
line = re.sub(r'^( +)?|( +)?' + '=' + '.*', '', line.rstrip('\n'))
append_to_yaml(f1, f1, [
AppendableEvents(["global","app1"], [
key("app2")] + map(line, encrypted_value.data.decode()))])
#key(line), literal_value(encrypted_value.data.decode())])])
ExistingFile()
creds 文件的内容是:
1=1
sadsa=ars
f1 文件的内容是:
global:
app1:
test: |
-----BEGIN PGP MESSAGE-----
Version: GnuPG v1
-----END PGP MESSAGE-----
在此代码中,必要的键、子键和值被附加到 yaml 文件中的适当块。
但问题是我在关键方法中传递的值正在被迭代,因此根据 creds 文件中的内容追加两次或更多次:
global:
app1:
test: |
-----BEGIN PGP MESSAGE-----
Version: GnuPG v1
-----END PGP MESSAGE-----
app2:
"1": |
-----BEGIN PGP MESSAGE-----
Version: GnuPG v1
-----END PGP MESSAGE-----
app2:
"sadsa": |
-----BEGIN PGP MESSAGE-----
Version: GnuPG v1
-----END PGP MESSAGE-----
子项“1”和 "sadsa" 也附加了双引号。
我想摆脱双引号,当我将它与 map 方法结合使用时,我在 key 方法中传递的值将仅附加到文件一次。
因此最终结果将是例如:
global:
app1:
test: |
-----BEGIN PGP MESSAGE-----
Version: GnuPG v1
-----END PGP MESSAGE-----
app2:
1: |
-----BEGIN PGP MESSAGE-----
Version: GnuPG v1
-----END PGP MESSAGE-----
sadsa: |
-----BEGIN PGP MESSAGE-----
Version: GnuPG v1
-----END PGP MESSAGE-----
注意:使用literal_value方法的注释行工作得很好所以我不想打破它的逻辑使用 map 方法更改案例。
首先,提问时请提供一个最小的例子。我从您的代码中删除了 gnupg
内容,因为它与您的问题根本不相关。您有责任只提供实际代码的相关部分,这样试图帮助您的人就不需要挖掘不相关的行。
现在,要解决您的问题:您只需要适当地构建您输出的事件。这是一个解决方案(没有 gnupg
东西):
def ExistingFile():
with open(creds) as sensitive_data:
additions = [key("app2"), MappingStartEvent(None, None, True)]
for line in sensitive_data:
encrypted_value = re.sub(r'^( +?|[A-Za-z0-9]|[A-Za]|[0-9])+( +)?' + '=' + '( +)?', '', line, 1)
line = re.sub(r'^( +)?|( +)?' + '=' + '.*', '', line.rstrip('\n'))
additions.extend(
[ScalarEvent(None, None, (True, False), line),
ScalarEvent(None, None, (False, True), encrypted_value, style='|')])
additions.append(MappingEndEvent())
append_to_yaml(f1, f1_mod, [AppendableEvents(["global", "app1"], additions)])
如您所见,我为键构造的标量事件与为值构造的标量事件不同,因此值显示为文字标量,键显示为普通标量(不带引号)。
我也只调用了一次append_to_yaml
,这样app2
就只创建了一次。
我有下一个代码:
import gnupg
import re
import textwrap
from pprint import pprint
import yaml
from yaml.events import *
class AppendableEvents:
def __init__(self, path, events):
self.path = path
self.events = events
def correct_position(self, levels):
if len(self.path) != len(levels):
return False
for index, expected in enumerate(self.path):
if expected != levels[index].cur_id:
return False
return True
class Level:
def __init__(self, mode):
self.mode = mode
self.cur_id = -1 if mode == "item" else ""
def append_to_yaml(yamlFile, targetFile, items):
events = []
levels = []
with open(yamlFile, 'r') as handle:
for event in yaml.parse(handle):
if isinstance(event, StreamStartEvent) or \
isinstance(event, StreamEndEvent) or \
isinstance(event, DocumentStartEvent) or \
isinstance(event, DocumentEndEvent):
pass
elif isinstance(event, CollectionStartEvent):
if len(levels) > 0:
if levels[-1].mode == "key":
# we can only handle scalar keys
raise ValueError("encountered complex key!")
else:
if levels[-1].mode == "value":
levels[-1].mode = "key"
if isinstance(event, MappingStartEvent):
levels.append(Level("key"))
else: # SequenceStartEvent
levels.append(Level("item"))
elif isinstance(event, ScalarEvent):
if len(levels) > 0:
if levels[-1].mode == "item":
levels[-1].cur_id += 1
elif levels[-1].mode == "key":
levels[-1].cur_id = event.value
levels[-1].mode = "value"
else: # mode == "value"
levels[-1].mode = "key"
elif isinstance(event, CollectionEndEvent):
# here we check whether we want to append anything
levels.pop()
for item in items:
if item.correct_position(levels):
for additional_event in item.events:
events.append(additional_event)
events.append(event)
with open(targetFile, mode="w") as handle:
yaml.emit(events, handle,line_break=True)
def key(name):
return ScalarEvent(None, None, (True, True), name)
def literal_value(content):
return ScalarEvent(None, None, (False, True), content, style="|")
def map(*scalarValues):
return [MappingStartEvent(None, None, True)] + \
[ScalarEvent(None, None, (False, True), v, style="|") for v in scalarValues] + \
[MappingEndEvent()]
gpg = gnupg.GPG(gnupghome='~/.gnupg')
gpg.encoding = 'utf-8'
def ExistingFile():
with open(creds) as sensitive_data:
for line in sensitive_data:
encrypted_value = gpg.encrypt(
re.sub(r'^( +?|[A-Za-z0-9]|[A-Za]|[0-9])+( +)?' + '=' + '( +)?', '', line, 1),
recipients="test", always_trust=True)
if not encrypted_value.ok:
print(encrypted_value.status, '\n', encrypted_value.stderr)
break
line = re.sub(r'^( +)?|( +)?' + '=' + '.*', '', line.rstrip('\n'))
append_to_yaml(f1, f1, [
AppendableEvents(["global","app1"], [
key("app2")] + map(line, encrypted_value.data.decode()))])
#key(line), literal_value(encrypted_value.data.decode())])])
ExistingFile()
creds 文件的内容是:
1=1
sadsa=ars
f1 文件的内容是:
global:
app1:
test: |
-----BEGIN PGP MESSAGE-----
Version: GnuPG v1
-----END PGP MESSAGE-----
在此代码中,必要的键、子键和值被附加到 yaml 文件中的适当块。
但问题是我在关键方法中传递的值正在被迭代,因此根据 creds 文件中的内容追加两次或更多次:
global:
app1:
test: |
-----BEGIN PGP MESSAGE-----
Version: GnuPG v1
-----END PGP MESSAGE-----
app2:
"1": |
-----BEGIN PGP MESSAGE-----
Version: GnuPG v1
-----END PGP MESSAGE-----
app2:
"sadsa": |
-----BEGIN PGP MESSAGE-----
Version: GnuPG v1
-----END PGP MESSAGE-----
子项“1”和 "sadsa" 也附加了双引号。
我想摆脱双引号,当我将它与 map 方法结合使用时,我在 key 方法中传递的值将仅附加到文件一次。
因此最终结果将是例如:
global:
app1:
test: |
-----BEGIN PGP MESSAGE-----
Version: GnuPG v1
-----END PGP MESSAGE-----
app2:
1: |
-----BEGIN PGP MESSAGE-----
Version: GnuPG v1
-----END PGP MESSAGE-----
sadsa: |
-----BEGIN PGP MESSAGE-----
Version: GnuPG v1
-----END PGP MESSAGE-----
注意:使用literal_value方法的注释行工作得很好所以我不想打破它的逻辑使用 map 方法更改案例。
首先,提问时请提供一个最小的例子。我从您的代码中删除了 gnupg
内容,因为它与您的问题根本不相关。您有责任只提供实际代码的相关部分,这样试图帮助您的人就不需要挖掘不相关的行。
现在,要解决您的问题:您只需要适当地构建您输出的事件。这是一个解决方案(没有 gnupg
东西):
def ExistingFile():
with open(creds) as sensitive_data:
additions = [key("app2"), MappingStartEvent(None, None, True)]
for line in sensitive_data:
encrypted_value = re.sub(r'^( +?|[A-Za-z0-9]|[A-Za]|[0-9])+( +)?' + '=' + '( +)?', '', line, 1)
line = re.sub(r'^( +)?|( +)?' + '=' + '.*', '', line.rstrip('\n'))
additions.extend(
[ScalarEvent(None, None, (True, False), line),
ScalarEvent(None, None, (False, True), encrypted_value, style='|')])
additions.append(MappingEndEvent())
append_to_yaml(f1, f1_mod, [AppendableEvents(["global", "app1"], additions)])
如您所见,我为键构造的标量事件与为值构造的标量事件不同,因此值显示为文字标量,键显示为普通标量(不带引号)。
我也只调用了一次append_to_yaml
,这样app2
就只创建了一次。