From eac1ce94de86b7ca314c1129128ec263a2af9926 Mon Sep 17 00:00:00 2001 From: Chris Lenk Date: Fri, 22 Sep 2017 11:03:25 -0400 Subject: [PATCH 1/2] Improve docstrings for Sphinx output Also remove package and module names from classes and functions. Also remove stix2.base from docs. We hide all private classes and functions from the docs, so the only thing the documentation for base included was STIXJSONEncoder. --- docs/api/stix2.base.rst | 5 --- docs/conf.py | 1 + stix2/__init__.py | 1 - stix2/common.py | 20 +++++------ stix2/core.py | 2 +- stix2/exceptions.py | 10 +++--- stix2/markings/granular_markings.py | 2 ++ stix2/markings/object_markings.py | 2 ++ stix2/markings/utils.py | 2 ++ stix2/observables.py | 30 ++++++++--------- stix2/properties.py | 51 +++++++++++++++-------------- stix2/sdo.py | 4 +-- 12 files changed, 65 insertions(+), 65 deletions(-) delete mode 100644 docs/api/stix2.base.rst diff --git a/docs/api/stix2.base.rst b/docs/api/stix2.base.rst deleted file mode 100644 index 459f2e5..0000000 --- a/docs/api/stix2.base.rst +++ /dev/null @@ -1,5 +0,0 @@ -base -========== - -.. automodule:: stix2.base - :members: \ No newline at end of file diff --git a/docs/conf.py b/docs/conf.py index daa1d30..6a20ace 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -19,6 +19,7 @@ autodoc_member_order = 'groupwise' autosummary_generate = True napoleon_numpy_docstring = False # Force consistency, leave only Google napoleon_use_rtype = False +add_module_names = False templates_path = ['_templates'] source_suffix = '.rst' diff --git a/stix2/__init__.py b/stix2/__init__.py index 8f5239a..770f8cb 100644 --- a/stix2/__init__.py +++ b/stix2/__init__.py @@ -3,7 +3,6 @@ .. autosummary:: :toctree: api - base common core environment diff --git a/stix2/common.py b/stix2/common.py index a2e6918..8f34ed6 100644 --- a/stix2/common.py +++ b/stix2/common.py @@ -65,7 +65,7 @@ class StatementMarking(_STIXBase): class MarkingProperty(Property): - """Represent the marking objects in the `definition` property of + """Represent the marking objects in the ``definition`` property of marking-definition objects. """ @@ -120,17 +120,15 @@ def _register_marking(cls): def CustomMarking(type='x-custom-marking', properties=None): - """ - Custom STIX Marking decorator. + """Custom STIX Marking decorator. - Examples: - - @CustomMarking('x-custom-marking', [ - ('property1', StringProperty(required=True)), - ('property2', IntegerProperty()), - ]) - class MyNewMarkingObjectType(): - pass + Example: + >>> @CustomMarking('x-custom-marking', [ + ... ('property1', StringProperty(required=True)), + ... ('property2', IntegerProperty()), + ... ]) + ... class MyNewMarkingObjectType(): + ... pass """ def custom_builder(cls): diff --git a/stix2/core.py b/stix2/core.py index 0271e34..3eaabb0 100644 --- a/stix2/core.py +++ b/stix2/core.py @@ -1,4 +1,4 @@ -"""STIX 2.0 Objects that are neither SDOs nor SROs""" +"""STIX 2.0 Objects that are neither SDOs nor SROs.""" from collections import OrderedDict diff --git a/stix2/exceptions.py b/stix2/exceptions.py index 32db472..17aa8bf 100644 --- a/stix2/exceptions.py +++ b/stix2/exceptions.py @@ -3,7 +3,7 @@ class STIXError(Exception): class InvalidValueError(STIXError, ValueError): - """An invalid value was provided to a STIX object's __init__.""" + """An invalid value was provided to a STIX object's ``__init__``.""" def __init__(self, cls, prop_name, reason): super(InvalidValueError, self).__init__() @@ -45,7 +45,7 @@ class ExtraPropertiesError(STIXError, TypeError): class ImmutableError(STIXError, ValueError): - """Attempted to modify an object after creation""" + """Attempted to modify an object after creation.""" def __init__(self, cls, key): super(ImmutableError, self).__init__() @@ -85,7 +85,7 @@ class InvalidObjRefError(STIXError, ValueError): class UnmodifiablePropertyError(STIXError, ValueError): - """Attempted to modify an unmodifiable property of object when creating a new version""" + """Attempted to modify an unmodifiable property of object when creating a new version.""" def __init__(self, unchangable_properties): super(UnmodifiablePropertyError, self).__init__() @@ -139,7 +139,7 @@ class AtLeastOnePropertyError(STIXError, TypeError): class RevokeError(STIXError, ValueError): - """Attempted to an operation on a revoked object""" + """Attempted to an operation on a revoked object.""" def __init__(self, called_by): super(RevokeError, self).__init__() @@ -153,7 +153,7 @@ class RevokeError(STIXError, ValueError): class ParseError(STIXError, ValueError): - """Could not parse object""" + """Could not parse object.""" def __init__(self, msg): super(ParseError, self).__init__(msg) diff --git a/stix2/markings/granular_markings.py b/stix2/markings/granular_markings.py index 7e9ccc7..893428e 100644 --- a/stix2/markings/granular_markings.py +++ b/stix2/markings/granular_markings.py @@ -1,3 +1,5 @@ +"""Functions for working with STIX 2.0 granular markings. +""" from stix2 import exceptions from stix2.markings import utils diff --git a/stix2/markings/object_markings.py b/stix2/markings/object_markings.py index c39c036..ce77966 100644 --- a/stix2/markings/object_markings.py +++ b/stix2/markings/object_markings.py @@ -1,3 +1,5 @@ +"""Functions for working with STIX 2.0 object markings. +""" from stix2 import exceptions from stix2.markings import utils diff --git a/stix2/markings/utils.py b/stix2/markings/utils.py index f5400a5..6fed976 100644 --- a/stix2/markings/utils.py +++ b/stix2/markings/utils.py @@ -1,3 +1,5 @@ +"""Utility functions for STIX 2.0 data markings. +""" import collections diff --git a/stix2/observables.py b/stix2/observables.py index e9939e7..e1f6bf8 100644 --- a/stix2/observables.py +++ b/stix2/observables.py @@ -1,8 +1,8 @@ -"""STIX 2.0 Cyber Observable Objects +"""STIX 2.0 Cyber Observable Objects. Embedded observable object types, such as Email MIME Component, which is -embedded in Email Message objects, inherit from _STIXBase instead of Observable -and do not have a '_type' attribute. +embedded in Email Message objects, inherit from ``_STIXBase`` instead of +Observable and do not have a ``_type`` attribute. """ from collections import OrderedDict @@ -19,6 +19,8 @@ from .utils import get_dict class ObservableProperty(Property): + """Property for holding Cyber Observable Objects. + """ def clean(self, value): try: @@ -39,7 +41,7 @@ class ObservableProperty(Property): class ExtensionsProperty(DictionaryProperty): - """ Property for representing extensions on Observable objects + """Property for representing extensions on Observable objects. """ def __init__(self, enclosing_type=None, required=False): @@ -138,7 +140,6 @@ class EmailAddress(_Observable): ('display_name', StringProperty()), ('belongs_to_ref', ObjectReferenceProperty(valid_types='user-account')), ('extensions', ExtensionsProperty(enclosing_type=_type)), - ]) @@ -798,16 +799,15 @@ def _register_observable(new_observable): def CustomObservable(type='x-custom-observable', properties=None): - """Custom STIX Cyber Observable type decorator + """Custom STIX Cyber Observable Object type decorator. - Example 1: - - @CustomObservable('x-custom-observable', [ - ('property1', StringProperty(required=True)), - ('property2', IntegerProperty()), - ]) - class MyNewObservableType(): - pass + Example: + >>> @CustomObservable('x-custom-observable', [ + ... ('property1', StringProperty(required=True)), + ... ('property2', IntegerProperty()), + ... ]) + ... class MyNewObservableType(): + ... pass """ def custom_builder(cls): @@ -873,7 +873,7 @@ def _register_extension(observable, new_extension): def CustomExtension(observable=None, type='x-custom-observable', properties={}): - """Decorator for custom extensions to STIX Cyber Observables + """Decorator for custom extensions to STIX Cyber Observables. """ if not observable or not issubclass(observable, _Observable): diff --git a/stix2/properties.py b/stix2/properties.py index 92f1a58..afe994f 100644 --- a/stix2/properties.py +++ b/stix2/properties.py @@ -19,43 +19,44 @@ class Property(object): """Represent a property of STIX data type. Subclasses can define the following attributes as keyword arguments to - __init__(): + ``__init__()``. - - `required` - If `True`, the property must be provided when creating an - object with that property. No default value exists for these properties. - (Default: `False`) - - `fixed` - This provides a constant default value. Users are free to - provide this value explicity when constructing an object (which allows - you to copy *all* values from an existing object to a new object), but - if the user provides a value other than the `fixed` value, it will raise - an error. This is semantically equivalent to defining both: - - a `clean()` function that checks if the value matches the fixed - value, and - - a `default()` function that returns the fixed value. - (Default: `None`) + Args: + required (bool): If ``True``, the property must be provided when creating an + object with that property. No default value exists for these properties. + (Default: ``False``) + fixed: This provides a constant default value. Users are free to + provide this value explicity when constructing an object (which allows + you to copy **all** values from an existing object to a new object), but + if the user provides a value other than the ``fixed`` value, it will raise + an error. This is semantically equivalent to defining both: - Subclasses can also define the following functions. + - a ``clean()`` function that checks if the value matches the fixed + value, and + - a ``default()`` function that returns the fixed value. - - `def clean(self, value) -> any:` - - Return a value that is valid for this property. If `value` is not + Subclasses can also define the following functions: + + - ``def clean(self, value) -> any:`` + - Return a value that is valid for this property. If ``value`` is not valid for this property, this will attempt to transform it first. If - `value` is not valid and no such transformation is possible, it should + ``value`` is not valid and no such transformation is possible, it should raise a ValueError. - - `def default(self):` + - ``def default(self):`` - provide a default value for this property. - - `default()` can return the special value `NOW` to use the current + - ``default()`` can return the special value ``NOW`` to use the current time. This is useful when several timestamps in the same object need to use the same default value, so calling now() for each property-- likely several microseconds apart-- does not work. - Subclasses can instead provide a lambda function for `default` as a keyword - argument. `clean` should not be provided as a lambda since lambdas cannot + Subclasses can instead provide a lambda function for ``default`` as a keyword + argument. ``clean`` should not be provided as a lambda since lambdas cannot raise their own exceptions. - When instantiating Properties, `required` and `default` should not be used - together. `default` implies that the property is required in the specification + When instantiating Properties, ``required`` and ``default`` should not be used + together. ``default`` implies that the property is required in the specification so this function will be used to supply a value if none is provided. - `required` means that the user must provide this; it is required in the + ``required`` means that the user must provide this; it is required in the specification and we can't or don't want to create a default value. """ @@ -88,7 +89,7 @@ class ListProperty(Property): def __init__(self, contained, **kwargs): """ - Contained should be a function which returns an object from the value. + ``contained`` should be a function which returns an object from the value. """ if inspect.isclass(contained) and issubclass(contained, Property): # If it's a class and not an instance, instantiate it so that diff --git a/stix2/sdo.py b/stix2/sdo.py index d24ba53..cdbb9ca 100644 --- a/stix2/sdo.py +++ b/stix2/sdo.py @@ -298,8 +298,8 @@ def CustomObject(type='x-custom-type', properties=None): ... class MyNewObjectType(): ... pass - Supply an __init__() function to add any special validations to the custom - type. Don't call super().__init__() though - doing so will cause an error. + Supply an ``__init__()`` function to add any special validations to the custom + type. Don't call ``super().__init__()`` though - doing so will cause an error. Example: >>> @CustomObject('x-type-name', [ From b6d1bb26de500d4b4c325aae30fa38844ec9cef5 Mon Sep 17 00:00:00 2001 From: Chris Lenk Date: Fri, 22 Sep 2017 14:54:21 -0400 Subject: [PATCH 2/2] Improve utils docs, rename subpackage docs folders --- .../stix2.markings.granular_markings.rst | 0 .../stix2.markings.object_markings.rst | 0 .../stix2.markings.utils.rst | 0 .../stix2.sources.filesystem.rst | 0 .../stix2.sources.filters.rst | 0 .../{api => sources}/stix2.sources.memory.rst | 0 .../{api => sources}/stix2.sources.taxii.rst | 0 stix2/markings/__init__.py | 2 +- stix2/sources/__init__.py | 2 +- stix2/utils.py | 29 ++++++++++++++----- 10 files changed, 23 insertions(+), 10 deletions(-) rename docs/api/{api => markings}/stix2.markings.granular_markings.rst (100%) rename docs/api/{api => markings}/stix2.markings.object_markings.rst (100%) rename docs/api/{api => markings}/stix2.markings.utils.rst (100%) rename docs/api/{api => sources}/stix2.sources.filesystem.rst (100%) rename docs/api/{api => sources}/stix2.sources.filters.rst (100%) rename docs/api/{api => sources}/stix2.sources.memory.rst (100%) rename docs/api/{api => sources}/stix2.sources.taxii.rst (100%) diff --git a/docs/api/api/stix2.markings.granular_markings.rst b/docs/api/markings/stix2.markings.granular_markings.rst similarity index 100% rename from docs/api/api/stix2.markings.granular_markings.rst rename to docs/api/markings/stix2.markings.granular_markings.rst diff --git a/docs/api/api/stix2.markings.object_markings.rst b/docs/api/markings/stix2.markings.object_markings.rst similarity index 100% rename from docs/api/api/stix2.markings.object_markings.rst rename to docs/api/markings/stix2.markings.object_markings.rst diff --git a/docs/api/api/stix2.markings.utils.rst b/docs/api/markings/stix2.markings.utils.rst similarity index 100% rename from docs/api/api/stix2.markings.utils.rst rename to docs/api/markings/stix2.markings.utils.rst diff --git a/docs/api/api/stix2.sources.filesystem.rst b/docs/api/sources/stix2.sources.filesystem.rst similarity index 100% rename from docs/api/api/stix2.sources.filesystem.rst rename to docs/api/sources/stix2.sources.filesystem.rst diff --git a/docs/api/api/stix2.sources.filters.rst b/docs/api/sources/stix2.sources.filters.rst similarity index 100% rename from docs/api/api/stix2.sources.filters.rst rename to docs/api/sources/stix2.sources.filters.rst diff --git a/docs/api/api/stix2.sources.memory.rst b/docs/api/sources/stix2.sources.memory.rst similarity index 100% rename from docs/api/api/stix2.sources.memory.rst rename to docs/api/sources/stix2.sources.memory.rst diff --git a/docs/api/api/stix2.sources.taxii.rst b/docs/api/sources/stix2.sources.taxii.rst similarity index 100% rename from docs/api/api/stix2.sources.taxii.rst rename to docs/api/sources/stix2.sources.taxii.rst diff --git a/stix2/markings/__init__.py b/stix2/markings/__init__.py index 6c13b87..400c54d 100644 --- a/stix2/markings/__init__.py +++ b/stix2/markings/__init__.py @@ -6,7 +6,7 @@ granular markings unless otherwise noted in each of the functions. .. autosummary:: - :toctree: api + :toctree: markings granular_markings object_markings diff --git a/stix2/sources/__init__.py b/stix2/sources/__init__.py index 8e19d1d..a8c27da 100644 --- a/stix2/sources/__init__.py +++ b/stix2/sources/__init__.py @@ -16,7 +16,7 @@ Note: .. autosummary:: - :toctree: api + :toctree: sources filters filesystem diff --git a/stix2/utils.py b/stix2/utils.py index ca195f6..8b9a136 100644 --- a/stix2/utils.py +++ b/stix2/utils.py @@ -34,16 +34,21 @@ class STIXdatetime(dt.datetime): def get_timestamp(): + """Return a STIX timestamp of the current date and time.""" return STIXdatetime.now(tz=pytz.UTC) def format_datetime(dttm): - # 1. Convert to timezone-aware - # 2. Convert to UTC - # 3. Format in ISO format - # 4. Ensure correct precision - # 4a. Add subsecond value if non-zero and precision not defined - # 5. Add "Z" + """Convert a datetime object into a valid STIX timestamp string. + + 1. Convert to timezone-aware + 2. Convert to UTC + 3. Format in ISO format + 4. Ensure correct precision + a. Add subsecond value if non-zero and precision not defined + 5. Add "Z" + + """ if dttm.tzinfo is None or dttm.tzinfo.utcoffset(dttm) is None: # dttm is timezone-naive; assume UTC @@ -63,6 +68,8 @@ def format_datetime(dttm): def parse_into_datetime(value, precision=None): + """Parse a value into a valid STIX timestamp object. + """ if isinstance(value, dt.date): if hasattr(value, 'hour'): ts = value @@ -102,6 +109,7 @@ def parse_into_datetime(value, precision=None): def get_dict(data): """Return data as a dictionary. + Input can be a dictionary, string, or file-like object. """ @@ -124,7 +132,7 @@ def get_dict(data): def find_property_index(obj, properties, tuple_to_find): """Recursively find the property in the object model, return the index - according to the _properties OrderedDict. If its a list look for + according to the _properties OrderedDict. If it's a list look for individual objects. """ from .base import _STIXBase @@ -159,7 +167,7 @@ def find_property_index(obj, properties, tuple_to_find): def new_version(data, **kwargs): """Create a new version of a STIX object, by modifying properties and - updating the `modified` property. + updating the ``modified`` property. """ if not isinstance(data, Mapping): @@ -196,6 +204,11 @@ def new_version(data, **kwargs): def revoke(data): + """Revoke a STIX object. + + Returns: + A new version of the object with ``revoked`` set to ``True``. + """ if not isinstance(data, Mapping): raise ValueError('cannot revoke object of this type! Try a dictionary ' 'or instance of an SDO or SRO class.')