Esempio n. 1
0
    def __init__(
        self,
        version=None,
        data_license=None,
        name=None,
        spdx_id=None,
        namespace=None,
        comment=None,
        package=None,
        license_list_version=None,
    ):
        # avoid recursive import
        from spdx.creationinfo import CreationInfo

        self.version = version
        self.data_license = data_license
        self.name = name
        self.license_list_version=license_list_version
        self.spdx_id = spdx_id
        self.ext_document_references = []
        self.comment = comment
        self.namespace = namespace
        self.creation_info = CreationInfo()
        self.packages = []
        if package is not None:
            self.packages.append(package)
        self.extracted_licenses = []
        self.reviews = []
        self.annotations = []
        self.relationships = []
        self.snippet = []
Esempio n. 2
0
 def __init__(self, version=None, data_license=None, comment=None, package=None):
     # avoid recursive impor
     from spdx.creationinfo import CreationInfo
     self.version = version
     self.data_license = data_license
     self.comment = comment
     self.creation_info = CreationInfo()
     self.package = package
     self.extracted_licenses = []
     self.reviews = []
Esempio n. 3
0
 def __init__(self, version=None, data_license=None, name=None, spdx_id=None,
              namespace=None, comment=None, package=None):
     # avoid recursive impor
     from spdx.creationinfo import CreationInfo
     self.version = version
     self.data_license = data_license
     self.name = name
     self.spdx_id = spdx_id
     self.ext_document_references = []
     self.comment = comment
     self.namespace = namespace
     self.creation_info = CreationInfo()
     self.package = package
     self.extracted_licenses = []
     self.reviews = []
     self.annotations = []
Esempio n. 4
0
 def test_creators(self):
     ci = CreationInfo()
     assert len(ci.creators) == 0
     person = Person(name='Alice', email='*****@*****.**')
     tool = Tool(name='spdxtron-9000')
     org = Organization(name='Acme', email='*****@*****.**')
     ci.add_creator(tool)
     ci.add_creator(org)
     ci.add_creator(person)
     assert len(ci.creators) == 3
     assert tool in ci.creators
     assert org in ci.creators
     assert person in ci.creators
     ci.remove_creator(person)
     assert len(ci.creators) == 2
     assert tool in ci.creators
     assert org in ci.creators
     assert person not in ci.creators
 def test_creators(self):
     ci = CreationInfo()
     assert len(ci.creators) == 0
     person = Person(name='Alice', email='*****@*****.**')
     tool = Tool(name='spdxtron-9000')
     org = Organization(name='Acme', email='*****@*****.**')
     ci.add_creator(tool)
     ci.add_creator(org)
     ci.add_creator(person)
     assert len(ci.creators) == 3
     assert tool in ci.creators
     assert org in ci.creators
     assert person in ci.creators
     ci.remove_creator(person)
     assert len(ci.creators) == 2
     assert tool in ci.creators
     assert org in ci.creators
     assert person not in ci.creators
Esempio n. 6
0
 def test_license_list_version(self):
     ci = CreationInfo()
     assert ci.license_list_version == config.LICENSE_LIST_VERSION
     ci = CreationInfo(license_list_version=Version(major=1, minor=0))
     assert ci.license_list_version == Version(major=1, minor=0)
     assert not ci.license_list_version == Version(major=1, minor=2)
Esempio n. 7
0
 def test_comment(self):
     ci_default = CreationInfo()
     assert ci_default.comment is None
     ci_comment = CreationInfo(comment='Hello There')
     assert ci_comment.comment == 'Hello There'
Esempio n. 8
0
 def test_iso_format(self):
     dt = datetime(2014, 4, 8, 13, 42, 12)
     ci_time = CreationInfo(created=dt)
     assert ci_time.created_iso_format == "2014-04-08T13:42:12Z"
Esempio n. 9
0
 def test_timestamp(self):
     dt = datetime(2014, 4, 8, 13, 42, 12)
     ci_time = CreationInfo(created=dt)
     assert ci_time.created == dt
