2018-12-11 19:22:04 +01:00
|
|
|
import datetime
|
2019-12-11 19:13:36 +01:00
|
|
|
import json
|
2017-09-21 23:27:13 +02:00
|
|
|
import os
|
2018-02-20 22:41:19 +01:00
|
|
|
import re
|
2017-09-21 23:27:13 +02:00
|
|
|
import sys
|
|
|
|
|
2018-02-20 20:48:53 +01:00
|
|
|
from six import class_types
|
|
|
|
from sphinx.ext.autodoc import ClassDocumenter
|
|
|
|
|
|
|
|
from stix2.base import _STIXBase
|
2020-10-16 22:43:12 +02:00
|
|
|
from stix2.equivalence.graph import GRAPH_WEIGHTS
|
|
|
|
from stix2.equivalence.object import WEIGHTS
|
2018-11-28 15:20:26 +01:00
|
|
|
from stix2.version import __version__
|
2018-02-20 20:48:53 +01:00
|
|
|
|
2017-09-21 23:27:13 +02:00
|
|
|
sys.path.insert(0, os.path.abspath('..'))
|
|
|
|
|
2017-04-07 19:10:42 +02:00
|
|
|
extensions = [
|
|
|
|
'sphinx-prompt',
|
2017-09-18 19:29:14 +02:00
|
|
|
'nbsphinx',
|
2017-09-21 23:27:13 +02:00
|
|
|
'sphinx.ext.autodoc',
|
|
|
|
'sphinx.ext.autosummary',
|
|
|
|
'sphinx.ext.napoleon',
|
2017-09-22 16:01:00 +02:00
|
|
|
'sphinx.ext.todo',
|
2017-04-07 19:10:42 +02:00
|
|
|
]
|
2017-09-21 23:27:13 +02:00
|
|
|
autodoc_default_flags = [
|
|
|
|
'undoc-members',
|
|
|
|
]
|
|
|
|
autodoc_member_order = 'groupwise'
|
|
|
|
autosummary_generate = True
|
|
|
|
napoleon_numpy_docstring = False # Force consistency, leave only Google
|
|
|
|
napoleon_use_rtype = False
|
2017-09-22 17:03:25 +02:00
|
|
|
add_module_names = False
|
2017-09-21 23:27:13 +02:00
|
|
|
|
2017-02-14 22:48:13 +01:00
|
|
|
templates_path = ['_templates']
|
|
|
|
source_suffix = '.rst'
|
|
|
|
master_doc = 'index'
|
|
|
|
|
|
|
|
project = 'stix2'
|
2018-12-11 19:22:04 +01:00
|
|
|
copyright = '{}, OASIS Open'.format(datetime.date.today().year)
|
2017-02-14 22:48:13 +01:00
|
|
|
author = 'OASIS Open'
|
|
|
|
|
2018-11-28 15:20:26 +01:00
|
|
|
version = __version__
|
|
|
|
release = __version__
|
2017-02-14 22:48:13 +01:00
|
|
|
|
|
|
|
language = None
|
2017-09-26 20:39:32 +02:00
|
|
|
exclude_patterns = ['_build', '_templates', 'Thumbs.db', '.DS_Store', 'guide/.ipynb_checkpoints']
|
2017-02-14 22:48:13 +01:00
|
|
|
pygments_style = 'sphinx'
|
|
|
|
todo_include_todos = False
|
|
|
|
|
|
|
|
html_theme = 'alabaster'
|
2017-02-20 21:38:35 +01:00
|
|
|
html_sidebars = {
|
|
|
|
'**': [
|
|
|
|
'about.html',
|
|
|
|
'navigation.html',
|
|
|
|
'relations.html',
|
|
|
|
'searchbox.html',
|
2018-07-13 17:10:05 +02:00
|
|
|
],
|
2017-02-20 21:38:35 +01:00
|
|
|
}
|
2017-02-14 22:48:13 +01:00
|
|
|
|
|
|
|
latex_elements = {}
|
|
|
|
latex_documents = [
|
|
|
|
(master_doc, 'stix2.tex', 'stix2 Documentation', 'OASIS', 'manual'),
|
|
|
|
]
|
2018-02-20 20:48:53 +01:00
|
|
|
|
2019-12-11 19:13:36 +01:00
|
|
|
# Add a formatted version of environment.WEIGHTS
|
2020-10-16 22:43:12 +02:00
|
|
|
object_default_sem_eq_weights = json.dumps(WEIGHTS, indent=4, default=lambda o: o.__name__)
|
|
|
|
object_default_sem_eq_weights = object_default_sem_eq_weights.replace('\n', '\n ')
|
|
|
|
object_default_sem_eq_weights = object_default_sem_eq_weights.replace(' "', ' ')
|
|
|
|
object_default_sem_eq_weights = object_default_sem_eq_weights.replace('"\n', '\n')
|
|
|
|
with open('object_default_sem_eq_weights.rst', 'w') as f:
|
|
|
|
f.write(".. code-block:: python\n\n {}\n\n".format(object_default_sem_eq_weights))
|
|
|
|
|
|
|
|
graph_default_sem_eq_weights = json.dumps(GRAPH_WEIGHTS, indent=4, default=lambda o: o.__name__)
|
|
|
|
graph_default_sem_eq_weights = graph_default_sem_eq_weights.replace('\n', '\n ')
|
|
|
|
graph_default_sem_eq_weights = graph_default_sem_eq_weights.replace(' "', ' ')
|
|
|
|
graph_default_sem_eq_weights = graph_default_sem_eq_weights.replace('"\n', '\n')
|
|
|
|
with open('graph_default_sem_eq_weights.rst', 'w') as f:
|
|
|
|
f.write(".. code-block:: python\n\n {}\n\n".format(graph_default_sem_eq_weights))
|
2019-12-11 19:13:36 +01:00
|
|
|
|
2018-02-22 15:55:15 +01:00
|
|
|
|
2018-02-20 22:41:19 +01:00
|
|
|
def get_property_type(prop):
|
2018-02-22 15:55:15 +01:00
|
|
|
"""Convert property classname into pretty string name of property.
|
|
|
|
|
|
|
|
"""
|
2018-02-20 22:41:19 +01:00
|
|
|
try:
|
|
|
|
prop_class = prop.__name__
|
|
|
|
except AttributeError:
|
|
|
|
prop_class = prop.__class__.__name__
|
2018-02-22 15:55:15 +01:00
|
|
|
# Remove 'Property' from the string
|
2018-02-20 22:41:19 +01:00
|
|
|
prop_class = prop_class.split('Property')[0]
|
2018-02-22 15:55:15 +01:00
|
|
|
# Split camelcase with spaces
|
2018-02-20 22:41:19 +01:00
|
|
|
split_camelcase = re.sub('(?!^)([A-Z][a-z]+)', r' \1', prop_class).split()
|
|
|
|
prop_class = ' '.join(split_camelcase)
|
|
|
|
return prop_class
|
|
|
|
|
2018-02-22 15:55:15 +01:00
|
|
|
|
2018-03-16 21:10:53 +01:00
|
|
|
class STIXPropertyDocumenter(ClassDocumenter):
|
2018-02-22 15:55:15 +01:00
|
|
|
"""Custom Sphinx extension to auto-document STIX properties.
|
2018-02-20 20:48:53 +01:00
|
|
|
|
|
|
|
Needed because descendants of _STIXBase use `_properties` dictionaries
|
|
|
|
instead of instance variables for STIX 2 objects' properties.
|
|
|
|
|
2018-02-22 15:55:15 +01:00
|
|
|
"""
|
2018-02-20 22:41:19 +01:00
|
|
|
objtype = 'stixattr'
|
|
|
|
directivetype = 'class'
|
2018-02-20 20:48:53 +01:00
|
|
|
priority = 999
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def can_document_member(cls, member, membername, isattr, parent):
|
|
|
|
return isinstance(member, class_types) and \
|
|
|
|
issubclass(member, _STIXBase) and \
|
|
|
|
hasattr(member, '_properties')
|
|
|
|
|
|
|
|
def add_content(self, more_content, no_docstring=False):
|
|
|
|
ClassDocumenter.add_content(self, more_content, no_docstring)
|
|
|
|
|
|
|
|
obj = self.object
|
2018-02-20 22:41:19 +01:00
|
|
|
self.add_line(':Properties:', '<stixattr>')
|
|
|
|
for prop_name, prop in obj._properties.items():
|
2018-03-16 21:10:53 +01:00
|
|
|
# Skip 'type'
|
|
|
|
if prop_name == 'type':
|
|
|
|
continue
|
|
|
|
|
2018-02-20 22:41:19 +01:00
|
|
|
# Add metadata about the property
|
|
|
|
prop_type = get_property_type(prop)
|
|
|
|
if prop_type == 'List':
|
|
|
|
prop_type = 'List of %ss' % get_property_type(prop.contained)
|
|
|
|
if prop.required:
|
|
|
|
prop_type += ', required'
|
2018-03-16 21:10:53 +01:00
|
|
|
if 'Timestamp' in prop_type and hasattr(prop, 'default'):
|
|
|
|
prop_type += ', default: current date/time'
|
2018-02-20 22:41:19 +01:00
|
|
|
prop_str = '**%s** (*%s*)' % (prop_name, prop_type)
|
|
|
|
self.add_line(' - %s' % prop_str, '<stixattr>')
|
2018-03-16 21:10:53 +01:00
|
|
|
|
2018-02-20 22:41:19 +01:00
|
|
|
self.add_line('', '<stixattr>')
|
2018-02-20 20:48:53 +01:00
|
|
|
|
2018-02-22 15:55:15 +01:00
|
|
|
|
2018-03-21 18:56:50 +01:00
|
|
|
def autodoc_skipper(app, what, name, obj, skip, options):
|
|
|
|
"""Customize Sphinx to skip some member we don't want documented.
|
|
|
|
|
|
|
|
Skips anything containing ':autodoc-skip:' in its docstring.
|
|
|
|
"""
|
|
|
|
if obj.__doc__ and ':autodoc-skip:' in obj.__doc__:
|
|
|
|
return skip or True
|
|
|
|
return skip
|
|
|
|
|
|
|
|
|
2018-02-20 20:48:53 +01:00
|
|
|
def setup(app):
|
2018-03-16 21:10:53 +01:00
|
|
|
app.add_autodocumenter(STIXPropertyDocumenter)
|
2018-03-21 18:56:50 +01:00
|
|
|
app.connect('autodoc-skip-member', autodoc_skipper)
|