Пример #1
0
    def test_facts_stored_with_context(self):
        # Test we can store 2 facts of the same concept but with different
        # contexts, and pull them both back out.
        doc = Entrypoint("CutSheet", self.taxonomy)
        concept = "solar:InverterCutSheetNotes"

        ctx_jan = Context(
            duration={
                "start": datetime(year=2018, month=1, day=1),
                "end": datetime(year=2018, month=2, day=1)
            },
            entity="JUPITER",
            ProductIdentifierAxis="placeholder",
            TestConditionAxis="solar:StandardTestConditionMember")
        ctx_feb = Context(
            duration={
                "start": datetime(year=2018, month=2, day=1),
                "end": datetime(year=2018, month=3, day=1)
            },
            entity="JUPITER",
            ProductIdentifierAxis="placeholder",
            TestConditionAxis="solar:StandardTestConditionMember")

        doc.set(concept, "Jan Value", context=ctx_jan)
        doc.set(concept, "Feb Value", context=ctx_feb)

        jan_fact = doc.get(concept, context=ctx_jan)
        feb_fact = doc.get(concept, context=ctx_feb)

        self.assertEqual(jan_fact.value, "Jan Value")
        self.assertEqual(feb_fact.value, "Feb Value")
Пример #2
0
    def test_set_context_arg(self):
        # Tests the case where .set() is called correctly, using
        # the way of calling .set() where we pass in a Context
        # object. Verify the data is stored and can be retrieved
        # using .get().
        doc = Entrypoint("CutSheet", self.taxonomy)
        ctx = Context(duration="forever",
                      entity="JUPITER",
                      ProductIdentifierAxis="placeholder",
                      TestConditionAxis="solar:StandardTestConditionMember")
        doc.set("solar:TypeOfDevice", "ModuleMember", context=ctx)

        now = datetime.now(),
        ctx = Context(instant=now,
                      entity="JUPITER",
                      ProductIdentifierAxis="placeholder",
                      TestConditionAxis="solar:StandardTestConditionMember")
        doc.set("solar:DeviceCost", 100, context=ctx, unit_name="USD")

        # Get the data bacK:
        typeFact = doc.get(
            "solar:TypeOfDevice",
            Context(duration="forever",
                    entity="JUPITER",
                    ProductIdentifierAxis="placeholder",
                    TestConditionAxis="solar:StandardTestConditionMember"))
        self.assertEqual(typeFact.value, "ModuleMember")
        costFact = doc.get(
            "solar:DeviceCost",
            Context(instant=now,
                    entity="JUPITER",
                    ProductIdentifierAxis="placeholder",
                    TestConditionAxis="solar:StandardTestConditionMember"))
        self.assertEqual(costFact.value, 100)
Пример #3
0
    def test_hypercube_store_context(self):
        doc = Entrypoint("CutSheet", self.taxonomy)
        table = doc.get_table("solar:InverterPowerLevelTable")

        c1 = table.store_context(
            Context(duration="forever",
                    entity="JUPITER",
                    ProductIdentifierAxis="ABCD",
                    InverterPowerLevelPercentAxis=
                    'solar:InverterPowerLevel50PercentMember'))
        self.assertEqual(c1.get_id(), "solar:InverterPowerLevelTable_0")
        c2 = table.store_context(
            Context(duration="forever",
                    entity="JUPITER",
                    ProductIdentifierAxis="ABCD",
                    InverterPowerLevelPercentAxis=
                    'solar:InverterPowerLevel50PercentMember'))  # Same
        self.assertIs(c1, c2)
        c3 = table.store_context(
            Context(duration="forever",
                    entity="JUPITER",
                    ProductIdentifierAxis="ABCD",
                    InverterPowerLevelPercentAxis=
                    'solar:InverterPowerLevel75PercentMember'))  # Different
        self.assertIsNot(c1, c3)
Пример #4
0
    def test_set_separate_dimension_args(self):
        # Tests the case where .set() is called correctly.  Use the
        # way of calling .set() where we pass in every dimension
        # separately. Verify the data is stored and can be retrieved
        # using .get().
        doc = Entrypoint("CutSheet", self.taxonomy)

        # Write a TypeOfDevice and a DeviceCost:

        doc.set("solar:TypeOfDevice",
                "ModuleMember",
                duration="forever",
                ProductIdentifierAxis="placeholder",
                TestConditionAxis="solar:StandardTestConditionMember")
        now = datetime.now()
        doc.set("solar:DeviceCost",
                100,
                instant=now,
                ProductIdentifierAxis="placeholder",
                TestConditionAxis="solar:StandardTestConditionMember",
                unit_name="USD")

        typeFact = doc.get(
            "solar:TypeOfDevice",
            Context(duration="forever",
                    ProductIdentifierAxis="placeholder",
                    TestConditionAxis="solar:StandardTestConditionMember"))
        self.assertEqual(typeFact.value, "ModuleMember")
        costFact = doc.get(
            "solar:DeviceCost",
            Context(instant=now,
                    ProductIdentifierAxis="placeholder",
                    TestConditionAxis="solar:StandardTestConditionMember"))
        self.assertEqual(costFact.value, 100)
        self.assertEqual(costFact.unit, "USD")