Esempio n. 10
0
class Document(object):
    """
    Represent an SPDX document with these fields:
    - version: Spec version. Mandatory, one - Type: Version.
    - data_license: SPDX-Metadata license. Mandatory, one. Type: License.
    - name: Name of the document. Mandatory, one. Type: str.
    - spdx_id: SPDX Identifier for the document to refer to itself in
      relationship to other elements. Mandatory, one. Type: str.
    - ext_document_references: External SPDX documents referenced within the
        given SPDX document. Optional, one or many. Type: ExternalDocumentRef
    - comment: Comments on the SPDX file, optional one. Type: str
    - namespace: SPDX document specific namespace. Mandatory, one. Type: str
    - creation_info: SPDX file creation info. Mandatory, one. Type: CreationInfo
    - package: Package described by this document. Mandatory, one. Type: Package
    - extracted_licenses: List of licenses extracted that are not part of the
      SPDX license list. Optional, many. Type: ExtractedLicense.
    - reviews: SPDX document review information, Optional zero or more.
      Type: Review.
    - annotations: SPDX document annotation information, Optional zero or more.
      Type: Annotation.
    """
    def __init__(self,
                 version=None,
                 data_license=None,
                 name=None,
                 spdx_id=None,
                 namespace=None,
                 comment=None,
                 package=None):
        # avoid recursive impor
        from spdx.creationinfo import CreationInfo
        self.version = version
        self.data_license = data_license
        self.name = name
        self.spdx_id = spdx_id
        self.ext_document_references = []
        self.comment = comment
        self.namespace = namespace
        self.creation_info = CreationInfo()
        self.package = package
        self.extracted_licenses = []
        self.reviews = []
        self.annotations = []

    def add_review(self, review):
        self.reviews.append(review)

    def add_annotation(self, annotation):
        self.annotations.append(annotation)

    def add_extr_lic(self, lic):
        self.extracted_licenses.append(lic)

    def add_ext_document_reference(self, ext_doc_ref):
        self.ext_document_references.append(ext_doc_ref)

    @property
    def files(self):
        return self.package.files

    @files.setter
    def files(self, value):
        self.package.files = value

    @property
    def has_comment(self):
        return self.comment is not None

    def validate(self, messages=None):
        """
        Validate all fields of the document and update the
        messages list with user friendly error messages for display.
        """
        # FIXME: messages should be returned
        messages = messages if messages is not None else []

        return (self.validate_version(messages)
                and self.validate_data_lics(messages)
                and self.validate_name(messages)
                and self.validate_spdx_id(messages)
                and self.validate_namespace(messages)
                and self.validate_ext_document_references(messages)
                and self.validate_creation_info(messages)
                and self.validate_package(messages)
                and self.validate_extracted_licenses(messages)
                and self.validate_reviews(messages))

    def validate_version(self, messages=None):
        # FIXME: messages should be returned
        messages = messages if messages is not None else []

        if self.version is None:
            messages.append('Document has no version.')
            return False
        else:
            return True

    def validate_data_lics(self, messages=None):
        # FIXME: messages should be returned
        messages = messages if messages is not None else []

        if self.data_license is None:
            messages.append('Document has no data license.')
            return False

        if self.data_license.identifier == 'CC0-1.0':
            return True
        else:
            # FIXME: REALLY? what if someone wants to use something else?
            messages.append('Document data license must be CC0-1.0.')
            return False

    def validate_name(self, messages=None):
        # FIXME: messages should be returned
        messages = messages if messages is not None else []

        if self.name is None:
            messages.append('Document has no name.')
            return False
        else:
            return True

    def validate_namespace(self, messages=None):
        # FIXME: messages should be returned
        messages = messages if messages is not None else []

        if self.namespace is None:
            messages.append('Document has no namespace.')
            return False
        else:
            return True

    def validate_spdx_id(self, messages=None):
        # FIXME: messages should be returned
        messages = messages if messages is not None else []

        if self.spdx_id is None:
            messages.append('Document has no SPDX Identifier.')
            return False

        if self.spdx_id.endswith('SPDXRef-DOCUMENT'):
            return True
        else:
            messages.append('Invalid Document SPDX Identifier value.')
            return False

    def validate_ext_document_references(self, messages=None):
        # FIXME: messages should be returned
        messages = messages if messages is not None else []

        valid = True
        for doc in self.ext_document_references:
            if isinstance(doc, ExternalDocumentRef):
                valid = doc.validate(messages) and valid
            else:
                messages.append(
                    'External document references must be of the type '
                    'spdx.document.ExternalDocumentRef and not ' + type(doc))
                valid = False
        return valid

    def validate_reviews(self, messages=None):
        # FIXME: messages should be returned
        messages = messages if messages is not None else []

        valid = True
        for review in self.reviews:
            valid = review.validate(messages) and valid
        return valid

    def validate_annotations(self, messages=None):
        # FIXME: messages should be returned
        messages = messages if messages is not None else []

        valid = True
        for annotation in self.annotations:
            valid = annotation.validate(messages) and valid
        return valid

    def validate_creation_info(self, messages=None):
        # FIXME: messages should be returned
        messages = messages if messages is not None else []

        if self.creation_info is not None:
            return self.creation_info.validate(messages)
        else:
            messages.append('Document has no creation information.')
            return False

    def validate_package(self, messages=None):
        # FIXME: messages should be returned
        messages = messages if messages is not None else []

        if self.package is not None:
            return self.package.validate(messages)
        else:
            messages.append('Document has no package.')
            return False

    def validate_extracted_licenses(self, messages=None):
        # FIXME: messages should be returned
        messages = messages if messages is not None else []

        valid = True
        for lic in self.extracted_licenses:
            if isinstance(lic, ExtractedLicense):
                valid = lic.validate(messages) and valid
            else:
                messages.append('Document extracted licenses must be of type '
                                'spdx.document.ExtractedLicense and not ' +
                                type(lic))
                valid = False
        return valid
