Imported from archive.

* Release 1.4.

* (all): Updated the copyright years for 2008 on some of the files
in the current release and added a copyright statement to any files
previously lacking one.

* LICENSE: Replaced the previous BSD-like license with the one used
by the OpenBSD project (modeled after the Internet Software
Consortium's, a two-clause BSD license removing language made
unnecessary by the Berne convention); this new license is
functionally identical to the old one, just more terse and openly
recognized.

* weather: Clarified function parameters in calls from the wrapper
script to ease future ABI changes in the underlying module.

* weather, weather.py: Some extra comments were added to the source,
indentation style was updated from tab characters to three-space,
and lines longer than 79 columns were refactored or otherwise split.

* weather.1, weather.5, weather.py: Added an flines option to allow
the maximum number of forecast output lines to be shortened. Added
furl and murl options to allow overriding of the default current
conditions and forecast data retrieval URLs. Added a headers option
to allow overriding the default list of header names for current
conditions data filtering. Added a quiet option to suppress the
preamble lines and indentation for both current conditions and
forecast output.

* weather.py: Replaced the hardcoded fallback default METAR station
ID and forecast city/state abbreviation with error messages to
minimize confusion when necessary values are omitted. Adjusted a
couple of hard-coded error message strings to be consistent with the
output format of the option_parser module. Switched from urllib to
urllib2 for retrieving data, providing a simpler means to detect and
report retrieval errors. Upped the version to 1.4.
This commit is contained in:
Jeremy Stanley
2008-07-13 07:49:02 +00:00
parent eb249a0ae2
commit 8349654b7c
9 changed files with 434 additions and 263 deletions

25
FAQ
View File

@@ -1,7 +1,9 @@
FREQUENTLY ASKED QUESTIONS ABOUT THE WEATHER UTILITY
Copyright (c) 2006 Jeremy Stanley <fungi@yuggoth.org>, all rights reserved.
Licensed per terms in the LICENSE file distributed with this software.
Copyright (c) 2006-2008 Jeremy Stanley <fungi@yuggoth.org>.
Permission to use, copy, modify, and distribute this software is
granted under terms provided in the LICENSE file distributed with
this software.
Table of Contents:
@@ -44,8 +46,10 @@ state abbreviation to get to a list of cities in that state).
4. I live outside the USA--can this be made to work for me
anyway?
If you have any recommendations for similar forecast data in
other countries, I will be happy to try and find a way to
METAR station IDs can be found for cities and airports worldwide,
but forecast data is harder to come by. If you have any
recommendations of forecast data for other countries available in a
format like NOAA's, I will be happy to try and find a way to
integrate it into the weather utility, but I suspect that some
serious modification would be necessary given that the data is
likely to be published in a non-English language, requiring some
@@ -59,10 +63,9 @@ The -i or --id switch (or the id parameter in an alias definition),
only tells weather(1) what current conditions to retrieve. If you
specify -f or --forecast on the command line (or forecast=True in
an alias) without providing a city name and state abbreviation
(-c/--city and -s/--st, or city and st in an alias), you will
instead see the forecast for the built-in default location (or the
city and st defined in the default alias, if you have one). See
question 3 above for information on figuring out what city name and
state abbreviation to use, and the manual for weatherrc(5) for
information on defining aliases.
(-c/--city and -s/--st, or city and st in an alias) and are seeing
an actual forecast, then you probably have a default city and state
abbreviation set in your config. See question 3 above for
information on figuring out what city name and state abbreviation
to use, and the manual for weatherrc(5) for information on defining
aliases.

View File

@@ -1,7 +1,9 @@
BASIC UNIX INSTALLATION INSTRUCTIONS FOR THE WEATHER UTILITY
Copyright (c) 2006 Jeremy Stanley <fungi@yuggoth.org>, all rights reserved.
Licensed per terms in the LICENSE file distributed with this software.
Copyright (c) 2006-2008 Jeremy Stanley <fungi@yuggoth.org>.
Permission to use, copy, modify, and distribute this software is
granted under terms provided in the LICENSE file distributed with
this software.
PREREQUISITES
@@ -55,4 +57,3 @@ MANUALS
Optionally, the weather.1 and weatherrc.5 files can be placed in
sane locations for TROFF/NROFF manual files on your system (for
example, /usr/local/share/man/ or ~/man/).

