Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue 78 - decimals/precision #111

Merged
merged 60 commits into from
Feb 7, 2019
Merged
Show file tree
Hide file tree
Changes from 58 commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
c742dff
Added code to taxonomy_semantic.py to extract arcrole relationships f…
jonoxia Nov 8, 2018
369c88e
Corrected my print statements to work in Python 3
jonoxia Nov 8, 2018
49b3a0b
Issue #22 - Added logic to Entrypoint class to look up which table a …
jonoxia Nov 8, 2018
218959f
Issue #22 - Added a .sufficientContext() method to EntryPoint which i…
jonoxia Nov 8, 2018
12ebeb2
Issue #22 - EntryPoint.sufficientContext() now checks that the requir…
jonoxia Nov 8, 2018
e834f1b
Issue #22 - EntryPoint .set() and .get() methods now store and retrie…
jonoxia Nov 8, 2018
c946fc6
Merge branch 'master' of https://github.com/SunSpecOrangeButton/core
jonoxia Nov 8, 2018
abcaf3f
Merge branch 'master' of https://github.com/SunSpecOrangeButton/pyoblib
jonoxia Nov 8, 2018
36a83a5
Corrected comment
jonoxia Nov 8, 2018
21369ca
Issue #22 - moved data_model and test_data_model to the new locations…
jonoxia Nov 8, 2018
c3926c6
Updated my unit test to be Python3 compatible by changing assertItems…
jonoxia Nov 8, 2018
d9b2a07
Wrote test in a way that works in either Python2 or Python3
jonoxia Nov 8, 2018
fef47be
Issue #25 - Entrypoint now takes taxonomy_semantic instance as an arg…
jonoxia Nov 8, 2018
bbb031c
Issue #25 - Created singleton accessor method getTaxonomy() in taxono…
jonoxia Nov 8, 2018
3f9e980
Resolved merge conflicts
jonoxia Nov 9, 2018
446ec5a
Issue #26 - Entrypoint.set() takes keyword args, either a 'context' k…
jonoxia Nov 9, 2018
c2db950
Data model improvements: now stores facts in a structure of nested di…
jonoxia Dec 4, 2018
dce89ab
Issue #52 and #53 - added methods to export an EntryPoint instance to…
jonoxia Dec 4, 2018
46f187a
Issue #22 - Added type checking for domains of axes. A table now know…
jonoxia Dec 5, 2018
90b00d5
Issue #22 #52 and #53 - Now checking that the units provided in Entry…
jonoxia Dec 5, 2018
5119906
Resolved merge conflicts
jonoxia Dec 5, 2018
76ec3ac
Renamed all methods in data_model to underscore_name_style. Added doc…
jonoxia Dec 6, 2018
8dd41d1
Issue #22 - Check type of given value against the datatype the concep…
jonoxia Dec 6, 2018
fb03e5b
Issue #27 - EntryPoint now supports .set_default_context() and values…
jonoxia Dec 6, 2018
052f35a
Issue #22 - allow concepts with no tables, since apparently some entr…
jonoxia Dec 6, 2018
88f6c6a
Resolved merge conflicts
jonoxia Dec 7, 2018
6970dd5
Added required modules to requirements.txt, commented out failing tes…
jonoxia Dec 7, 2018
b39dd4f
Removed unwanted modules from requirements.txt
jonoxia Dec 7, 2018
7895b59
Enum back to requirements
jonoxia Dec 7, 2018
d4d3b36
Use PeriodType.instant and PeriodType.duration instead of string lite…
jonoxia Dec 8, 2018
e652534
Make the SOLAR_TAXONOMY_DIR constant relative to the file location in…
jonoxia Dec 10, 2018
5b4530b
Issue
jonoxia Dec 10, 2018
c73cf05
Uncomment taxonomy tests and try checking for instance of unicode ins…
jonoxia Dec 10, 2018
bfe0f34
Corrected exception handling syntax for python3 compatibility
jonoxia Dec 10, 2018
03e446c
Used six.string_types to make the string/unicode type checking work i…
jonoxia Dec 10, 2018
8d83e96
Added some explicit list conversions for python2-python3 compatibility
jonoxia Dec 10, 2018
d5ffa6a
Make test not depend on odering of unsorted list
jonoxia Dec 10, 2018
564885c
Resolved merge conflict in requirements.txt
jonoxia Dec 11, 2018
acc7024
Have taxonomy_semantic load Data entry points as well as Document ent…
jonoxia Dec 17, 2018
25d4fa0
When setting defaults on Entrypoint context values, update rather tha…
jonoxia Dec 17, 2018
94bae49
Accept a string like '1.0' as a valid integer value
jonoxia Dec 18, 2018
fd7fba7
Use named exception subclasses in data_model for more structured excd…
jonoxia Dec 18, 2018
e802554
Made all OB Exceptions inherit from a single OBException parent class
jonoxia Dec 18, 2018
784feb6
Spell Exception correctly
jonoxia Dec 19, 2018
9918087
Added method get_valid_values_for_axis to Hypercube class
jonoxia Dec 28, 2018
fea4b12
Added TaxonomyDocstrings which reads the documentation text for each …
jonoxia Dec 31, 2018
bd7091c
Added support for 'All' Entrypoint, that simply allows all concepts. …
jonoxia Jan 4, 2019
01b244e
Resolved merge conflict
jonoxia Jan 11, 2019
43431f3
Fixed broken unit tests
jonoxia Jan 11, 2019
69da8d2
Replaced unicode() with str() in order to work across py2/py3
jonoxia Jan 11, 2019
968fa4e
Resolved merge conflicts
jonoxia Jan 22, 2019
b26b12d
Issue #77 - changed format of JSON export so that facts are a diction…
jonoxia Jan 22, 2019
f861468
Removed PyInstaller dependency
jonoxia Jan 23, 2019
7913979
Placeholder test for precision/decimals feature
jonoxia Jan 24, 2019
f6d2371
Removed pyinstaller from requirements
jonoxia Jan 24, 2019
00cc2d6
Issue #78 - set() now takes precision argument XOR decimals argument,…
jonoxia Jan 25, 2019
12c3091
Merge branch 'master' of https://github.com/SunSpecOrangeButton/pyoblib
jonoxia Jan 26, 2019
52c6abf
Resolved merge conflict
jonoxia Jan 26, 2019
cd69e9f
Issue #78 - made tests pass on python3
jonoxia Feb 5, 2019
32b1d05
Issue #78 removed default decimals in fact constructor, removed 'unit…
jonoxia Feb 7, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 34 additions & 8 deletions oblib/data_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -444,14 +444,15 @@ class Fact(object):
as either XML or JSON. A Fact provides a value for a certain concept within
a certain context, and can optionally provide units and a precision.
"""
def __init__(self, concept, context, unit, value, decimals=2):
def __init__(self, concept, context, unit, value, decimals=None, precision=None):
"""
Concept is the field name - it must match the schema definition.
Context is a reference to this fact's parent Context object.
Units is a string naming the unit, for example "kWh"
Value is a string, integer, or float
Decimals is used only for float types, it is the number of
digits
Value is a string, integer, or float.
For numeric types only, precision OR decimals (not both) can be specified.
Decimals is the number of digits past the decimal point; precision is
the total number of significant digits.
"""
# in case of xml the context ID will be rendered in the fact tag.
# in case of json the contexts' attributes will be copied to the
Expand All @@ -460,7 +461,15 @@ def __init__(self, concept, context, unit, value, decimals=2):
self.value = value
self.context = context
self.unit = unit

if decimals is not None and precision is not None:
raise OBException("Fact given both precision and decimals - use only one.")
self.decimals = decimals
self.precision = precision
if decimals is None and precision is None:
cwhanse marked this conversation as resolved.
Show resolved Hide resolved
# Default to 2 decimals:
self.decimals = 2

# Fill in the id property with a UUID:
self.id = identifier.identifier() # Only used when exporting JSON

Expand All @@ -473,10 +482,13 @@ def _toXML(self):
# also the self.unit may not be correct unitRef? not sure
if self.unit is not None:
attribs["unitRef"] = self.unit
if self.unit == "pure" or self.unit == "degrees":
if self.unit == "pure":
attribs["decimals"] = "0"
else:
attribs["decimals"] = str(self.decimals)
if self.decimals is not None:
attribs["decimals"] = str(self.decimals)
elif self.precision is not None:
attribs["precision"] = str(self.precision)
elem = Element(self.concept, attrib=attribs)
if self.unit == "pure":
elem.text = "%d" % self.value
Expand All @@ -493,6 +505,13 @@ def _toJSON(self):
aspects["concept"] = self.concept
if self.unit is not None:
aspects["unit"] = self.unit
if self.unit == "pure":
aspects["decimals"] = "0"
cwhanse marked this conversation as resolved.
Show resolved Hide resolved
else:
if self.decimals is not None:
aspects["decimals"] = str(self.decimals)
elif self.precision is not None:
aspects["precision"] = str(self.precision)

if isinstance( self.value, datetime.datetime):
value_str = self.value.strftime("%Y-%m-%dT%H:%M:%S")
Expand Down Expand Up @@ -986,6 +1005,12 @@ def set(self, concept_name, value, **kwargs):

if "precision" in kwargs:
precision = kwargs.pop("precision")
else:
precision = None
if "decimals" in kwargs:
cwhanse marked this conversation as resolved.
Show resolved Hide resolved
decimals = kwargs.pop("decimals")
else:
decimals = None

if not self.is_concept_writable(concept_name):
raise OBConceptException(
Expand Down Expand Up @@ -1027,8 +1052,9 @@ def set(self, concept_name, value, **kwargs):
table = self.get_table_for_concept(concept_name)
context = table.store_context(context) # dedupes, assigns ID

f = Fact(concept_name, context, unit_name, value)
# TODO pass in decimals? Fact expects decimals and "precision" is slightly different
f = Fact(concept_name, context, unit_name, value,
precision=precision,
decimals=decimals)

# self.facts is nested dict keyed first on table then on context ID
# and finally on concept:
Expand Down
42 changes: 41 additions & 1 deletion oblib/tests/test_data_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

import unittest
from data_model import OBInstance, Context, Hypercube, UNTABLE
from data_model import OBException, OBContextException
from datetime import datetime, date
from taxonomy import getTaxonomy
from lxml import etree
Expand Down Expand Up @@ -648,7 +649,7 @@ def test_hypercube_rejects_context_with_unwanted_axes(self):
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):
with self.assertRaises(OBContextException):
doc.validate_context("solar:DeviceCost", threeAxisContext)


Expand Down Expand Up @@ -774,4 +775,43 @@ def test_validate_values_for_enumerated_solar_data_types(self):
pass


def test_decimals_and_precision(self):
# if we set a fact and pass in a Decimals argument,
# then when we write out to JSON or XML we should see decimals there.
# Same with Precision.
# Trying to set both Decimals and Precision should give an error.
# If we don't set either, it should default to decimals=2.

doc = OBInstance("CutSheet", self.taxonomy)
now = datetime.now()
doc.set_default_context({"entity": "JUPITER",
"solar:TestConditionAxis": "solar:StandardTestConditionMember",
PeriodType.instant: now,
PeriodType.duration: "forever"
})

# If we set a fact that wants a duration context, it should use jan 1 - jan 31:
doc.set("solar:ModuleNameplateCapacity", "6.25", unit_name="W",
ProductIdentifierAxis = 1, precision = 3)

jsonstring = doc.to_JSON_string()
facts = json.loads(jsonstring)["facts"]

# TODO is supposed to be in aspects or not?
self.assertEqual(len(facts), 1)
self.assertEqual(facts.values()[0]["aspects"]["precision"], "3")

doc.set("solar:ModuleNameplateCapacity", "6.25", unit_name="W",
ProductIdentifierAxis = 1, decimals = 3)
jsonstring = doc.to_JSON_string()
facts = json.loads(jsonstring)["facts"]
self.assertEqual(len(facts), 1)
self.assertEqual(facts.values()[0]["aspects"]["decimals"], "3")

# Trying to set both decimals and precision should raise an error
with self.assertRaises(OBException):
doc.set("solar:ModuleNameplateCapacity", "6.25", unit_name="W",
ProductIdentifierAxis = 1, decimals = 3, precision=3)



3 changes: 0 additions & 3 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,3 @@ Sphinx==1.8.2
sphinx-rtd-theme==0.4.2
sphinxcontrib-websupport==1.1.0

# pyinstaller
pyinstaller==3.4