Esempio n. 11
0
class Document(object):
    """
    Represent an SPDX document with these fields:
    - version: Spec version. Mandatory, one - Type: Version.
    - data_license: SPDX-Metadata license. Mandatory, one. Type: License.
    - name: Name of the document. Mandatory, one. Type: str.
    - spdx_id: SPDX Identifier for the document to refer to itself in
      relationship to other elements. Mandatory, one. Type: str.
    - ext_document_references: External SPDX documents referenced within the
        given SPDX document. Optional, one or many. Type: ExternalDocumentRef
    - comment: Comments on the SPDX file, optional one. Type: str
    - documentNamespace: SPDX document specific namespace. Mandatory, one. Type: str
    - creation_info: SPDX file creation info. Mandatory, one. Type: CreationInfo
    - package: Package described by this document. Mandatory, one. Type: Package
    - extracted_licenses: List of licenses extracted that are not part of the
      SPDX license list. Optional, many. Type: ExtractedLicense.
    - reviews: SPDX document review information, Optional zero or more.
      Type: Review.
    - annotations: SPDX document annotation information, Optional zero or more.
      Type: Annotation.
    - snippet: Snippet information. Optional zero or more. Type: Snippet.
    - relationships : Relationship between two SPDX elements. Optional zero or more.
      Type: Relationship. 
    """

    def __init__(
        self,
        version=None,
        data_license=None,
        name=None,
        spdx_id=None,
        namespace=None,
        comment=None,
        package=None,
        license_list_version=None,
    ):
        # avoid recursive import
        from spdx.creationinfo import CreationInfo

        self.version = version
        self.data_license = data_license
        self.name = name
        self.license_list_version=license_list_version
        self.spdx_id = spdx_id
        self.ext_document_references = []
        self.comment = comment
        self.namespace = namespace
        self.creation_info = CreationInfo()
        self.packages = []
        if package is not None:
            self.packages.append(package)
        self.extracted_licenses = []
        self.reviews = []
        self.annotations = []
        self.relationships = []
        self.snippet = []

    def add_review(self, review):
        self.reviews.append(review)

    def add_annotation(self, annotation):
        self.annotations.append(annotation)

    def add_relationships(self, relationship):
        self.relationships.append(relationship)

    def add_extr_lic(self, lic):
        self.extracted_licenses.append(lic)

    def add_ext_document_reference(self, ext_doc_ref):
        self.ext_document_references.append(ext_doc_ref)

    def add_snippet(self, snip):
        self.snippet.append(snip)

    def add_package(self, package):
        self.packages.append(package)

    # For backwards compatibility with older versions, we support a
    # mode where the first package in a document may be referred to as
    # the document's "package", and the files it contains may be
    # referred to as the document's files.  This usage is deprecated.

    @property
    def package(self):
        warnings.warn('document.package and document.files are deprecated; '
                      'use document.packages instead',
                      DeprecationWarning)
        if len(self.packages) == 0:
            return None
        else:
            return self.packages[0]

    @package.setter
    def package(self, value):
        warnings.warn('document.package and document.files are deprecated; '
                      'use document.packages instead',
                      DeprecationWarning)
        if len(self.packages) == 0:
            self.packages.append(value)
        else:
            self.packages[0] = value

    @property
    def files(self):
        return self.package.files

    @files.setter
    def files(self, value):
        self.package.files = value

    @property
    def has_comment(self):
        return self.comment is not None

    def validate(self, messages=None):
        """
        Validate all fields of the document and update the
        messages list with user friendly error messages for display.
        """
        if isinstance(messages, list):
            raise TypeError("messages should be None or an instance of ErrorMessages")
        if messages is None:
            messages = ErrorMessages()

        messages.push_context(self.name)
        self.validate_version(messages)
        self.validate_data_lics(messages)
        self.validate_name(messages)
        self.validate_spdx_id(messages)
        self.validate_namespace(messages)
        self.validate_ext_document_references(messages)
        self.validate_creation_info(messages)
        self.validate_packages(messages)
        self.validate_extracted_licenses(messages)
        self.validate_reviews(messages)
        self.validate_snippet(messages)
        self.validate_annotations(messages)
        self.validate_relationships(messages)
        messages.pop_context()
        return messages

    def validate_version(self, messages):
        if self.version is None:
            messages.append("Document has no version.")

    def validate_data_lics(self, messages):
        if self.data_license is None:
            messages.append("Document has no data license.")
        else:
            # FIXME: REALLY? what if someone wants to use something else?
            if self.data_license.identifier != "CC0-1.0":
                messages.append("Document data license must be CC0-1.0.")

    def validate_name(self, messages):
        if self.name is None:
            messages.append("Document has no name.")

    def validate_namespace(self, messages):
        if self.namespace is None:
            messages.append("Document has no namespace.")

    def validate_spdx_id(self, messages):
        if self.spdx_id is None:
            messages.append("Document has no SPDX Identifier.")
        else:
            if not self.spdx_id.endswith("SPDXRef-DOCUMENT"):
                messages.append("Invalid Document SPDX Identifier value.")

    def validate_ext_document_references(self, messages):
        for doc in self.ext_document_references:
            if isinstance(doc, ExternalDocumentRef):
                messages = doc.validate(messages)
            else:
                messages = list(messages) + [
                    "External document references must be of the type "
                    "spdx.document.ExternalDocumentRef and not " + str(type(doc))
                ]
    def validate_reviews(self, messages):
        for review in self.reviews:
            messages = review.validate(messages)

    def validate_annotations(self, messages):
        for annotation in self.annotations:
            messages = annotation.validate(messages)

    def validate_relationships(self, messages):
        for relationship in self.relationships:
            messages = relationship.validate(messages)

    def validate_snippet(self, messages=None):
        for snippet in self.snippet:
            snippet.validate(messages)

    def validate_creation_info(self, messages):
        if self.creation_info is not None:
            self.creation_info.validate(messages)
        else:
            messages.append("Document has no creation information.")

    def validate_packages(self, messages):
        if len(self.packages) > 0:
            for package in self.packages:
                messages = package.validate(messages)
        else:
            messages.append("Document has no packages.")

    def validate_package(self, messages):
        if self.package is not None:
            self.package.validate(messages)
        else:
            messages.append("Document has no packages.")

    def validate_extracted_licenses(self, messages):
        for lic in self.extracted_licenses:
            if isinstance(lic, ExtractedLicense):
                messages = lic.validate(messages)
            else:
                messages.append(
                    "Document extracted licenses must be of type "
                    "spdx.document.ExtractedLicense and not " + type(lic)
                )