31
LICENSE
View File

@@ -1,22 +1,13 @@
Copyright (c) 2006 Jeremy Stanley <fungi@yuggoth.org>, all rights reserved.
Copyright (c) 2006-2008 Jeremy Stanley <fungi@yuggoth.org>
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

35
README
View File

@@ -1,7 +1,9 @@
GENERAL INFORMATION ABOUT THE WEATHER UTILITY
Copyright (c) 2006 Jeremy Stanley <fungi@yuggoth.org>, all rights reserved.
Licensed per terms in the LICENSE file distributed with this software.
Copyright (c) 2006-2008 Jeremy Stanley <fungi@yuggoth.org>.
Permission to use, copy, modify, and distribute this software is
granted under terms provided in the LICENSE file distributed with
this software.
WHAT?
@@ -10,24 +12,24 @@ This command-line utility is intended to provide quick access to
current weather conditions and forecasts. Presently, it is
capable of returning data for localities throughout the USA by
retrieving and formatting decoded METARs (Meteorological
Aerodrome Reports) from NOAA (the National Oceanic and
Atmospheric Administration) and forecasts from the NWS (National
Weather Service). The tool is written to function in the same
spirit as other command-line informational utilities like cal(1),
calendar(1) and dict(1). It can retrieve arbitrary weather data
via specific command-line switches (station ID, city, state), or
aliases can be configured system wide and on a per-user basis. It
can be freely used and redistributed under the terms of the BSD
License.
Aerodrome Reports) from NOAA (the USA National Oceanic and
Atmospheric Administration) and forecasts from NWS (the USA
National Weather Service). The tool is written to function in the
same spirit as other command-line informational utilities like
cal(1), calendar(1) and dict(1). It can retrieve arbitrary weather
data via specific command-line switches (station ID, city, state),
or aliases can be configured system wide and on a per-user basis.
It can be freely used and redistributed under the terms of a
BSD-like License.
WHY?
My girlfriend has a long commute to/from work and school, and
often wants to check the weather both for home and her office.
My girlfriend had a long commute to/from work and school, and
often wanted to check the weather both for home and her office.
Unfortunately, starting a Web browser, pulling up a weather site,
entering multiple ZIP codes and waiting for them to load is
time-consuming for the marginally-impatient. Since she tends to
time-consuming for the marginally-impatient. Since she tended to
stay logged into a shell server most of the time, I figured I'd
install a quick command-line tool to retrieve weather info for
her commute, but to my surprise, a quick search turned up little
@@ -47,6 +49,5 @@ be had here:
http://fungi.yuggoth.org/weather/src/
Alternatively, Debian Etch (testing) and Sid (unstable) users can
install the weather-util package from any mirror.
Alternatively, Debian users can install the weather-util package
from any mirror.

45
weather
View File

@@ -1,16 +1,18 @@
#!/usr/bin/env python
# weather version 1.3, http://fungi.yuggoth.org/weather/
# Copyright (c) 2006 Jeremy Stanley <fungi@yuggoth.org>, all rights reserved.
# Licensed per terms in the LICENSE file distributed with this software.
# weather version 1.4, http://fungi.yuggoth.org/weather/
# Copyright (c) 2006-2008 Jeremy Stanley <fungi@yuggoth.org>.
# Permission to use, copy, modify, and distribute this software is
# granted under terms provided in the LICENSE file distributed with
# this software.
"""Wrapper utility using the weather.py module."""
# added so distributors can consistently specify a private module location
private_module_path = None
if private_module_path:
import sys
sys.path.insert(1, private_module_path)
import sys
sys.path.insert(1, private_module_path)
import weather
@@ -24,17 +26,22 @@ if get_bool("list"): print weather.list_aliases(selections.config)
# normal operation
else:
for argument in selections.arguments:
if get_bool("conditions", argument):
print weather.get_metar(
get("id", argument),
get_bool("verbose", argument)
)
if not get_bool("conditions", argument) \
or get_bool("forecast", argument):
print weather.get_forecast(
get("city", argument),
get("st", argument),
get_bool("verbose", argument)
)
for argument in selections.arguments:
if get_bool("conditions", argument):
print weather.get_metar(
id=get("id", argument),
verbose=get_bool("verbose", argument),
quiet=get_bool("quiet", argument),
headers=get("headers", argument),
murl=get("murl", argument)
)
if not get_bool("conditions", argument) \
or get_bool("forecast", argument):
print weather.get_forecast(
city=get("city", argument),
st=get("st", argument),
verbose=get_bool("verbose", argument),
quiet=get_bool("quiet", argument),
flines=get("flines", argument),
furl=get("furl", argument)
)