Пример #5
0
    def test_hypercube_rejects_out_of_domain_axis_values(self):
        # Try passing in something as a value for TestConditionAxis that is not
        # one of the enumerated Members; it should be rejected:

        doc = Entrypoint("CutSheet", self.taxonomy)
        table = doc.get_table("solar:CutSheetDetailsTable")

        self.assertTrue(
            table.axis_value_within_domain(
                "solar:TestConditionAxis",
                "solar:StandardTestConditionMember"))

        self.assertFalse(
            table.axis_value_within_domain(
                "solar:TestConditionAxis",
                "solar:InverterPowerLevel100PercentMember"))

        concept = 'solar:InverterOutputRatedPowerAC'
        context = Context(
            duration="forever",
            ProductIdentifierAxis="placeholder",
            InverterPowerLevelPercentAxis='solar:StandardTestConditionMember')
        # not a valid value for InverterPowerLevelPercentAxis
        with self.assertRaises(Exception):
            doc.sufficient_context(concept, context)
Пример #6
0
    def test_set_default_multiple_times(self):
        # set default for some fields, then set default again for different
        # fields, assert the non-replaced fields keep old values.
        doc = OBInstance("CutSheet", self.taxonomy)
        now = datetime.now()
        doc.set_default_context({
            "entity":
            "JUPITER",
            "solar:TestConditionAxis":
            "solar:StandardTestConditionMember",
        })

        doc.set_default_context({
            PeriodType.instant: now,
            PeriodType.duration: "forever"
        })

        # The second set_default_context should not erase defaults for entity or
        # TestConditionAxis
        doc.set("solar:DeviceCost",
                "100",
                unit_name="USD",
                ProductIdentifierAxis="placeholder")
        fact = doc.get(
            "solar:DeviceCost",
            Context(ProductIdentifierAxis="placeholder",
                    TestConditionAxis="solar:StandardTestConditionMember",
                    entity="JUPITER",
                    instant=now))
        self.assertEqual(fact.value, "100")
        self.assertEqual(fact.unit, "USD")
        self.assertEqual(fact.context.entity, "JUPITER")
        self.assertEqual(fact.context.instant, now)
Пример #7
0
    def test_set_context_arg(self):
        # Tests the case where .set() is called correctly, using
        # the way of calling .set() where we pass in a Context
        # object. Verify the data is stored and can be retrieved
        # using .get().
        doc = Entrypoint("CutSheet", self.taxonomy)
        ctx = Context(duration="forever",
                      entity="JUPITER",
                      ProductIdentifierAxis="placeholder",
                      TestConditionAxis="placeholder")
        doc.set("solar:TypeOfDevice", "Module", context=ctx)

        ctx = Context(instant=datetime.now(),
                      entity="JUPITER",
                      ProductIdentifierAxis="placeholder",
                      TestConditionAxis="placeholder")
        doc.set("solar:DeviceCost", 100, context=ctx, unit="dollars")
Пример #8
0
    def test_sufficient_context_instant_vs_duration(self):
        doc = Entrypoint("CutSheet", self.taxonomy)

        # in order to set a concept value, sufficient context must be
        # provided. what is sufficient context varies by concept.
        # in general the context must provide the correct time information
        # (either duration or instant)

        # We shouldn't even be able to instantiate a context with no time info:
        with self.assertRaises(Exception):
            noTimeContext = Context(
                ProductIdentifierAxis="placeholder",
                TestConditionAxis="solar:StandardTestConditionMember")

        # solar:DeviceCost has period_type instant
        # so it requires a context with an instant. A context without an instant
        # should be insufficient:
        instantContext = Context(
            ProductIdentifierAxis="placeholder",
            TestConditionAxis="solar:StandardTestConditionMember",
            instant=datetime.now())
        durationContext = Context(
            ProductIdentifierAxis="placeholder",
            TestConditionAxis="solar:StandardTestConditionMember",
            duration="forever")

        self.assertTrue(
            doc.sufficient_context("solar:DeviceCost", instantContext))
        # A context with a duration instead of an instant should also be
        # rejected:
        with self.assertRaises(Exception):
            doc.sufficient_context("solar:DeviceCost", durationContext)

        # solar:ModuleNameplateCapacity has period_type duration.
        # A context with an instant instead of a duration should also be
        # rejected:
        with self.assertRaises(Exception):
            doc.sufficient_context("solar:ModuleNameplateCapacity",
                                   instantContext)
        self.assertTrue(
            doc.sufficient_context("solar:ModuleNameplateCapacity",
                                   durationContext))