Esempio n. 12
0
class Document(object):
    """
    Represent an SPDX document with these fields:
    - version: Spec version. Mandatory, one - Type: Version.
    - data_license: SPDX-Metadata license. Mandatory, one. Type: License.
    - name: Name of the document. Mandatory, one. Type: str.
    - spdx_id: SPDX Identifier for the document to refer to itself in
      relationship to other elements. Mandatory, one. Type: str.
    - ext_document_references: External SPDX documents referenced within the
        given SPDX document. Optional, one or many. Type: ExternalDocumentRef
    - comment: Comments on the SPDX file, optional one. Type: str
    - documentNamespace: SPDX document specific namespace. Mandatory, one. Type: str
    - creation_info: SPDX file creation info. Mandatory, one. Type: CreationInfo
    - package: Package described by this document. Mandatory, one. Type: Package
    - extracted_licenses: List of licenses extracted that are not part of the
      SPDX license list. Optional, many. Type: ExtractedLicense.
    - reviews: SPDX document review information, Optional zero or more.
      Type: Review.
    - annotations: SPDX document annotation information, Optional zero or more.
      Type: Annotation.
    - snippet: Snippet information. Optional zero or more. Type: Snippet.
    - relationships : Relationship between two SPDX elements. Optional zero or more.
      Type: Relationship. 
    """
    def __init__(
        self,
        version=None,
        data_license=None,
        name=None,
        spdx_id=None,
        namespace=None,
        comment=None,
        package=None,
    ):
        # avoid recursive import
        from spdx.creationinfo import CreationInfo

        self.version = version
        self.data_license = data_license
        self.name = name
        self.spdx_id = spdx_id
        self.ext_document_references = []
        self.comment = comment
        self.namespace = namespace
        self.creation_info = CreationInfo()
        self.package = package
        self.extracted_licenses = []
        self.reviews = []
        self.annotations = []
        self.relationships = []
        self.snippet = []

    def add_review(self, review):
        self.reviews.append(review)

    def add_annotation(self, annotation):
        self.annotations.append(annotation)

    def add_relationships(self, relationship):
        self.relationships.append(relationship)

    def add_extr_lic(self, lic):
        self.extracted_licenses.append(lic)

    def add_ext_document_reference(self, ext_doc_ref):
        self.ext_document_references.append(ext_doc_ref)

    def add_snippet(self, snip):
        self.snippet.append(snip)

    @property
    def files(self):
        return self.package.files

    @files.setter
    def files(self, value):
        self.package.files = value

    @property
    def has_comment(self):
        return self.comment is not None

    def validate(self, messages):
        """
        Validate all fields of the document and update the
        messages list with user friendly error messages for display.
        """
        messages = self.validate_version(messages)
        messages = self.validate_data_lics(messages)
        messages = self.validate_name(messages)
        messages = self.validate_spdx_id(messages)
        messages = self.validate_namespace(messages)
        messages = self.validate_ext_document_references(messages)
        messages = self.validate_creation_info(messages)
        messages = self.validate_package(messages)
        messages = self.validate_extracted_licenses(messages)
        messages = self.validate_reviews(messages)
        messages = self.validate_snippet(messages)
        # messages = self.validate_annotations(messages)
        # messages = self.validate_relationships(messages)

        return messages

    def validate_version(self, messages):
        if self.version is None:
            messages = messages + ["Document has no version."]

        return messages

    def validate_data_lics(self, messages):
        if self.data_license is None:
            messages = messages + ["Document has no data license."]
        else:
            # FIXME: REALLY? what if someone wants to use something else?
            if self.data_license.identifier != "CC0-1.0":
                messages = messages + [
                    "Document data license must be CC0-1.0."
                ]

        return messages

    def validate_name(self, messages):
        if self.name is None:
            messages = messages + ["Document has no name."]

        return messages

    def validate_namespace(self, messages):
        if self.namespace is None:
            messages = messages + ["Document has no namespace."]

        return messages

    def validate_spdx_id(self, messages):
        if self.spdx_id is None:
            messages = messages + ["Document has no SPDX Identifier."]
        else:
            if not self.spdx_id.endswith("SPDXRef-DOCUMENT"):
                messages = messages + [
                    "Invalid Document SPDX Identifier value."
                ]

        return messages

    def validate_ext_document_references(self, messages):
        for doc in self.ext_document_references:
            if isinstance(doc, ExternalDocumentRef):
                messages = doc.validate(messages)
            else:
                messages = list(messages) + [
                    "External document references must be of the type "
                    "spdx.document.ExternalDocumentRef and not " +
                    str(type(doc))
                ]
        return messages

    def validate_reviews(self, messages):
        for review in self.reviews:
            messages = review.validate(messages)

        return messages

    def validate_annotations(self, messages):
        for annotation in self.annotations:
            messages = annotation.validate(messages)

        return messages

    def validate_relationships(self, messages):
        for relationship in self.relationships:
            messages = relationship.validate(messages)

        return messages

    def validate_snippet(self, messages=None):
        for snippet in self.snippet:
            messages = snippet.validate(messages)

        return messages

    def validate_creation_info(self, messages):
        if self.creation_info is not None:
            messages = self.creation_info.validate(messages)
        else:
            messages = messages + ["Document has no creation information."]

        return messages

    def validate_package(self, messages):
        if self.package is not None:
            messages = self.package.validate(messages)
        else:
            messages = messages + ["Document has no package."]

        return messages

    def validate_extracted_licenses(self, messages):
        for lic in self.extracted_licenses:
            if isinstance(lic, ExtractedLicense):
                messages = lic.validate(messages)
            else:
                messages = messages + [
                    "Document extracted licenses must be of type "
                    "spdx.document.ExtractedLicense and not " + type(lic)
                ]
        return messages