View File

@@ -1,6 +1,8 @@
.TH WEATHER 1 "March 26, 2006" "" \" -*- nroff -*-
\" Copyright (c) 2006 Jeremy Stanley <fungi@yuggoth.org>, all rights reserved.
\" Licensed per terms in the LICENSE file distributed with this software.
.TH WEATHER 1 "July 13, 2008" "" \" -*- nroff -*-
\" Copyright (c) 2006-2008 Jeremy Stanley <fungi@yuggoth.org>.
\" Permission to use, copy, modify, and distribute this software is
\" granted under terms provided in the LICENSE file distributed with
\" this software.
.SH NAME
weather \- command\-line tool to obtain weather conditions and forecasts
.SH SYNOPSIS
@@ -30,26 +32,41 @@ show a help message and exit
.B \-cCITY, \-\-city=CITY
the city name (ex: "Raleigh Durham")
.TP
.B \-\-flines=FLINES
maximum number of forecast lines to show
.TP
.B \-f, \-\-forecast
include a local forecast
.TP
.B \-\-furl=FURL
forecast URL (including %city% and %st%)
.TP
.B \-\-headers=HEADERS
the conditions headers to display
.TP
.B \-iID, \-\-id=ID
the METAR station ID (ex: KRDU)
.TP
.B \-l, \-\-list
print a list of configured aliases
.TP
.B \-\-murl=MURL
METAR URL (including %id%)
.TP
.B \-n, \-\-no\-conditions
disable output of current conditions (forces \-f)
.TP
.B \-o, \-\-omit\-forecast
omit the local forecast (cancels \-f)
.TP
.B \-\-quiet
skip preambles and don't indent
.TP
.B \-sST, \-\-st=ST
the state abbreviation (ex: NC)
.TP
.B \-v, \-\-verbose
show full decoded feeds
show full decoded feeds (cancels \-q)
.SH FILES
.B weather
may additionally obtain configuration data from a system\-wide

View File

