import logging

from marshmallow import Schema, fields, post_load

from great_expectations.core import DataContextKey, DataAssetIdentifierSchema
from great_expectations.exceptions import InvalidDataContextKeyError

logger = logging.getLogger(__name__)


class ExpectationSuiteIdentifier(DataContextKey):

    def __init__(self, expectation_suite_name):
        super(ExpectationSuiteIdentifier, self).__init__()
        self._expectation_suite_name = expectation_suite_name

    @property
    def expectation_suite_name(self):
        return self._expectation_suite_name

    def to_tuple(self):
        return self.expectation_suite_name,
        # return tuple(self.expectation_suite_name.split("."))

    @classmethod
    def from_tuple(cls, tuple_):
        return cls(expectation_suite_name=tuple_[0])
        # return cls(".".join(tuple_))


class ExpectationSuiteIdentifierSchema(Schema):
    expectation_suite_name = fields.Str()

    # noinspection PyUnusedLocal
    @post_load
    def make_expectation_suite_identifier(self, data, **kwargs):
        return ExpectationSuiteIdentifier(**data)


class BatchIdentifier(DataContextKey):

    def __init__(self, batch_identifier):
        super(BatchIdentifier, self).__init__()
        # batch_kwargs
        # if isinstance(batch_identifier, (BatchKwargs, dict)):
        #     self._batch_identifier = batch_identifier.batch_fingerprint
        # else:
        self._batch_identifier = batch_identifier

    @property
    def batch_identifier(self):
        return self._batch_identifier

    def to_tuple(self):
        return self.batch_identifier,

    @classmethod
    def from_tuple(cls, tuple_):
        return cls(batch_identifier=tuple_[0])


class BatchIdentifierSchema(Schema):
    batch_identifier = fields.Str()

    # noinspection PyUnusedLocal
    @post_load
    def make_batch_identifier(self, data, **kwargs):
        return BatchIdentifier(**data)


class ValidationResultIdentifier(DataContextKey):
    """A ValidationResultIdentifier identifies a validation result by the fully qualified expectation_suite_identifer
    and run_id.
    """

    def __init__(self, batch_identifier, expectation_suite_identifier, run_id):
        """Constructs a ValidationResultIdentifier

        Args:
            expectation_suite_identifier (ExpectationSuiteIdentifier, list, tuple, or dict):
                identifying information for the fully qualified expectation suite used to validate
            run_id (str): The run_id for which validation occurred
        """
        super(ValidationResultIdentifier, self).__init__()
        self._batch_identifier = batch_identifier
        self._expectation_suite_identifier = expectation_suite_identifier
        self._run_id = run_id

    @property
    def batch_identifier(self):
        return self._batch_identifier

    @property
    def expectation_suite_identifier(self):
        return self._expectation_suite_identifier

    @property
    def run_id(self):
        return self._run_id

    def to_tuple(self):
        return tuple(
            [self.batch_identifier] +
            list(self.expectation_suite_identifier.to_tuple()) +
            [self._run_id or ""]
        )
        # return self.batch_identifier, self.expectation_suite_identifier, self.run_id

    @classmethod
    def from_tuple(cls, tuple_):
        return cls(tuple_[0], ExpectationSuiteIdentifier.from_tuple(tuple_[1:-1]), tuple_[-1])


class ValidationResultIdentifierSchema(Schema):
    batch_identifier = fields.Nested(BatchIdentifierSchema, required=True)
    expectation_suite_identifier = fields.Nested(ExpectationSuiteIdentifierSchema, required=True, error_messages={
        'required': 'expectation_suite_identifier is required for a ValidationResultIdentifier'})
    run_id = fields.Str(required=True, error_messages={'required': "run_id is required for a "
                                                                   "ValidationResultIdentifier"})

    # noinspection PyUnusedLocal
    @post_load
    def make_validation_result_identifier(self, data, **kwargs):
        return ValidationResultIdentifier(**data)


class SiteSectionIdentifier(DataContextKey):
    def __init__(self, site_section_name, resource_identifier):
        self._site_section_name = site_section_name
        if site_section_name in ["validations", "profiling"]:
            if isinstance(resource_identifier, ValidationResultIdentifier):
                self._resource_identifier = resource_identifier
            elif isinstance(resource_identifier, (tuple, list)):
                self._resource_identifier = ValidationResultIdentifier(*resource_identifier)
            else:
                self._resource_identifier = ValidationResultIdentifier(**resource_identifier)
        elif site_section_name == "expectations":
            if isinstance(resource_identifier, ExpectationSuiteIdentifier):
                self._resource_identifier = resource_identifier
            elif isinstance(resource_identifier, (tuple, list)):
                self._resource_identifier = ExpectationSuiteIdentifier(*resource_identifier)
            else:
                self._resource_identifier = ExpectationSuiteIdentifier(**resource_identifier)
        else:
            raise InvalidDataContextKeyError(
                "SiteSectionIdentifier only supports 'validations' and 'expectations' as site section names"
            )

    @property
    def site_section_name(self):
        return self._site_section_name

    @property
    def resource_identifier(self):
        return self._resource_identifier

    def to_tuple(self):
        # if PY3:
        #     return (self.site_section_name, *self.resource_identifier.to_tuple())
        # else:
        site_section_identifier_tuple_list = [self.site_section_name] + list(self.resource_identifier.to_tuple())
        return tuple(site_section_identifier_tuple_list)

    @classmethod
    def from_tuple(cls, tuple_):
        if tuple_[0] == "validations":
            return cls(
                site_section_name=tuple_[0],
                resource_identifier=ValidationResultIdentifier.from_tuple(tuple_[1:])
            )
        elif tuple_[0] == "expectations":
            return cls(
                site_section_name=tuple_[0],
                resource_identifier=ExpectationSuiteIdentifier.from_tuple(tuple_[1:])
            )
        else:
            raise InvalidDataContextKeyError(
                "SiteSectionIdentifier only supports 'validations' and 'expectations' as site section names"
            )


dataAssetIdentifierSchema = DataAssetIdentifierSchema(strict=True)
expectationSuiteIdentifierSchema = ExpectationSuiteIdentifierSchema(strict=True)
validationResultIdentifierSchema = ValidationResultIdentifierSchema(strict=True)

@@ -588,32 +588,34 @@
 e(self):%0A       
+ #
  return self.exp
@@ -634,34 +634,32 @@
 te_name,%0A       
- #
  return tuple(se
@@ -746,32 +746,34 @@
 tuple_):%0A       
+ #
  return cls(expe
@@ -801,34 +801,32 @@
 ple_%5B0%5D)%0A       
- #
  return cls(%22.%22.

Switch back tuple logic