mirror of
https://github.com/weewx/weewx.git
synced 2026-06-10 01:55:07 -04:00
Greatly simplified tags, getting rid of two classes. Changed syntax used to explicitly bind to a database.
This commit is contained in:
@@ -314,9 +314,8 @@ class CheetahGenerator(weewx.reportengine.ReportGenerator):
|
||||
self.outputted_dict]
|
||||
|
||||
# Then add the V3.X style search list extensions
|
||||
db_factory = weewx.tags.DBFactory(self.db_binder, default_binding)
|
||||
for obj in self.search_list_objs:
|
||||
searchList += obj.get_extension_list(timespan, db_factory)
|
||||
searchList += obj.get_extension_list(timespan, self.db_binder, default_binding)
|
||||
|
||||
return searchList
|
||||
|
||||
@@ -385,14 +384,17 @@ class SearchList(object):
|
||||
"""
|
||||
self.generator = generator
|
||||
|
||||
def get_extension_list(self, timespan, db_factory):
|
||||
def get_extension_list(self, timespan, db_binder, default_binding):
|
||||
"""For weewx V3.x extensions. Should return a list
|
||||
of objects whose attributes or keys define the extension.
|
||||
|
||||
timespan: An instance of weeutil.weeutil.TimeSpan. This will hold the
|
||||
start and stop times of the domain of valid times.
|
||||
|
||||
db_factory: An instance of class weewx.tags.DBFactory
|
||||
db_binder: An instance of class weewx.manager.DBBinder
|
||||
|
||||
default_binding: In the absence of a binding, the binding name
|
||||
to be used.
|
||||
"""
|
||||
return [self]
|
||||
|
||||
@@ -463,32 +465,24 @@ class Stats(SearchList):
|
||||
as $day.outTemp.max"""
|
||||
|
||||
|
||||
def get_extension_list(self, timespan, db_factory):
|
||||
def get_extension_list(self, timespan, db_binder, default_binding):
|
||||
try:
|
||||
trend_dict = self.generator.skin_dict['Units']['Trend']
|
||||
except KeyError:
|
||||
trend_dict = {'time_delta' : 10800,
|
||||
'time_grace' : 300}
|
||||
|
||||
# Build a "current record" from the default database binding. This
|
||||
# will allow the database to be hit only once for the most common
|
||||
# lookups
|
||||
dbmanager = db_factory.get_database()
|
||||
record = dbmanager.getRecord(timespan.stop)
|
||||
current = weewx.tags.CurrentRecord(record, context='current',
|
||||
formatter=self.generator.formatter,
|
||||
converter=self.generator.converter)
|
||||
stats = weewx.tags.TimeBinder(db_binder,
|
||||
default_binding,
|
||||
timespan.stop,
|
||||
formatter=self.generator.formatter,
|
||||
converter=self.generator.converter,
|
||||
week_start=self.generator.stn_info.week_start,
|
||||
rain_year_start=self.generator.stn_info.rain_year_start,
|
||||
trend=trend_dict,
|
||||
skin_dict=self.generator.skin_dict)
|
||||
|
||||
stats = weewx.tags.FactoryBinder(db_factory,
|
||||
timespan.stop,
|
||||
formatter=self.generator.formatter,
|
||||
converter=self.generator.converter,
|
||||
week_start=self.generator.stn_info.week_start,
|
||||
rain_year_start=self.generator.stn_info.rain_year_start,
|
||||
trend=trend_dict,
|
||||
skin_dict=self.generator.skin_dict)
|
||||
|
||||
return [{'current':current}, stats]
|
||||
return [stats]
|
||||
|
||||
class UnitInfo(SearchList):
|
||||
"""Class that implements the $unit tag."""
|
||||
|
||||
@@ -12,72 +12,26 @@ from weeutil.weeutil import to_int
|
||||
import weewx.units
|
||||
from weewx.units import ValueTuple
|
||||
|
||||
#===============================================================================
|
||||
# Class DBFactory
|
||||
#===============================================================================
|
||||
|
||||
class DBFactory(object):
|
||||
"""Binds a database cache, with a default database."""
|
||||
|
||||
def __init__(self, db_binder, default_binding='wx_binding'):
|
||||
self.db_binder = db_binder
|
||||
self.default_binding = default_binding
|
||||
|
||||
def get_database(self, binding=None):
|
||||
if binding is None:
|
||||
binding = self.default_binding
|
||||
return self.db_binder.get_database(binding)
|
||||
|
||||
#===============================================================================
|
||||
# Class FactoryBinder
|
||||
# Class TimeBinder
|
||||
#===============================================================================
|
||||
|
||||
class FactoryBinder(object):
|
||||
"""Binds a DBFactory and an end time together.
|
||||
|
||||
This class sits on the top of chain of helper classes that enable
|
||||
syntax such as $db($data_binding='wx_binding').month.rain.sum in the Cheetah templates."""
|
||||
|
||||
def __init__(self, dbfactory, report_time,
|
||||
formatter=weewx.units.Formatter(), converter=weewx.units.Converter(), **option_dict):
|
||||
|
||||
self.dbfactory = dbfactory
|
||||
self.report_time = report_time
|
||||
self.formatter = formatter
|
||||
self.converter = converter
|
||||
self.option_dict = option_dict
|
||||
|
||||
def db(self, data_binding=None):
|
||||
opendb = self.dbfactory.get_database(data_binding)
|
||||
return DatabaseBinder(opendb, self.report_time, self.formatter, self.converter, **self.option_dict)
|
||||
|
||||
def __getattr__(self, attr):
|
||||
# The following is so the Python version of Cheetah's NameMapper does not think I'm a dictionary.
|
||||
if attr == 'has_key':
|
||||
raise AttributeError(attr)
|
||||
# For syntax such as $month.outTemp.max, the funcion db() above will not
|
||||
# get called and instead, we will be queried for an attribute such as 'month'.
|
||||
# So, make the call to db() with default values, then ask it for the
|
||||
# attribute.
|
||||
return getattr(self.db(), attr)
|
||||
|
||||
#===============================================================================
|
||||
# Class DatabaseBinder
|
||||
#===============================================================================
|
||||
|
||||
class DatabaseBinder(object):
|
||||
"""Binds to a specific database. Can be queried for time attributes, such as month.
|
||||
class TimeBinder(object):
|
||||
"""Binds to a specific time. Can be queried for time attributes, such as month.
|
||||
|
||||
When a time period is given as an attribute to it, such as obj.month,
|
||||
the next item in the chain is returned, in this case an instance of
|
||||
TimeBinder, which binds the database with the time period.
|
||||
TimespanBinder, which binds things to a timespan.
|
||||
"""
|
||||
|
||||
def __init__(self, opendb, report_time,
|
||||
def __init__(self, db_binder, data_binding, report_time,
|
||||
formatter=weewx.units.Formatter(), converter=weewx.units.Converter(), **option_dict):
|
||||
"""Initialize an instance of DatabaseBinder.
|
||||
|
||||
opendb: A Database from which the aggregates are to be extracted.
|
||||
db_binder: An instance of weewx.manager.DBBinder
|
||||
|
||||
data_binding: In the absence of an explicit binding, use this data binding.
|
||||
|
||||
report_time: The time for which the report should be run.
|
||||
|
||||
@@ -92,61 +46,74 @@ class DatabaseBinder(object):
|
||||
option_dict: Other options which can be used to customize calculations.
|
||||
[Optional.]
|
||||
"""
|
||||
self.opendb = opendb
|
||||
self.report_time = report_time
|
||||
self.formatter = formatter
|
||||
self.converter = converter
|
||||
self.option_dict = option_dict
|
||||
self.db_binder = db_binder
|
||||
self.data_binding = data_binding
|
||||
self.report_time = report_time
|
||||
self.formatter = formatter
|
||||
self.converter = converter
|
||||
self.option_dict = option_dict
|
||||
|
||||
# What follows is the list of time period attributes:
|
||||
|
||||
@property
|
||||
def current(self, timestamp=None):
|
||||
def current(self, timestamp=None, data_binding=None):
|
||||
"""Return a CurrentObj"""
|
||||
if timestamp is None:
|
||||
timestamp = self.report_time
|
||||
return CurrentObj(self.opendb, timestamp,
|
||||
if data_binding is None:
|
||||
data_binding = self.data_binding
|
||||
return CurrentObj(self.db_binder, data_binding, timestamp,
|
||||
self.formatter, self.converter, **self.option_dict)
|
||||
|
||||
def trend(self, time_delta=None, time_grace=None):
|
||||
def trend(self, time_delta=None, time_grace=None, data_binding=None):
|
||||
"""Returns a TrendObj that is bound to the trend parameters."""
|
||||
if time_delta is None:
|
||||
time_delta = to_int(self.option_dict['trend'].get('time_delta', 10800))
|
||||
if time_grace is None:
|
||||
time_grace = to_int(self.option_dict['trend'].get('time_grace', 300))
|
||||
|
||||
return TrendObj(time_delta, time_grace, self.opendb, self.report_time,
|
||||
if data_binding is None:
|
||||
data_binding = self.data_binding
|
||||
return TrendObj(time_delta, time_grace, self.db_binder, data_binding, self.report_time,
|
||||
self.formatter, self.converter, **self.option_dict)
|
||||
|
||||
@property
|
||||
def day(self):
|
||||
return TimeBinder(weeutil.weeutil.archiveDaySpan(self.report_time), self.opendb,
|
||||
'day', self.formatter, self.converter, **self.option_dict)
|
||||
@property
|
||||
def week(self):
|
||||
def day(self, data_binding=None):
|
||||
if data_binding is None:
|
||||
data_binding = self.data_binding
|
||||
return TimespanBinder(weeutil.weeutil.archiveDaySpan(self.report_time),
|
||||
self.db_binder, data_binding,
|
||||
'day', self.formatter, self.converter, **self.option_dict)
|
||||
def week(self, data_binding=None):
|
||||
if data_binding is None:
|
||||
data_binding = self.data_binding
|
||||
week_start = to_int(self.option_dict.get('week_start', 6))
|
||||
return TimeBinder(weeutil.weeutil.archiveWeekSpan(self.report_time, week_start), self.opendb,
|
||||
'week', self.formatter, self.converter, **self.option_dict)
|
||||
@property
|
||||
def month(self):
|
||||
return TimeBinder(weeutil.weeutil.archiveMonthSpan(self.report_time), self.opendb,
|
||||
'month', self.formatter, self.converter, **self.option_dict)
|
||||
@property
|
||||
def year(self):
|
||||
return TimeBinder(weeutil.weeutil.archiveYearSpan(self.report_time), self.opendb,
|
||||
'year', self.formatter, self.converter, **self.option_dict)
|
||||
@property
|
||||
def rainyear(self):
|
||||
return TimespanBinder(weeutil.weeutil.archiveWeekSpan(self.report_time, week_start),
|
||||
self.db_binder, data_binding,
|
||||
'week', self.formatter, self.converter, **self.option_dict)
|
||||
def month(self, data_binding=None):
|
||||
if data_binding is None:
|
||||
data_binding = self.data_binding
|
||||
return TimespanBinder(weeutil.weeutil.archiveMonthSpan(self.report_time),
|
||||
self.db_binder, data_binding,
|
||||
'month', self.formatter, self.converter, **self.option_dict)
|
||||
def year(self, data_binding=None):
|
||||
if data_binding is None:
|
||||
data_binding = self.data_binding
|
||||
return TimespanBinder(weeutil.weeutil.archiveYearSpan(self.report_time),
|
||||
self.db_binder, data_binding,
|
||||
'year', self.formatter, self.converter, **self.option_dict)
|
||||
def rainyear(self, data_binding=None):
|
||||
if data_binding is None:
|
||||
data_binding = self.data_binding
|
||||
rain_year_start = to_int(self.option_dict.get('rain_year_start', 1))
|
||||
return TimeBinder(weeutil.weeutil.archiveRainYearSpan(self.report_time, rain_year_start), self.opendb,
|
||||
'rainyear', self.formatter, self.converter, **self.option_dict)
|
||||
return TimespanBinder(weeutil.weeutil.archiveRainYearSpan(self.report_time, rain_year_start),
|
||||
self.db_binder, data_binding,
|
||||
'rainyear', self.formatter, self.converter, **self.option_dict)
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# Class TimeBinder
|
||||
# Class TimespanBinder
|
||||
#===============================================================================
|
||||
|
||||
class TimeBinder(object):
|
||||
class TimespanBinder(object):
|
||||
"""Holds a binding between a database and a timespan.
|
||||
|
||||
This class is the next class in the chain of helper classes.
|
||||
@@ -164,14 +131,17 @@ class TimeBinder(object):
|
||||
# Print maximum temperature for each month in the year:
|
||||
print monthStats.outTemp.max
|
||||
"""
|
||||
def __init__(self, timespan, opendb, context='current', formatter=weewx.units.Formatter(),
|
||||
def __init__(self, timespan, db_binder, data_binding, context='current',
|
||||
formatter=weewx.units.Formatter(),
|
||||
converter=weewx.units.Converter(), **option_dict):
|
||||
"""Initialize an instance of TimeBinder.
|
||||
"""Initialize an instance of TimespanBinder.
|
||||
|
||||
timespan: An instance of weeutil.Timespan with the time span
|
||||
over which the statistics are to be calculated.
|
||||
|
||||
opendb: A database from which the stats are to be extracted.
|
||||
db_binder: An instance of weewx.manager.DBBinder
|
||||
|
||||
data_binding: In the absence of an explicit binding, use this data binding.
|
||||
|
||||
context: A tag name for the timespan. This is something like 'current', 'day',
|
||||
'week', etc. This is used to find an appropriate label, if necessary.
|
||||
@@ -189,36 +159,43 @@ class TimeBinder(object):
|
||||
"""
|
||||
|
||||
self.timespan = timespan
|
||||
self.opendb = opendb
|
||||
self.db_binder = db_binder
|
||||
self.data_binding= data_binding
|
||||
self.context = context
|
||||
self.formatter = formatter
|
||||
self.converter = converter
|
||||
self.option_dict = option_dict
|
||||
|
||||
# Iterate over days in the time period:
|
||||
@property
|
||||
def days(self):
|
||||
return TimeBinder._seqGenerator(weeutil.weeutil.genDaySpans, self.timespan, self.opendb,
|
||||
'day', self.formatter, self.converter, **self.option_dict)
|
||||
def days(self, data_binding=None):
|
||||
if data_binding is None:
|
||||
data_binding = self.data_binding
|
||||
return TimespanBinder._seqGenerator(weeutil.weeutil.genDaySpans, self.timespan,
|
||||
self.db_binder, data_binding,
|
||||
'day', self.formatter, self.converter, **self.option_dict)
|
||||
|
||||
# Iterate over months in the time period:
|
||||
@property
|
||||
def months(self):
|
||||
return TimeBinder._seqGenerator(weeutil.weeutil.genMonthSpans, self.timespan, self.opendb,
|
||||
'month', self.formatter, self.converter, **self.option_dict)
|
||||
def months(self, data_binding=None):
|
||||
if data_binding is None:
|
||||
data_binding = self.data_binding
|
||||
return TimespanBinder._seqGenerator(weeutil.weeutil.genMonthSpans, self.timespan,
|
||||
self.db_binder, data_binding,
|
||||
'month', self.formatter, self.converter, **self.option_dict)
|
||||
|
||||
# Iterate over years in the time period:
|
||||
@property
|
||||
def years(self):
|
||||
return TimeBinder._seqGenerator(weeutil.weeutil.genYearSpans, self.timespan, self.opendb,
|
||||
'year', self.formatter, self.converter, **self.option_dict)
|
||||
def years(self, data_binding=None):
|
||||
if data_binding is None:
|
||||
data_binding = self.data_binding
|
||||
return TimespanBinder._seqGenerator(weeutil.weeutil.genYearSpans, self.timespan,
|
||||
self.db_binder, data_binding,
|
||||
'year', self.formatter, self.converter, **self.option_dict)
|
||||
|
||||
# Static method used to implement the iteration:
|
||||
@staticmethod
|
||||
def _seqGenerator(genSpanFunc, timespan, *args, **option_dict):
|
||||
"""Generator function that returns TimeBinder for the appropriate timespans"""
|
||||
"""Generator function that returns TimespanBinder for the appropriate timespans"""
|
||||
for span in genSpanFunc(timespan.start, timespan.stop):
|
||||
yield TimeBinder(span, *args, **option_dict)
|
||||
yield TimespanBinder(span, *args, **option_dict)
|
||||
|
||||
# Return the start time of the time period as a ValueHelper
|
||||
@property
|
||||
@@ -239,21 +216,9 @@ class TimeBinder(object):
|
||||
if obs_type == 'has_key':
|
||||
raise AttributeError
|
||||
|
||||
# If we represent the "current" time, then no aggregation is possible. Just return
|
||||
# a ValueHelper.
|
||||
if self.context == 'current':
|
||||
max_delta = self.option_dict.get('max_delta')
|
||||
record_dict = self.opendb.getRecord(self.timespan.stop, max_delta)
|
||||
if record_dict is not None:
|
||||
vt = weewx.units.as_value_tuple(record_dict, obs_type)
|
||||
else:
|
||||
vt = (None, None, None)
|
||||
vh = weewx.units.ValueHelper(vt, context='current', formatter=self.formatter, converter=self.converter)
|
||||
return vh
|
||||
|
||||
# For other contexts, an aggregation is possible. Return an ObservationBinder: if an attribute is
|
||||
# requested from it, an aggregation value will be returned instead.
|
||||
return ObservationBinder(obs_type, self.timespan, self.opendb, self.context,
|
||||
# Return an ObservationBinder: if an attribute is
|
||||
# requested from it, an aggregation value will be returned.
|
||||
return ObservationBinder(obs_type, self.timespan, self.db_binder, self.data_binding, self.context,
|
||||
self.formatter, self.converter, **self.option_dict)
|
||||
|
||||
#===============================================================================
|
||||
@@ -268,7 +233,7 @@ class ObservationBinder(object):
|
||||
query against the database, assembles the result, and returns it as a ValueHelper.
|
||||
"""
|
||||
|
||||
def __init__(self, obs_type, timespan, opendb, context,
|
||||
def __init__(self, obs_type, timespan, db_binder, data_binding, context,
|
||||
formatter=weewx.units.Formatter(), converter=weewx.units.Converter(), **option_dict):
|
||||
""" Initialize an instance of ObservationBinder
|
||||
|
||||
@@ -278,7 +243,9 @@ class ObservationBinder(object):
|
||||
timespan: An instance of TimeSpan holding the time period over which the query is
|
||||
to be run
|
||||
|
||||
opendb: The database from which the stats are to be extracted.
|
||||
db_binder: An instance of weewx.manager.DBBinder
|
||||
|
||||
data_binding: In the absence of an explicit binding, use this data binding.
|
||||
|
||||
context: A tag name for the timespan. This is something like 'current', 'day',
|
||||
'week', etc. This is used to find an appropriate label, if necessary.
|
||||
@@ -295,13 +262,14 @@ class ObservationBinder(object):
|
||||
[Optional.]
|
||||
"""
|
||||
|
||||
self.obs_type = obs_type
|
||||
self.timespan = timespan
|
||||
self.opendb = opendb
|
||||
self.context = context
|
||||
self.formatter = formatter
|
||||
self.converter = converter
|
||||
self.option_dict = option_dict
|
||||
self.obs_type = obs_type
|
||||
self.timespan = timespan
|
||||
self.db_binder = db_binder
|
||||
self.data_binding = data_binding
|
||||
self.context = context
|
||||
self.formatter = formatter
|
||||
self.converter = converter
|
||||
self.option_dict = option_dict
|
||||
|
||||
def max_ge(self, val):
|
||||
return self._do_query('max_ge', val=val)
|
||||
@@ -332,17 +300,17 @@ class ObservationBinder(object):
|
||||
|
||||
@property
|
||||
def exists(self):
|
||||
|
||||
return self.opendb.exists(self.obs_type)
|
||||
return self.db_binder.get_database(self.data_binding).exists(self.obs_type)
|
||||
|
||||
@property
|
||||
def has_data(self):
|
||||
|
||||
return self.opendb.has_data(self.obs_type, self.timespan)
|
||||
return self.db_binder.get_database(self.data_binding).has_data(self.obs_type, self.timespan)
|
||||
|
||||
def _do_query(self, aggregateType, val=None):
|
||||
"""Run a query against the databases, using the given aggregation type."""
|
||||
result = self.opendb.getAggregate(self.timespan, self.obs_type, aggregateType, val=val, **self.option_dict)
|
||||
db_manager = self.db_binder.get_database(self.data_binding)
|
||||
result = db_manager.getAggregate(self.timespan, self.obs_type, aggregateType,
|
||||
val=val, **self.option_dict)
|
||||
return weewx.units.ValueHelper(result, self.context, self.formatter, self.converter)
|
||||
|
||||
#===============================================================================
|
||||
@@ -356,11 +324,12 @@ class CurrentObj(object):
|
||||
$current.barometer
|
||||
"""
|
||||
|
||||
def __init__(self, opendb, timestamp, formatter, converter, **option_dict):
|
||||
self.opendb = opendb
|
||||
self.timestamp = timestamp
|
||||
self.formatter = formatter
|
||||
self.converter = converter
|
||||
def __init__(self, db_binder, data_binding, timestamp, formatter, converter, **option_dict):
|
||||
self.db_binder = db_binder
|
||||
self.data_binding = data_binding
|
||||
self.timestamp = timestamp
|
||||
self.formatter = formatter
|
||||
self.converter = converter
|
||||
|
||||
def __getattr__(self, obs_type):
|
||||
"""Return the given observation type."""
|
||||
@@ -369,9 +338,13 @@ class CurrentObj(object):
|
||||
if obs_type == 'has_key':
|
||||
raise AttributeError
|
||||
|
||||
# Get the current record:
|
||||
record = self.opendb.getRecord(self.timestamp)
|
||||
# Get the appropriate database manager
|
||||
db_manager = self.db_binder.get_database(self.data_binding)
|
||||
# Get the current record from it
|
||||
record = db_manager.getRecord(self.timestamp)
|
||||
# Form a ValueTuple
|
||||
vt = weewx.units.as_value_tuple(record, obs_type)
|
||||
# Finally, return a ValueHelper
|
||||
return weewx.units.ValueHelper(vt, 'current',
|
||||
self.formatter,
|
||||
self.converter)
|
||||
@@ -387,7 +360,7 @@ class TrendObj(object):
|
||||
$trend.barometer
|
||||
"""
|
||||
|
||||
def __init__(self, time_delta, time_grace, opendb, nowtime, formatter, converter, **option_dict):
|
||||
def __init__(self, time_delta, time_grace, db_binder, data_binding, nowtime, formatter, converter, **option_dict):
|
||||
"""Initialize a Trend object
|
||||
|
||||
time_delta: The time difference over which the trend is to be calculated
|
||||
@@ -396,7 +369,8 @@ class TrendObj(object):
|
||||
"""
|
||||
self.time_delta_val = time_delta
|
||||
self.time_grace_val = time_grace
|
||||
self.opendb = opendb
|
||||
self.db_binder = db_binder
|
||||
self.data_binding = data_binding
|
||||
self.nowtime = nowtime
|
||||
self.formatter = formatter
|
||||
self.converter = converter
|
||||
@@ -416,9 +390,10 @@ class TrendObj(object):
|
||||
if obs_type == 'has_key':
|
||||
raise AttributeError
|
||||
|
||||
db_manager = self.db_binder.get_database(self.data_binding)
|
||||
# Get the current record, and one "time_delta" ago:
|
||||
now_record = self.opendb.getRecord(self.nowtime, self.time_grace_val)
|
||||
then_record = self.opendb.getRecord(self.nowtime - self.time_delta_val, self.time_grace_val)
|
||||
now_record = db_manager.getRecord(self.nowtime, self.time_grace_val)
|
||||
then_record = db_manager.getRecord(self.nowtime - self.time_delta_val, self.time_grace_val)
|
||||
|
||||
# Do both records exist?
|
||||
if now_record is None or then_record is None:
|
||||
|
||||
@@ -88,7 +88,7 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Outside Temperature (with explicit database binding)</td>
|
||||
<td>$db($data_binding='wx_binding').current.outTemp</td>
|
||||
<td>$current($data_binding='wx_binding').outTemp</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Outside Temperature trend ($trend.time_delta.hour.format("%.0f"))</td>
|
||||
|
||||
Reference in New Issue
Block a user