Esempio n. 13
0
class Document(object):
    """Represents an SPDX document.
        Fields:
        version: Spec version. Mandatory, one - Type: Version.
        data_license: SPDX-Metadata license. Mandatory, one. Type: License.
        comment: Comments on the SPDX file, optional one. Type: str
        creation_info: SPDX file creation info. Mandatory, one. Type: CreationInfo
        package: Package described by this document. Mandatory, one. Type: Package
        extracted_licenses: List of licenses extracted that are not part of the
            SPDX license list. Optional, many. Type: ExtractedLicense.
        reviews: SPDX document review information, Optional zero or more.
            Type: Review.
    """
    def __init__(self,
                 version=None,
                 data_license=None,
                 comment=None,
                 package=None):
        # avoid recursive impor
        from spdx.creationinfo import CreationInfo

        super(Document, self).__init__()
        self.version = version
        self.data_license = data_license
        self.comment = comment
        self.creation_info = CreationInfo()
        self.package = package
        self.extracted_licenses = []
        self.reviews = []

    def add_review(self, review):
        self.reviews.append(review)

    def add_extr_lic(self, lic):
        self.extracted_licenses.append(lic)

    @property
    def files(self):
        return self.package.files

    @files.setter
    def files(self, value):
        self.package.files = value

    @property
    def has_comment(self):
        return self.comment is not None

    def validate(self, messages=[]):
        """Validate all fields of the document.
        messages - appends user friendly error messages to this list for display.
        """
        return (self.validate_version(messages)
                and self.validate_data_lics(messages)
                and self.validate_creation_info(messages)
                and self.validate_package(messages)
                and self.validate_extracted_licenses(messages)
                and self.validate_reviews(messages))

    def validate_version(self, messages):
        if self.version is None:
            messages.append('Document has no version.')
            return False
        else:
            return True

    def validate_data_lics(self, messages):
        if self.data_license is not None:
            if self.data_license.identifier == 'CC0-1.0':
                return True
            else:
                messages.append('Document data license must be CC0-1.0.')
                return False
        else:
            messages.append('Document has no data license.')
            return False

    def validate_reviews(self, messages):
        status = True
        for review in self.reviews:
            status = status and review.validate(messages)
        return status

    def validate_creation_info(self, messages):
        if self.creation_info is not None:
            return self.creation_info.validate(messages)
        else:
            messages.append('Document has no creation information.')
            return False

    def validate_package(self, messages):
        if self.package is not None:
            return self.package.validate(messages)
        else:
            messages.append('Document has no package.')
            return False

    def validate_extracted_licenses(self, messages):
        status = True
        for lic in self.extracted_licenses:
            if isinstance(lic, ExtractedLicense):
                status = status and lic.validate(messages)
            else:
                messages.append('Document extracted licenses must be of type' +
                                'spdx.document.ExtractedLicense')
                return False

        return status