Пример #9
0
    def test_hypercube_rejects_context_with_unwanted_axes(self):
        # Test that giving a context an *extra* axis that is invalid for the table
        # causes it to be rejected as well.
        doc = Entrypoint("CutSheet", self.taxonomy)

        twoAxisContext = Context(
            ProductIdentifierAxis="placeholder",
            TestConditionAxis="solar:StandardTestConditionMember",
            instant=datetime.now())
        self.assertTrue(
            doc.sufficient_context("solar:DeviceCost", twoAxisContext))

        threeAxisContext = Context(
            ProductIdentifierAxis="placeholder",
            InverterPowerLevelPercentAxis=
            'solar:InverterPowerLevel50PercentMember',
            TestConditionAxis="solar:StandardTestConditionMember",
            instant=datetime.now())
        # InverterPowerLevelPercentAxis is a valid axis and this is a valid value for it,
        # but the table that holds DeviceCost doesn't want this axis:
        with self.assertRaises(Exception):
            doc.sufficient_context("solar:DeviceCost", threeAxisContext)
Пример #10
0
    def test_tableless_facts(self):
        # Some entry points, like MonthlyOperatingReport, seem to have concepts
        # in them that are not part of any table:
        doc = Entrypoint("MonthlyOperatingReport", self.taxonomy)

        doc.set("solar:MonthlyOperatingReportEffectiveDate",
                date(year=2018, month=6, day=1),
                entity="JUPITER",
                duration="forever")

        fact = doc.get("solar:MonthlyOperatingReportEffectiveDate",
                       Context(entity="JUPITER", duration="forever"))

        self.assertEqual(fact.value, date(year=2018, month=6, day=1))
Пример #11
0
    def test_sufficient_context_axes(self):
        doc = Entrypoint("CutSheet", self.taxonomy)

        # The context must also provide all of the axes needed to place the
        # fact within the right table.

        # DeviceCost is on the CutSheetDetailsTable so it needs a value
        # for ProductIdentifierAxis and TestConditionAxis.
        with self.assertRaises(Exception):
            doc.sufficient_context("solar:DeviceCost", {})

        context = Context(
            instant=datetime.now(),
            ProductIdentifierAxis="placeholder",
            TestConditionAxis="solar:StandardTestConditionMember")
        self.assertTrue(doc.sufficient_context("solar:DeviceCost", context))

        badContext = Context(
            instant=datetime.now(),
            TestConditionAxis="solar:StandardTestConditionMember")
        with self.assertRaises(Exception):
            doc.sufficient_context("solar:DeviceCost", badContext)

        badContext = Context(instant=datetime.now(),
                             ProductIdentifierAxis="placeholder")
        with self.assertRaises(Exception):
            doc.sufficient_context("solar:DeviceCost", badContext)

        # How do we know what are valid values for ProductIdentifierAxis and
        # TestConditionAxis?  (I think they are meant to be UUIDs.)

        # Note: TestConditionAxis is part of the following relationships:
        # solar:TestConditionAxis -> dimension-domain -> solar:TestConditionDomain
        # solar:TestConditionAxis -> dimension-default -> solar:TestConditionDomain
        # i wonder what that "dimension-default" means

        #'solar:InverterOutputRatedPowerAC' is on the 'solar:InverterPowerLevelTable' which requires axes: [u'solar:ProductIdentifierAxis', u'solar:InverterPowerLevelPercentAxis']. it's a duration.
        concept = 'solar:InverterOutputRatedPowerAC'
        context = Context(duration="forever",
                          ProductIdentifierAxis="placeholder",
                          InverterPowerLevelPercentAxis=
                          'solar:InverterPowerLevel100PercentMember')

        self.assertTrue(doc.sufficient_context(concept, context))

        badContext = Context(instant=datetime.now(),
                             InverterPowerLevelPercentAxis=
                             'solar:InverterPowerLevel100PercentMember')
        with self.assertRaises(Exception):
            doc.sufficient_context(concept, badContext)

        badContext = Context(instant=datetime.now(),
                             ProductIdentifierAxis="placeholder")
        with self.assertRaises(Exception):
            doc.sufficient_context(concept, badContext)
