Skip to content

Commit

Permalink
needimport supports extra options and links
Browse files Browse the repository at this point in the history
* extra options and links are imported
* pre/post/template can be defined by needimport
* same for style and layout

Fixes #227
  • Loading branch information
danwos committed Apr 17, 2021
1 parent adc8018 commit 5d36dd5
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 29 deletions.
2 changes: 2 additions & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ Changelog
(`#168 <https://github.com/useblocks/sphinxcontrib-needs/issues/168>`_)
* Bugfix: Needs nodes get ``ids`` set directly, to avoid empty ids given by sphinx or other extensions for need-nodes.
(`#193 <https://github.com/useblocks/sphinxcontrib-needs/issues/193>`_)
* Bugfix: :ref:`needimport` supports extra options and extra fields.
(`#227 <https://github.com/useblocks/sphinxcontrib-needs/issues/227>`_)
* Bugfix: Using correct indention for pre and post_template function of needs.


Expand Down
12 changes: 12 additions & 0 deletions docs/directives/needimport.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ The directive **.. needimport::** can be used in all rst-documents. Simply write
:tags: imported;external
:hide:
:filter: "test" in tags
:template: template.rst
:pre_template: pre_template.rst
:post_template: post_template.rst

The directive needs an absolute or relative path as argument.
If the path is relative, an absolute path gets calculated with the folder of the **conf.py** as basedir.
Expand Down Expand Up @@ -43,4 +46,13 @@ in :ref:`needfilter`.
The sphinx project owner is responsible for a correct configuration for internal and external needs.
There is no automatic typ transformation during an import.

Customization
-------------
The following options can be set, which overwrite the related options in the imported need itself.
So you can decide during import what kind of layout or style is used.

* layout
* style
* template
* pre_template
* post_template
13 changes: 11 additions & 2 deletions sphinxcontrib/needs/api/need.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,10 @@ def run():
if tags is None:
tags = []
if len(tags) > 0:
tags = [tag.strip() for tag in re.split(";|,", tags)]

# tags should be a string, but it can also be already a list,which can be used.
if isinstance(tags, str):
tags = [tag.strip() for tag in re.split(";|,", tags)]
new_tags = [] # Shall contain only valid tags
for i in range(len(tags)):
if len(tags[i]) == 0 or tags[i].isspace():
Expand Down Expand Up @@ -370,7 +373,13 @@ def _read_in_links(links_string):
# Get links
links = []
if links_string:
for link in re.split(";|,", links_string):
# Check if links_string is really a string, otherwise it will be a list, which can be used
# without modifications
if isinstance(links_string, str):
link_list = re.split(";|,", links_string)
else:
link_list = links_string
for link in link_list:
if link.isspace():
logger.warning('Grubby link definition found in need {}. '
'Defined link contains spaces only.'.format(id))
Expand Down
87 changes: 60 additions & 27 deletions sphinxcontrib/needs/directives/needimport.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from docutils.parsers.rst import Directive
from jinja2 import Template

from sphinxcontrib.needs.api import add_need
from sphinxcontrib.needs.filter_common import filter_single_need
from sphinxcontrib.needs.utils import logger

Expand All @@ -26,7 +27,12 @@ class NeedimportDirective(Directive):
'hide': directives.flag,
'filter': directives.unchanged_required,
'id_prefix': directives.unchanged_required,
'tags': directives.unchanged_required
'tags': directives.unchanged_required,
'style': directives.unchanged_required,
'layout': directives.unchanged_required,
'template': directives.unchanged_required,
'pre_template': directives.unchanged_required,
'post_template': directives.unchanged_required,
}

final_argument_whitespace = True
Expand Down Expand Up @@ -78,19 +84,11 @@ def run(self):
if filter_string is None:
needs_list_filtered[key] = need
else:
filter_context = {
"tags": need["tags"],
"status": need["status"],
"type": need["type"],
"id": need["id"],
"title": need["title"],
"links": need["links"],
# "search": re.search,
# Support both ways of addressing the description, as "description" is used in json file, but
# "content" is the sphinx internal name for this kind of information
"content": need["description"],
"description": need["description"]
}
filter_context = {key: value for key, value in need.items()}

# Support both ways of addressing the description, as "description" is used in json file, but
# "content" is the sphinx internal name for this kind of information
filter_context['content'] = need['description']
try:
if filter_single_need(filter_context, filter_string):
needs_list_filtered[key] = need
Expand All @@ -107,11 +105,12 @@ def run(self):

for key, need in needs_list.items():
for id in needs_ids:
# Manipulate links
if id in need["links"]:
for n, link in enumerate(need["links"]):
if id == link:
need["links"][n] = "".join([id_prefix, id])
# Manipulate links in all link types
for extra_link in env.config.needs_extra_links:
if extra_link['option'] in need.keys() and id in need[extra_link['option']]:
for n, link in enumerate(need[extra_link['option']]):
if id == link:
need[extra_link['option']][n] = "".join([id_prefix, id])
# Manipulate descriptions
# ToDo: Use regex for better matches.
need["description"] = need["description"].replace(id, "".join([id_prefix, id]))
Expand All @@ -120,15 +119,49 @@ def run(self):
for key, need in needs_list.items():
need["tags"] = need["tags"] + tags

template_location = os.path.join(os.path.dirname(os.path.abspath(__file__)), "needimport_template.rst")
with open(template_location, "r") as template_file:
template_content = template_file.read()
template = Template(template_content)
content = template.render(needs_list=needs_list, hide=hide, id_prefix=id_prefix)
self.state_machine.insert_input(content.split('\n'),
self.state_machine.document.attributes['source'])
# template_location = os.path.join(os.path.dirname(os.path.abspath(__file__)), "needimport_template.rst")
# with open(template_location, "r") as template_file:
# template_content = template_file.read()
# template = Template(template_content)
# content = template.render(needs_list=needs_list, hide=hide, id_prefix=id_prefix)
# self.state_machine.insert_input(content.split('\n'),
# self.state_machine.document.attributes['source'])

return []
need_nodes = []
for key, need in needs_list.items():
need['template'] = self.options.get("template", getattr(need, 'template', None))
need['pre_template'] = self.options.get("pre_template", getattr(need, 'pre_template', None))
need['post_template'] = self.options.get("post_template", getattr(need, 'post_template', None))
need['layout'] = self.options.get("layout", getattr(need, 'layout', None))
need['style'] = self.options.get("style", getattr(need, 'style', None))
need['need_type'] = need['type']
need['id'] = id_prefix + need['id']

need['content'] = need['description']
# Remove unknown options, as they may be defined in source system, but not in this sphinx project
extra_link_keys = [x['option'] for x in env.config.needs_extra_links]
extra_option_keys = list(env.config.needs_extra_options.keys())
default_options = ['title', 'status', 'content', 'id', 'tags', 'hide', 'template', 'pre_template',
'post_template', 'collapse', 'style', 'layout', 'need_type']
delete_options = []
for option in need.keys():
if option not in default_options + extra_link_keys + extra_option_keys:
delete_options.append(option)

for option in delete_options:
del (need[option])

need['docname'] = self.docname
need['lineno'] = self.lineno

nodes = add_need(env.app, self.state, **need)
need_nodes.extend(nodes)

return need_nodes

@property
def docname(self):
return self.state.document.settings.env.docname


class VersionNotFound(BaseException):
Expand Down

0 comments on commit 5d36dd5

Please sign in to comment.