Esempio n. 14
0
class Document(object):
    """
    Represent an SPDX document with these fields:
    - version: Spec version. Mandatory, one - Type: Version.
    - data_license: SPDX-Metadata license. Mandatory, one. Type: License.
    - comment: Comments on the SPDX file, optional one. Type: str
    - creation_info: SPDX file creation info. Mandatory, one. Type: CreationInfo
    - package: Package described by this document. Mandatory, one. Type: Package
    - extracted_licenses: List of licenses extracted that are not part of the
      SPDX license list. Optional, many. Type: ExtractedLicense.
    - reviews: SPDX document review information, Optional zero or more.
      Type: Review.
    """

    def __init__(self, version=None, data_license=None, comment=None, package=None):
        # avoid recursive impor
        from spdx.creationinfo import CreationInfo
        self.version = version
        self.data_license = data_license
        self.comment = comment
        self.creation_info = CreationInfo()
        self.package = package
        self.extracted_licenses = []
        self.reviews = []

    def add_review(self, review):
        self.reviews.append(review)

    def add_extr_lic(self, lic):
        self.extracted_licenses.append(lic)

    @property
    def files(self):
        return self.package.files

    @files.setter
    def files(self, value):
        self.package.files = value

    @property
    def has_comment(self):
        return self.comment is not None

    def validate(self, messages=None):
        """
        Validate all fields of the document and update the
        messages list with user friendly error messages for display.
        """
        # FIXME: messages should be returned
        messages = messages if messages is not None else []

        return (self.validate_version(messages)
            and self.validate_data_lics(messages)
            and self.validate_creation_info(messages)
            and self.validate_package(messages)
            and self.validate_extracted_licenses(messages)
            and self.validate_reviews(messages)
        )

    def validate_version(self, messages=None):
        # FIXME: messages should be returned
        messages = messages if messages is not None else []

        if self.version is None:
            messages.append('Document has no version.')
            return False
        else:
            return True

    def validate_data_lics(self, messages=None):
        # FIXME: messages should be returned
        messages = messages if messages is not None else []

        if self.data_license is None:
            messages.append('Document has no data license.')
            return False

        if self.data_license.identifier == 'CC0-1.0':
            return True
        else:
            # FIXME: REALLY? what if someone wants to use something else?
            messages.append('Document data license must be CC0-1.0.')
            return False

    def validate_reviews(self, messages=None):
        # FIXME: messages should be returned
        messages = messages if messages is not None else []

        valid = True
        for review in self.reviews:
            valid = review.validate(messages) and valid
        return valid

    def validate_creation_info(self, messages=None):
        # FIXME: messages should be returned
        messages = messages if messages is not None else []

        if self.creation_info is not None:
            return self.creation_info.validate(messages)
        else:
            messages.append('Document has no creation information.')
            return False

    def validate_package(self, messages=None):
        # FIXME: messages should be returned
        messages = messages if messages is not None else []

        if self.package is not None:
            return self.package.validate(messages)
        else:
            messages.append('Document has no package.')
            return False

    def validate_extracted_licenses(self, messages=None):
        # FIXME: messages should be returned
        messages = messages if messages is not None else []

        valid = True
        for lic in self.extracted_licenses:
            if isinstance(lic, ExtractedLicense):
                valid = lic.validate(messages) and valid
            else:
                messages.append(
                    'Document extracted licenses must be of type '
                    'spdx.document.ExtractedLicense and not ' + type(lic))
                valid = False
        return valid