Пример #12
0
    def test_ids_in_xml_and_json(self):
        # facts should have IDs in both exported JSON and exported XML, and they
        # should be the same ID either way.
        doc = OBInstance("CutSheet", self.taxonomy)
        now = datetime.now()
        doc.set_default_context({
            "entity": "JUPITER",
            "solar:TestConditionAxis": "solar:StandardTestConditionMember",
            PeriodType.instant: now,
            PeriodType.duration: "forever"
        })

        doc.set("solar:ModuleNameplateCapacity",
                "6.25",
                unit_name="W",
                ProductIdentifierAxis=1)

        fact = doc.get(
            "solar:ModuleNameplateCapacity",
            Context(ProductIdentifierAxis=1,
                    TestConditionAxis="solar:StandardTestConditionMember",
                    entity="JUPITER",
                    duration="forever"))
        # Read the fact ID that was automatically assigned when we set the fact:
        fact_id = fact.id

        # Look for fact ID in JSON:
        jsonstring = doc.to_JSON_string()
        facts = json.loads(jsonstring)["facts"]
        self.assertEqual(len(list(facts.keys())), 1)
        self.assertEqual(list(facts.keys())[0], fact_id)

        # Look for fact ID in XML:
        xml = doc.to_XML_string()
        root = etree.fromstring(xml)
        fact = root.find(
            "{http://xbrl.us/Solar/v1.2/2018-03-31/solar}ModuleNameplateCapacity"
        )
        self.assertEqual(fact.attrib["id"], fact_id)
Пример #13
0
    def test_set_default_context_values(self):
        # Test setting default values, for example something like:
        doc = Entrypoint("CutSheet", self.taxonomy)
        now = datetime.now()
        doc.set_default_context({
            "entity": "JUPITER",
            "solar:TestConditionAxis": "solar:StandardTestConditionMember",
            PeriodType.instant: now,
            PeriodType.duration: "forever"
        })
        # Could also support setting default unit, even though that's not part of context:

        # If we set a fact that wants an instant context, it should use 'now':
        doc.set("solar:DeviceCost",
                "100",
                unit_name="USD",
                ProductIdentifierAxis="placeholder")
        # This would normally raise an exception because it's missing instant, entity, and
        # TestConditionAxis. But we set defaults for those, so they should be filled in:
        fact = doc.get(
            "solar:DeviceCost",
            Context(ProductIdentifierAxis="placeholder",
                    TestConditionAxis="solar:StandardTestConditionMember",
                    entity="JUPITER",
                    instant=now))
        self.assertEqual(fact.value, "100")
        self.assertEqual(fact.unit, "USD")
        self.assertEqual(fact.context.entity, "JUPITER")
        self.assertEqual(fact.context.instant, now)

        # TODO test method of calling set() where we pass in Context object.

        # If we set a fact that wants a duration context, it should use jan 1 - jan 31:
        doc.set("solar:ModuleNameplateCapacity",
                "0.3",
                unit_name="W",
                ProductIdentifierAxis="placeholder")
        # Would normally raise an exception because missing duration, entity, and
        # TestConditionAxis. But we set defaults for those, so they should be filled in:
        fact = doc.get(
            "solar:ModuleNameplateCapacity",
            Context(ProductIdentifierAxis="placeholder",
                    TestConditionAxis="solar:StandardTestConditionMember",
                    entity="JUPITER",
                    duration="forever"))
        self.assertEqual(fact.value, "0.3")
        self.assertEqual(fact.unit, "W")
        self.assertEqual(fact.context.entity, "JUPITER")
        self.assertEqual(fact.context.duration, "forever")

        # Try setting ALL the fields in set_default_context and then pass in NO context fields,
        # that should work too:
        doc.set_default_context({
            "entity": "JUPITER",
            "solar:TestConditionAxis": "solar:StandardTestConditionMember",
            PeriodType.instant: now,
            "solar:ProductIdentifierAxis": "placeholder"
        })
        doc.set("solar:DeviceCost", "99", unit_name="USD")
        fact = doc.get(
            "solar:DeviceCost",
            Context(ProductIdentifierAxis="placeholder",
                    TestConditionAxis="solar:StandardTestConditionMember",
                    entity="JUPITER",
                    instant=now))
        self.assertEqual(fact.value, "99")