Version 5 - weewx/weewx GitHub Wiki

Overview

This document discusses the goals and design decisions for WeeWX Version 5.

Goals

Complete WeeWX install, including dependencies, using pip, without requiring root privileges. However, the operating system may require privileges in order to install daemon files and to access hardware.

Future-proof the install. Right now, we depend heavily on custom commands in setup.py. However, the imperative approach of setup.py is being phased out in favor of a more declarative approach, using pyproject.toml (see PEP 621 and PEP 631). As an alternative, we could use setup.cfg, but it's clear that pyproject.toml is the future.

Version 5 will require support for importing resources, which was introduced in Python 3.7. However, a backport of importlib.resources is available for Python 3.6. Hence, the earliest supported version of Python will be 3.6 (introduced Dec. 2016). Version 5 will use f-strings, so Python 3.5 cannot be supported.

Support for Python 2.7 will be dropped. All references to six and other compatibility shims will be removed. All __future__ imports will be removed.

Clean separation of WeeWX source code from station data:

  • Easier to back up.
  • Source code can be considered read-only. It could potentially be distributed as a zip file or Python egg.
  • Multiple stations can share the same source code. They just have different station data areas.

See the section Location of user Python code below for details.

Resources

The old distutils approach used by previous versions of WeeWX supported a data_files option that could be used to install miscellaneous resources, such as documentation or configuration files, into a final installation target such as /home/weewx.

However, option data_files is being deprecated for a variety of reasons (see this post for a summary). Instead, data resources must now be included as "package data", that is, as part of a Python package. Like any other package, package data includes an __init__.py file, but unlike regular packages, it can include non-code resources.

That means, once installed, these non-code resources will live deep in the target site-packages directory, where they are difficult to find and even more difficult to modify.

Furthermore, package data must be regarded as "read only". For example, it is possible that WeeWX could be installed as a zipfile or Python egg, so, even if a user was willing to find the data resources deep in site-packages somewhere, s/he still could not edit them.

Location of package data

These are the non-code resources that are used in WeeWX and where they will be located as package data:

Non-code resource Package data location
Configuration file weewx_data/weewx.conf
Examples weewx_data/examples
Skins weewx_data/skins
Daemon utility files weewx_data/util
User code weewx_data/bin/user (but, see below)

Destination for data resources

Previously, we used /home/weewx as the destination for station data, but it required root access in order to set up. With Version 5, the default area becomes ~/weewx-data in the user's home directory. However, /home/weewx can continue to be used by older installations.

Because pip no longer allows free access to the operating system, these user data cannot be set up by pip. Instead, they must be copied into place using a new tool, weectl.

Install process

All of this means that installing WeeWX becomes a two-step process:

  • Install the source code and package data using pip into standard Python library locations (usually, site-packages).

  • Copy package data out of the Python library to a "station data" area using weectl.

Install using pip

See the companion document pip install strategies for all the various way pip and its allies can be used to install WeeWX.

Copy non-code resources

With Version 5, the default area for station data is ~/weewx-data, which allows WeeWX to be installed entirely without root privileges.

The directory /home/weewx served this purpose in previous versions of WeeWX and, indeed, it can continue to be used by just specifying the location /home/weewx/weewx.conf when using the tool weectl. Note that in the past, /home/weewx also held WeeWX code in the bin subdirectory, which, starting with V5, will no longer be used. Instead, all source code will live within the normal Python library structure, except for code used by user-installed extensions, which will live in the station data area.

Build tools

There are many tools that were considered to manage the Python distribution build process including setuptools, pdm, flit, and poetry. We have chosen poetry. It is mature, simple to use, depends on pyproject.toml, and very popular. Poetry can also be used to do an in situ install, but that's not the intended use case. Most users will use pip.

The ubiquitous setuptools was considered, but poetry is easier to use and its implementation of pyproject.toml is more mature. NB: this only affects the distribution build process. Either way, pip is used to install.

Applications

Applications will be invoked using an entry point. This is a small shim, installed by pip, which invokes a function within a module or package.

Namespaces

Most packages used by WeeWX already start with the prefix wee_, which is a reasonable claim to a namespace. However, there are two problem areas: user and schemas. Renaming them would break a lot of code, particularly the renaming of user.

However, the recommended install method is to install into a virtual environment where WeeWX does not have to compete with other Python installs for a unique namespace. A collision is improbable.

Extensions

Through the years, WeeWX has built up an extensive ecosystem of 3rd party extensions. It is essential that we not lose backwards compatibility with them. For this reason, they should continue to be installed directly into the target installation directories, and not indirectly through package resources.

All extensions will be installed into the station data area. That is, into ~/weewx-data, or /etc/weewx.

Nominal locations (new install)

This results in the following list of nominal locations, relative to WEEWX_ROOT:

Symbol Pkg install Pip install
WEEWX_ROOT /etc/weewx ~/weewx-data
SKIN_ROOT ./skins ./skins
DOC_ROOT ./docs ./docs
EXAMPLE_ROOT ./examples ./examples
USER_ROOT ./bin/user ./bin/user
SQLITE_ROOT /var/lib/weewx ./archive
HTML_ROOT /var/www/weewx ./public_html
BIN_ROOT /usr/share/weewx ~/weewx-venv/pythonX.Y/site-packages

Command weectl

Presently, we have 7 different utilities. Version 5 will combining them into one command called, simply, weectl, with different subcommands. By having a single application, we make it easier to find the appropriate subcommand: the user can simply run weectl --help.

