From c99f9fa95ffcf6f4cb15a069623ae5c613cec6ff Mon Sep 17 00:00:00 2001 From: Tom Keffer Date: Sat, 11 Oct 2014 15:50:48 +0000 Subject: [PATCH] Finished a more complete explanation of how weewx tags interact with the search list. --- docs/customizing.htm | 188 +++++++++++++++++++++++++++---------------- 1 file changed, 119 insertions(+), 69 deletions(-) diff --git a/docs/customizing.htm b/docs/customizing.htm index f595c1b1..177d840b 100644 --- a/docs/customizing.htm +++ b/docs/customizing.htm @@ -1171,7 +1171,7 @@ Sunrise, sunset: 06:51 19:30

In the section on Customizing - templates, we have seen how you can change a template and + templates, we have seen how you can change a template and make use of the various tags available such as $day.outTemp.max for the maximum outside temperature for the day. But, what if you want to introduce some @@ -1195,51 +1195,99 @@ Sunrise, sunset: 06:51 19:30 The answer is to write a search list extension.

-

How tags work

+

How the search list works

- But, before getting too deeply into extensions, it's worth - taking a look at how weewx tags work. - Let's start by looking at a simple example: station altitude, - available as the tag + Let's start by taking a look at how the Cheetah search list + works. +

+

+ The Cheetah template engine (which weewx + uses) finds tags by scanning a search list, a Python + list of objects. For example, for a tag $foo, + the engine will scan down the list, trying each object in the + list in turn. For each object, it will first try using foo as an attribute, that is, it will try + evaluating obj.foo. If that + raises an AttributeError exception, + then it will try foo as a key, that is + obj[key]. If that raises a KeyError exception, then it moves on to + the next item in the list. The first match that does not raise + an exception is used. If no match is found, Cheetah raises a NameMapper.NotFound exception. +

+ +

How tags work

+

+ Now let's take a look at how the search list interacts with weewx tags. Let's start by looking at a + simple example: station altitude, available as the tag

 $station.altitude

- What this returns is not a raw value, say 700, - nor even a string. Instead, it returns an instance of the class - ValueHelper, a special class - defined in module weewx.units. When - the Cheetah template generator encounters this tag, it - eventually needs to convert it into a string. How it does this - is like any other Python object: it calls the special method station. In the default search list, weewx includes one such object, an + instance of the class weewx.cheetahgenerator.Station, + which has an attribute station, so it + gets a hit on this object. +

+

+ Cheetah will then try to evaluate the attribute altitude on this object. Class Station has such an attribute, so Cheetah + evaluates it. +

+ +

+ What this attribute returns is not a raw value, say 700, nor even a string. Instead, it + returns an instance of the class ValueHelper, + a special class defined in module weewx.units. + Internally, it holds the formats, labels, and conversion targets + you specified in your configuration file. It's job is to make sure + that the final output reflects these preferences. Cheetah doesn't know + anything about this class. What it needs, when it has finished + evaluating the expression $day.outTemp.max + is a string. In order to convert the ValueHelper + into a string, it does what every other Python object does when + faced with this situation: it calls the special method __str__. Class ValueHelper has a definition for - this method, which applies any necessary unit conversions, then - consults any formatting and labeling you may have specified, and - then, finally, builds the string. The result is something like + this method. Evaluating this function triggers the final steps + in this process. Any necessary unit conversions are done, then + formatting occurs and, finally, a label is attached. The result + is a string something like

700 feet

+

which is what Cheetah actually puts in the generated HTML + file. +

-

Now let's look at a more complicated example, say the - maximum temperature since midnight:

+

+ Now let's look at a more complicated example, one that uses lazy + evaluation,say the maximum temperature since midnight: +

$day.outTemp.max

When this is evaluated by Cheetah, it actually produces a chain of objects. At the top of this chain is class weewx.stats.TaggedStats, - an instance of which is supplied by the search list - (more on this later). Internally, this instance stores the - database to be hit, as well as a few other bookkeeping objects - (mostly having to do with formatting and labeling). + an instance of which is included in the default search list. + Internally, this instance stores the database to be hit, as well + as a few other bookkeeping objects (mostly having to do with + formatting and labeling).

This instance is examined by Cheetah to see if it has an - attribute day. It does, and it returns - the next class in the chain, an instance of class weewx.stats.TimeSpanStats. This instance - stores not only the database, but also the requested time span, - namely the time since midnight, internally. + attribute day. It does and, when it is + evaluated, it returns the next class in the chain, an instance + of weewx.stats.TimeSpanStats. This + instance stores not only the database, but also the requested + time span, namely the time since midnight, internally.

Cheetah then tries to find an attribute outTemp @@ -1248,57 +1296,57 @@ $station.altitude types would be impractical!). Instead, class TimeSpanStats returns an instance of the next class in the chain, weewx.stats.StatsTypeHelper, which not - only remembers the observation type, but also the database and - the previously evaluated time span. + only remembers what is already known, namely the database to be + hit and the time span, but also adds the observation type, outTemp, in this case.

- Cheetah then tries to find an attribute max + Cheetah then tries to evaluate an attribute max of this class. Now, finally, the chain ends. The attribute max triggers the actual calculation of the - value, using all the known parameters: the time span, the - observation type, and the type of aggregation, querying the - database as necessary. This is an example of lazy - evaluation. That is, the database is not actually hit until - the last possible moment, after everything needed to do the - evalation is known. + value, using all the known parameters: the database to be hit, + the time span of interest, the observation type, and the type of + aggregation, querying the database as necessary. This is an + example of lazy evaluation. That is, the database is not + actually hit until the last possible moment, after everything + needed to do the evalation is known.

The results of the evaluation is then packaged up in, you guessed it, an instance of ValueHelper, - which is what actually converts the value into the desired - string. + which does the final conversion to the desired units, formats + the string, then adds a label. The results, something like +

+

12°C

+

+ are put in the generated HTML file. As you can see, a lot of + machinery is hidden behind the deceptively simple expression $day.outTemp.max!

-

Search list

-

The Cheetah template engine (which weewx uses) finds tags by - scanning a search - list, - a Python list of objects. For example, for a tag $foo, the - engine will scan down the list, trying each object obj in turn. First - it tries using foo as an attribute, that is, - obj.foo. If that raises an - exception AttributeError, then it will try - foo as a key, that is - obj[key]. If that raises a - KeyError, then it moves on to the next item - in the list. The first match that does not raise an exception is - returned. If no match is found, it raises a NameMapper.NotFound - exception.

-

- Extending the list

-

Weewx comes with a number of objects already in the search list, but you can - extend it. To do so, you should have some familiarity with Python, in - particular, how to write new classes and member functions for them.

-

Let's look at an example. The regular version of weewx - offers statistical summaries by day, week, month, and year. Suppose we - would like to add two more:

+

Extending the list

+

+ As mentioned, weewx comes with a + number of objects already in the search list, but you can extend + it. To do so, you should have some familiarity with Python, in + particular, how to write new classes and member functions for + them. +

+

+ Let's look at an example. The regular version of weewx offers statistical summaries by day, + week, month, and year. Suppose we would like to add two more: +

This example is included in the distribution as $BIN_ROOT/examples/xsearch.py:

@@ -1371,7 +1419,9 @@ class MyXSearch(SearchList): #1
  • The class TimeSpanStats represents a - statistical calculation over a time period. In our case, we will set + statistical calculation over a time period. We have already met + it in the introduction How tags work above. + In our case, we will set it up to represent the statistics over all possible times. The class takes 4 parameters.