@@ -1,206 +1,323 @@
# weather.py version 1.3, http://fungi.yuggoth.org/weather/
# Copyright (c) 2006 Jeremy Stanley <fungi@yuggoth.org>, all rights reserved.
# Licensed per terms in the LICENSE file distributed with this software.
# weather.py version 1.4, http://fungi.yuggoth.org/weather/
# Copyright (c) 2006-2008 Jeremy Stanley <fungi@yuggoth.org>.
# Permission to use, copy, modify, and distribute this software is
# granted under terms provided in the LICENSE file distributed with
# this software.
"""Contains various object definitions needed by the weather utility."""
version = "1.3"
version = "1.4"
class Selections:
"""An object to contain selection data."""
def __init__(self):
"""Store the config, options and arguments."""
self.config = get_config()
self.options, self.arguments = get_options(self.config)
if self.arguments:
self.arguments = [(x.lower()) for x in self.arguments]
else: self.arguments = [ None ]
def get(self, option, argument=None):
"""Retrieve data from the config or options."""
if not argument: return self.options.__dict__[option]
elif not self.config.has_section(argument):
import sys
sys.stderr.write("ERROR: no alias defined for " \
+ argument + "\n")
sys.exit(1)
elif self.config.has_option(argument, option):
return self.config.get(argument, option)
else: return self.options.__dict__[option]
def get_bool(self, option, argument=None):
"""Get data and coerce to a boolean if necessary."""
return bool(self.get(option, argument))
"""An object to contain selection data."""
def __init__(self):
"""Store the config, options and arguments."""
self.config = get_config()
self.options, self.arguments = get_options(self.config)
if self.arguments:
self.arguments = [(x.lower()) for x in self.arguments]
else: self.arguments = [ None ]
def get(self, option, argument=None):
"""Retrieve data from the config or options."""
if not argument: return self.options.__dict__[option]
elif not self.config.has_section(argument):
import sys
sys.stderr.write("weather: error: no alias defined for " \
+ argument + "\n")
sys.exit(1)
elif self.config.has_option(argument, option):
return self.config.get(argument, option)
else: return self.options.__dict__[option]
def get_bool(self, option, argument=None):
"""Get data and coerce to a boolean if necessary."""
return bool(self.get(option, argument))
def bool(data):
"""Coerce data to a boolean value."""
if type(data) is str:
if eval(data): return True
else: return False
else:
if data: return True
else: return False
"""Coerce data to a boolean value."""
if type(data) is str:
if eval(data): return True
else: return False
else:
if data: return True
else: return False
def quote(words):
"""Wrap a string in quotes if it contains spaces."""
if words.find(" ") != -1: words = "\"" + words + "\""
return words
"""Wrap a string in quotes if it contains spaces."""
if words.find(" ") != -1: words = "\"" + words + "\""
return words
def sorted(data):
"""Return a sorted copy of a list."""
new_copy = data[:]
new_copy.sort()
return new_copy
"""Return a sorted copy of a list."""
new_copy = data[:]
new_copy.sort()
return new_copy
def get_url(url):
"""Return a string containing the results of a URL GET."""
import urllib
return urllib.urlopen(url).read()
"""Return a string containing the results of a URL GET."""
import urllib2
try: return urllib2.urlopen(url).read()
except urllib2.URLError:
import sys, traceback
sys.stderr.write("weather: error: failed to retrieve\n " \
+ url + "\n " + \
traceback.format_exception_only(sys.exc_type, sys.exc_value)[0])
sys.exit(1)
def get_metar(id, verbose=False):
"""Return a summarized METAR for the specified station."""
metar = get_url(
"http://weather.noaa.gov/pub/data/observations/metar/decoded/" \
+ id.upper() + ".TXT")
if verbose: return metar
else:
lines = metar.split("\n")
headings = [
"Relative Humidity",
"Precipitation last hour",
"Sky conditions",
"Temperature",
"Weather",
"Wind"
]
output = []
output.append("Current conditions at " \
+ lines[0].split(", ")[1] + " (" \
+ id.upper() +")")
output.append("Last updated " + lines[1])
for line in lines:
for heading in headings:
if line.startswith(heading + ":"):
if line.endswith(":0"):
line = line[:-2]
output.append(" " + line)
return "\n".join(output)
def get_metar(id, verbose=False, quiet=False, headers=None, murl=None):
"""Return a summarized METAR for the specified station."""
if not id:
import sys
sys.stderr.write("weather: error: id required for conditions\n")
sys.exit(1)
if not murl:
murl = \
"http://weather.noaa.gov/pub/data/observations/metar/decoded/%ID%.TXT"
murl = murl.replace("%ID%", id.upper())
murl = murl.replace("%Id%", id.capitalize())
murl = murl.replace("%iD%", id)
murl = murl.replace("%id%", id.lower())
murl = murl.replace(" ", "_")
metar = get_url(murl)
if verbose: return metar
else:
lines = metar.split("\n")
if not headers:
headers = \
"relative_humidity," \
+ "precipitation_last_hour," \
+ "sky conditions," \
+ "temperature," \
+ "weather," \
+ "wind"
headerlist = headers.lower().replace("_"," ").split(",")
output = []
if not quiet:
output.append("Current conditions at " \
+ lines[0].split(", ")[1] + " (" \
+ id.upper() +")")
output.append("Last updated " + lines[1])
for header in headerlist:
for line in lines:
if line.lower().startswith(header + ":"):
if line.endswith(":0"):
line = line[:-2]
if quiet: output.append(line)
else: output.append(" " + line)
return "\n".join(output)
def get_forecast(city, st, verbose=False):
"""Return the forecast for a specified city/st combination."""
forecast = get_url("http://weather.noaa.gov/pub/data/forecasts/city/" \
+ st.lower() + "/" + city.lower().replace(" ", "_") \
+ ".txt")
if verbose: return forecast
else:
lines = forecast.split("\n")
output = []
output.append(lines[2])
output.append(lines[3])
for line in lines:
if line.startswith("."):
output.append(line.replace(".", " ", 1))
return "\n".join(output)
def get_forecast(city, st, verbose=False, quiet=False, flines="0", furl=None):
"""Return the forecast for a specified city/st combination."""
if not city or not st:
import sys
sys.stderr.write("weather: error: city and st required for forecast\n")
sys.exit(1)
if not furl:
furl = "http://weather.noaa.gov/pub/data/forecasts/city/%st%/%city%.txt"
furl = furl.replace("%CITY%", city.upper())
furl = furl.replace("%City%", city.capitalize())
furl = furl.replace("%citY%", city)
furl = furl.replace("%city%", city.lower())
furl = furl.replace("%ST%", st.upper())
furl = furl.replace("%St%", st.capitalize())
furl = furl.replace("%sT%", st)
furl = furl.replace("%st%", st.lower())
furl = furl.replace(" ", "_")
forecast = get_url(furl)
if verbose: return forecast
else:
lines = forecast.split("\n")
output = []
if not quiet: output += lines[2:4]
flines = int(flines)
if not flines: flines = len(lines) - 5
for line in lines[5:flines+5]:
if line.startswith("."):
if quiet: output.append(line.replace(".", "", 1))
else: output.append(line.replace(".", " ", 1))
return "\n".join(output)
def get_options(config):
"""Parse the options passed on the command line."""
import optparse
usage = "usage: %prog [ options ] [ alias [ alias [...] ] ]"
verstring = "%prog " + version
option_parser = optparse.OptionParser(usage=usage, version=verstring)
if config.has_option("default", "city"):
default_city = config.get("default", "city")
else: default_city = "Raleigh Durham"
option_parser.add_option("-c", "--city",
dest="city",
default=default_city,
help="the city name (ex: \"Raleigh Durham\")")
if config.has_option("default", "forecast"):
default_forecast = bool(config.get("default", "forecast"))
else: default_forecast = False
option_parser.add_option("-f", "--forecast",
dest="forecast",
action="store_true",
default=default_forecast,
help="include a local forecast")
if config.has_option("default", "id"):
default_id = config.get("default", "id")
else: default_id = "KRDU"
option_parser.add_option("-i", "--id",
dest="id",
default=default_id,
help="the METAR station ID (ex: KRDU)")
option_parser.add_option("-l", "--list",
dest="list",
action="store_true",
default=False,
help="print a list of configured aliases")
if config.has_option("default", "conditions"):
default_conditions = bool(config.get("default", "conditions"))
else: default_conditions = True
option_parser.add_option("-n", "--no-conditions",
dest="conditions",
action="store_false",
default=default_conditions,
help="disable output of current conditions (forces -f)")
option_parser.add_option("-o", "--omit-forecast",
dest="forecast",
action="store_false",
default=default_forecast,
help="omit the local forecast (cancels -f)")
if config.has_option("default", "st"):
default_st = config.get("default", "st")
else: default_st = "NC"
option_parser.add_option("-s", "--st",
dest="st",
default=default_st,
help="the state abbreviation (ex: NC)")
if config.has_option("default", "verbose"):
default_verbose = bool(config.get("default", "verbose"))
else: default_verbose = False
option_parser.add_option("-v", "--verbose",
dest="verbose",
action="store_true",
default=default_verbose,
help="show full decoded feeds")
options, arguments = option_parser.parse_args()
return options, arguments
"""Parse the options passed on the command line."""
# for optparse's builtin -h/--help option
usage = "usage: %prog [ options ] [ alias [ alias [...] ] ]"
# for optparse's builtin --version option
verstring = "%prog " + version
# create the parser
import optparse
option_parser = optparse.OptionParser(usage=usage, version=verstring)
# the -c/--city option
if config.has_option("default", "city"):
default_city = config.get("default", "city")
else: default_city = ""
option_parser.add_option("-c", "--city",
dest="city",
default=default_city,
help="the city name (ex: \"Raleigh Durham\")")
# the --flines option
if config.has_option("default", "flines"):
default_flines = config.get("default", "flines")
else: default_flines = "0"
option_parser.add_option("--flines",
dest="flines",
default=default_flines,
help="maximum number of forecast lines to show")
# the -f/--forecast option
if config.has_option("default", "forecast"):
default_forecast = bool(config.get("default", "forecast"))
else: default_forecast = False
option_parser.add_option("-f", "--forecast",
dest="forecast",
action="store_true",
default=default_forecast,
help="include a local forecast")
# the --furl option
if config.has_option("default", "furl"):
default_furl = config.get("default", "furl")
else:
default_furl = \
"http://weather.noaa.gov/pub/data/forecasts/city/%st%/%city%.txt"
option_parser.add_option("--furl",
dest="furl",
default=default_furl,
help="forecast URL (including %city% and %st%)")
# the --headers option
if config.has_option("default", "headers"):
default_headers = config.get("default", "headers")
else:
default_headers = \
"temperature," \
+ "relative_humidity," \
+ "wind," \
+ "weather," \
+ "sky_conditions," \
+ "precipitation_last_hour"
option_parser.add_option("--headers",
dest="headers",
default=default_headers,
help="the conditions headers to display")
# the -i/--id option
if config.has_option("default", "id"):
default_id = config.get("default", "id")
else: default_id = ""
option_parser.add_option("-i", "--id",
dest="id",
default=default_id,
help="the METAR station ID (ex: KRDU)")
# the -l/--list option
option_parser.add_option("-l", "--list",
dest="list",
action="store_true",
default=False,
help="print a list of configured aliases")
# the --murl option
if config.has_option("default", "murl"):
default_murl = config.get("default", "murl")
else:
default_murl = \
"http://weather.noaa.gov/pub/data/observations/metar/decoded/%ID%.TXT"
option_parser.add_option("--murl",
dest="murl",
default=default_murl,
help="METAR URL (including %id%)")
# the -n/--no-conditions option
if config.has_option("default", "conditions"):
default_conditions = bool(config.get("default", "conditions"))
else: default_conditions = True
option_parser.add_option("-n", "--no-conditions",
dest="conditions",
action="store_false",
default=default_conditions,
help="disable output of current conditions (forces -f)")
# the -o/--omit-forecast option
option_parser.add_option("-o", "--omit-forecast",
dest="forecast",
action="store_false",
default=default_forecast,
help="omit the local forecast (cancels -f)")
# the -q/--quiet option
if config.has_option("default", "quiet"):
default_quiet = bool(config.get("default", "quiet"))
else: default_quiet = False
option_parser.add_option("-q", "--quiet",
dest="quiet",
action="store_true",
default=default_quiet,
help="skip preambles and don't indent")
# the -s/--st option
if config.has_option("default", "st"):
default_st = config.get("default", "st")
else: default_st = ""
option_parser.add_option("-s", "--st",
dest="st",
default=default_st,
help="the state abbreviation (ex: NC)")
# the -v/--verbose option
if config.has_option("default", "verbose"):
default_verbose = bool(config.get("default", "verbose"))
else: default_verbose = False
option_parser.add_option("-v", "--verbose",
dest="verbose",
action="store_true",
default=default_verbose,
help="show full decoded feeds (cancels -q)")
# separate options object from list of arguments and return both
options, arguments = option_parser.parse_args()
return options, arguments
def get_config():
"""Parse the aliases and configuration."""
import ConfigParser
config = ConfigParser.ConfigParser()
import os.path
rcfiles = [
"/etc/weatherrc",
os.path.expanduser("~/.weatherrc"),
"weatherrc"
]
import os
for rcfile in rcfiles:
if os.access(rcfile, os.R_OK): config.read(rcfile)
for section in config.sections():
if section != section.lower():
if config.has_section(section.lower()):
config.remove_section(section.lower())
config.add_section(section.lower())
for option,value in config.items(section):
config.set(section.lower(), option, value)
return config
"""Parse the aliases and configuration."""
import ConfigParser
config = ConfigParser.ConfigParser()
import os.path
rcfiles = [
"/etc/weatherrc",
os.path.expanduser("~/.weatherrc"),
"weatherrc"
]
import os
for rcfile in rcfiles:
if os.access(rcfile, os.R_OK): config.read(rcfile)
for section in config.sections():
if section != section.lower():
if config.has_section(section.lower()):
config.remove_section(section.lower())
config.add_section(section.lower())
for option,value in config.items(section):
config.set(section.lower(), option, value)
return config
def list_aliases(config):
"""Return a formatted list of aliases defined in the config."""
sections = []
for section in sorted(config.sections()):
if section.lower() not in sections and section != "default":
sections.append(section.lower())
output = "configured aliases..."
for section in sorted(sections):
output += "\n " \
+ section \
+ ": --id=" \
+ quote(config.get(section, "id")) \
+ " --city=" \
+ quote(config.get(section, "city")) \
+ " --st=" \
+ quote(config.get(section, "st"))
return output
"""Return a formatted list of aliases defined in the config."""
sections = []
for section in sorted(config.sections()):
if section.lower() not in sections and section != "default":
sections.append(section.lower())
output = "configured aliases..."
for section in sorted(sections):
output += "\n " \
+ section \
+ ": --id=" \
+ quote(config.get(section, "id")) \
+ " --city=" \
+ quote(config.get(section, "city")) \
+ " --st=" \
+ quote(config.get(section, "st"))
return output