Version 5 will offer these subcommands:

Old utility New utility
wee_database weectl database
wee_debug weectl debug
wee_device weectl device
wee_extension weectl extension
wee_import weectl import
wee_reports weectl report
wee_config weectl station

Some examples

# Create a new station data area in ~/weewx-data (the default)
weectl station create
# Upgrade config file, docs, examples, and daemon utility files in ~/weewx-data.
# Skins will be untouched
weectl station upgrade
# Upgrade the config file only
weectl statioin upgrade --what config
# Upgrade the skins only
weectl station upgrade --what skins

# Install the Windy extension:
weectl extension install https://github.com/matthewwall/weewx-windy/archive/master.zip

Location of user Python code ($USER_ROOT)

Previously, user Python code lived amongst the rest of WeeWX's source code, that is, either under /home/weewx/bin, or /usr/share/weewx. However, with Version 5, we are seeking a clean separation between WeeWX source code and station data. Because user Python code is customized, it will live with other station data. For a pip install, its location will be ~/weewx-data/bin/user for a pip install, it's /etc/weewx/bin/user.

In both caes, note that it's the path of the parent directory that gets injected into PYTHON_PATH when weewxd starts up. This is because user is actually a Python package. We need to find user.foo, not just foo.

Subgoals

As far as possible, we want the configuration file weewx.conf used by package installs to be the same as the file used by pip installs. This will simplify the install logic, as well as support burden.

For this reason, it would be desirable if $USER_ROOT is the same for the two install methods. What is different, is the value for $WEEWX_ROOT.

No ambiguity. For legacy installs, it is tempting to inject both the legacy location (e.g., /usr/share/weewx/) and the new location (/etc/weewx/) into PYTHONPATH, which would make old user code accessible in a new install. However, that tempation should be resisted. Only one, well-defined, location should be used, otherwise there can be inconsistent versions between the two locations, leading to difficult-to-diagnose bugs.

Use cases

  • New pip install. Everything under ~/weewx-data.
  • Pip install, using legacy (setup.py) station data. Station data is located under /home/weewx. User Python code can be reused if $USER_ROOT is ./bin/user.
  • New package install. Everything, except the database, is under /etc/weewx.
  • Package install, using legacy station data. Station data is located under /etc/weewx. User legacy Python code is in /usr/share/weewx/user and cannot be reused.
  • Run from git repository.

The table below summarizes the methods and their locations. A question mark means there are several choices.

Method $WEEWX_ROOT $USER_ROOT
New pip ~/weewx-data ?
Legacy pip /home/weewx ./bin/user
New pkg /etc/weewx ?
Legacy pkg /etc/weewx /usr/share/weewx/user
Git ~/weewx-data ?

Potential locations for $USER_ROOT that were considered

The following has the pros and cons for different values of $USER_ROOT. It only discusses legacy installs --- new installs will work with any solution.

$WEEWX_ROOT/bin/user

Pip install, using legacy user python code, would require no changes.

Package install. Cannot reuse legacy python code. All user extensions would have to be either reinstalled, or copied from /usr/share/weewx/user to the new, appropriate $USER_DIR location, perhaps by the postinst script.

$WEEWX_ROOT/lib/user

Has the advantage that the lib clearly indicates the role of its underlying contents: it's part of a library (not some kind of binary). It is also a little more future-proof --- we have clearly deliniated where user supplied library-related code goes ---- although at the moment it's difficult to see where that might be useful.

Pip install would require either a symbolic link from $WEEWX_ROOT/bin to $WEEWX_ROOT/lib, or the user would have to copy files over to its new location.

Package install. The comments for $WEEWX_ROOT/bin/user above apply, except the contents would have to be copied to /etc/weewx/lib/user.

One other comment on using lib instead of bin. Presently, the prototype user subdirectory is located under bin in the source tree, yet it would finally end up under lib. That's an inconsistency. We could relocate it to a new lib subdirectory, but then what of the rest of the WeeWX code? Why is it under bin, instead of also under lib?

$WEEWX_ROOT/user

With this approach, the user package would live directly in $WEEWX_ROOT. It is less verbose, but is, perhaps, a bit less future-proof.

Pip installs would require that the user subdirectory be moved:

mv /home/weewx/bin/user/ /home/weewx

This isn't so bad because once the directory user had been moved, /home/weewx/bin would no longer be needed and can be safely deleted.

Package install. The comments for $WEEWX_ROOT/bin/user above apply, except the contents would have to be copied to /etc/weewx/user.

Definitions

Throughout this document, the following definitions are used

Name Definition
package data A resource, such as weewx.conf or skins, included in a distribution as a Python package. Read-only.
Must be accessed using importlib.resources.
package data location Location of the package data, typically somewhere under site-packages. May or may not be a file.
WEEWX_ROOT Final, installed, location of station data, particularly the configuration file and skins.
Typically, ~/weewx-data, /etc/weewx, or /home/weewx
USER_ROOT The location of the user subdirectory, relative to WEEWX_ROOT.
Typically, ./bin/user, ./lib/user, or ./user.
driver The driver module (e.g., weewx.drivers.vantage).
driver name Returned by the attribute DRIVER_NAME of a driver. By default, this becomes the "stanza name" (e.g., [Vantage]).
active driver Option station_type specifies the active driver to be used. A corresponding driver name must exist.
⚠️ **GitHub.com Fallback** ⚠️