Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DRAFT: yamlinclude initial commit #1038

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions sphinxext/yamlinclude.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import os.path
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would recommend running black on this file


from docutils import statemachine

from docutils.parsers.rst import directives

from sphinx.util.docutils import SphinxDirective

import yaml

class YamlInclude(SphinxDirective):

has_content = False
required_arguments = 1 # Must have the file to include
optional_arguments = 0 # Must only specify the file to include

option_spec = {
"key": directives.unchanged_required,
"subs" : directives.unchanged,
"includepath" : directives.unchanged,
"debug" : directives.flag,
}

def run(self):

# Subs should be specified as a multi-line indented set of comma-separated key values
# :subs:
# foo,bar
# bin,baz
#
# We parse that into a dictionary for lookup later as part of the substitution loop.
subs = {}
if ('subs') in self.options:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for parenthesis -- makes it look at first glance like you might be creating a tuple

for i in self.options.get('subs').splitlines():
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just self.options["subs"] is fine. get() is unnecessary

kv = i.split(',')
subs[kv[0]] = kv[1]

if ('debug') in self.options: print ("Substitution dictionary is "); print(subs)

key = self.options.get('key')
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You probably want self.options["key"] unless you actually want to handle the case where key doesn't exist


# I straight up have no idea what this does or how it works
# It is pulled directly from the Includes definition in
# docutils/parsers/rst/directives.misc.py
# But it returns the correct directory so I guess it's fine

source = self.state_machine.input_lines.source(
self.lineno - self.state_machine.input_offset - 1)
source_dir = os.path.dirname(os.path.abspath(source))

if ('includepath') in self.options:
source_dir += '/' + self.options.get('includepath')
else:
source_dir += '/includes'

if ('debug') in self.options: print ("Using " + source_dir + " as source directory")

path = os.path.normpath(os.path.join(source_dir, self.arguments[0]))
if ('debug') in self.options: print ("Path is " + path)

# We open the YAML file and do a lookup based on the key
# This should theoretically be O(1) regardless of file size

with open(path, "r") as file:
try:
yfile = yaml.safe_load(file)
Copy link

@i80and i80and Oct 16, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Limit the try block to just this line

content = yfile[key]['content']
if ('debug') in self.options: print ("Content is " + content)

content = statemachine.string2lines(content, convert_whitespace=True)

# If we have any subs, iterate through the content line by line and perform simple string substitution.

if (len(subs) > 0):
print("Doing substitutions")
for i,x in enumerate(content):
for j in subs:
content[i] = content[i].replace(j,subs[j])


self.state_machine.insert_input(content, path)

return []

except yaml.YAMLError as exc:
print(exc)

return []

def setup(app):
directives.register_directive('yamlinclude', YamlInclude)

return {
'parallel_read_safe': True,
'parallel_write_safe': True,
}