View File

@@ -1,3 +1,8 @@
# Copyright (c) 2006-2008 Jeremy Stanley <fungi@yuggoth.org>.
# Permission to use, copy, modify, and distribute this software is
# granted under terms provided in the LICENSE file distributed with
# this software.
[ABE]
City = Allentown
ID = KABE

View File

@@ -1,6 +1,8 @@
.TH WEATHERRC 5 "March 26, 2006" "" \" -*- nroff -*-
\" Copyright (c) 2006 Jeremy Stanley <fungi@yuggoth.org>, all rights reserved.
\" Licensed per terms in the LICENSE file distributed with this software.
.TH WEATHERRC 5 "July 13, 2008" "" \" -*- nroff -*-
\" Copyright (c) 2006-2008 Jeremy Stanley <fungi@yuggoth.org>.
\" Permission to use, copy, modify, and distribute this software is
\" granted under terms provided in the LICENSE file distributed with
\" this software.
.SH NAME
weatherrc \- configuration file format for the
.BR weather (1)
@@ -20,20 +22,47 @@ These parameters are supported...
.B city
the city name (ex: Raleigh Durham)
.TP
.B conditions
output current conditions (possible values are False and True or 0 and 1)
.TP
.B flines
maximum number of forecast lines to show (integer value, 0 means unlimited)
.TP
.B forecast
include a local forecast (possible values are False and True or 0 and 1)
.TP
.B furl
forecast URL (ex: http://forecast.org/%st%/%city%.txt)
.TP
.B headers
the conditions headers to display (ex: temperature,wind)
.TP
.B id
the METAR station ID (ex: KRDU)
.TP
.B conditions
output current conditions (possible values are False and True or 0 and 1)
.B murl
METAR URL (ex: http://metar.org/%id%.txt)
.TP
.B quiet
skip preambles and don't indent (possible values are False and True or 0 and 1)
.TP
.B st
the state abbreviation (ex: NC)
.TP
.B verbose
show full decoded feeds (possible values are False and True or 0 and 1)
.SH URL FORMAT
The placeholders %city% and %st% in the furl URL and %id% in the murl URL
will be replaced with the city, st and id definitions respectively. If the
placeholder has all letters lowercased, the replacement will be forced to
all lowercase. If the placeholder has all letters uppercased, the
replacement will be forced to all uppercase. If the placeholder has its
first letter uppercased and the remainder lowercased, then all words in the
replacement will start with an uppercase letter and the rest will be
lowercase. If the placeholder has its last letter uppercased and the
remainder lowercased, then case will be preserved in the replacement. Also,
after replacement, any spaces in the resulting URL will be converted to
underscore characters prior to use.
.SH EXAMPLES
Following is an example
.B ~/.weatherrc