diff --git a/README.md b/README.rst similarity index 59% rename from README.md rename to README.rst index 76b2f07..da744ee 100644 --- a/README.md +++ b/README.rst @@ -1,15 +1,15 @@ - +.. Always edit README.tpl.md and create README.md by running + python -m i3pystatus.mkdocs You can also let the maintainer do the + latter :) -# i3pystatus +i3pystatus +========== i3pystatus is a (hopefully growing) collection of python scripts for status output compatible to i3status / i3bar of the i3 window manager. -## Installation +Installation +------------ Note: i3pystatus requires Python 3.2 or newer and is not compatible with Python 2.x. @@ -22,9 +22,11 @@ Python 2.x. * [Arch Linux](https://aur.archlinux.org/packages/i3pystatus-git/) -### Release Notes +Release Notes +------------- -#### 3.28 +3.28 (not released yet) ++++++++++++++++++++++++ * **If you're currently using the `i3pystatus` command to run your i3bar**: Replace `i3pystatus` command in your i3 configuration with `python ~/path/to/your/i3pystatus.py` @@ -33,33 +35,40 @@ Python 2.x. * pulseaudio: changed context name to "i3pystatus_pulseaudio" * Code changes -#### 3.27 +3.27 +++++ * Add weather module * Add text module * PulseAudio module: Add muted/unmuted options -#### 3.26 +3.26 +++++ * Add mem module -#### 3.24 +3.24 +++++ **This release introduced changes that may require manual changes to your configuration file** * Introduced TimeWrapper -* battery module: removed remaining_\* formatters in favor of TimeWrapper, -as it can not only reproduce all the variants removed, but can do much more. +* battery module: removed remaining\_* formatters in favor of + TimeWrapper, as it can not only reproduce all the variants removed, + but can do much more. * mpd: Uses TimeWrapper for song_length, song_elapsed -## Configuration +Configuration +------------- The config file is just a normal Python script. A simple configuration file could look like this (note the additional dependencies from network, wireless and pulseaudio in this example): +:: + # -*- coding: utf-8 -*- import subprocess @@ -165,6 +174,8 @@ from network, wireless and pulseaudio in this example): Also change your i3wm config to the following: +:: + # i3bar bar { status_command python ~/.path/to/your/config/file.py @@ -172,23 +183,26 @@ Also change your i3wm config to the following: workspace_buttons yes } -### Formatting +Formatting +++++++++++ All modules let you specifiy the exact output formatting using a [format string](http://docs.python.org/3/library/string.html#formatstrings), which gives you a great deal of flexibility. -Some common stuff: +If a module gives you a float, it probably has a ton of +uninteresting decimal places. Use `{somefloat:.0f}` to get the integer +value, `{somefloat:0.2f}` gives you two decimal places after the +decimal dot -* If a module gives you a float, it probably has a ton of uninteresting decimal -places. Use `{somefloat:.0f}` to get the integer value, `{somefloat:0.2f}` gives -you two decimal places after the decimal dot - -#### formatp +formatp +~~~~~~~ Some modules use an extended format string syntax (the mpd module, for example). Given the format string below the output adapts itself to the available data. +:: + [{artist}/{album}/]{title}{status} Only if both the artist and album is known they're displayed. If only one or none @@ -202,7 +216,8 @@ Inside a group always all format specifiers must evaluate to true (logical and). You can nest groups. The inner group will only become part of the output if both the outer group and the inner group are eligible for output. -#### TimeWrapper +TimeWrapper +~~~~~~~~~~~ Some modules that output times use TimeWrapper to format these. TimeWrapper is a mere extension of the standard formatting method. @@ -211,54 +226,34 @@ The time format that should be used is specified using the format specifier, i.e with some_time being 3951 seconds a format string like `{some_time:%h:%m:%s}` would produce `1:5:51` -* `%h`, `%m` and `%s` are the hours, minutes and seconds without leading zeros -(i.e. 0 to 59 for minutes and seconds) -* `%H`, `%M` and `%S` are padded with a leading zero to two digits, i.e. 00 to 59 -* `%l` and `%L` produce hours non-padded and padded but only if hours is not zero. -If the hours are zero it produces an empty string. +* `%h`, `%m` and `%s` are the hours, minutes and seconds without + leading zeros (i.e. 0 to 59 for minutes and seconds) +* `%H`, `%M` and `%S` are padded with a leading zero to two digits, + i.e. 00 to 59 +* `%l` and `%L` produce hours non-padded and padded but only if hours + is not zero. If the hours are zero it produces an empty string. * `%%` produces a literal % -* `%E` (only valid on beginning of the string) if the time is null, don't format -anything but rather produce an empty string. If the time is non-null it is -removed from the string. -* When the module in question also uses formatp, 0 seconds counts as "not known". -* The formatted time is stripped, i.e. spaces on both ends of the result are removed +* `%E` (only valid on beginning of the string) if the time is null, + don't format anything but rather produce an empty string. If the + time is non-null it is removed from the string. +* When the module in question also uses formatp, 0 seconds counts as + "not known". +* The formatted time is stripped, i.e. spaces on both ends of the + result are removed -## Modules +Modules +------- -System: -[Clock](#clock) - -[Free space](#disk) - -[System load](#load) - -[Memory usage](#mem) - -Audio: -[ALSA](#alsa) - -[PulseAudio](#pulseaudio) - -Hardware: -[Battery](#battery) - -[Screen brightness](#backlight) - -[CPU temperature (Intel)](#temp) - -Network: -[Wired](#network) - -[Wireless](#wireless) - -Other: -[Unread mail](#mail) - -[Tracking parcels](#parcel) - -[pyLoad](#pyload) - -[Weather](#weather) - -[Music Player Daemon (MPD)](#mpd) - -[Simple text](#text) - -Advanced: -[Rip info from files](#file) - -[Regular expressions](#regex) - -[Run watcher](#runwatch) +:System: `clock`_ - `disk`_ - `load`_ - `mem`_ +:Audio: `alsa`_ - `pulseaudio`_ +:Hardware: `battery`_ - `backlight`_ - `temp`_ +:Network: `network`_ - `wireless`_ +:Other: `mail`_ - `parcel`_ - `pyload`_ - `weather`_ - `mpd`_ - `text`_ +:Advanced: `file`_ - `regex`_ - `runwatch`_ -### alsa +alsa +++++ Shows volume of ALSA mixer. You can also use this for inputs, btw. @@ -273,21 +268,22 @@ Available formatters: * `{mixer}` — the associated ALSA mixer -__Settings:__ +Settings: -* `format` — (default: `♪: {volume}`) -* `mixer` — ALSA mixer (default: `Master`) -* `mixer_id` — ALSA mixer id (default: `0`) -* `card` — ALSA sound card (default: `0`) -* `muted` — (default: `M`) -* `unmuted` — (default: ``) -* `color_muted` — (default: `#AAAAAA`) -* `color` — (default: `#FFFFFF`) -* `channel` — (default: `0`) +:format: (default: '♪: {volume}') +:mixer: ALSA mixer (default: 'Master') +:mixer_id: ALSA mixer id (default: '0') +:card: ALSA sound card (default: '0') +:muted: (default: 'M') +:unmuted: (default: '') +:color_muted: (default: '#AAAAAA') +:color: (default: '#FFFFFF') +:channel: (default: '0') -### backlight +backlight ++++++++++ Screen backlight info @@ -298,15 +294,16 @@ Available formatters: * `{percentage}` — current brightness in percent -__Settings:__ +Settings: -* `format` — format string, formatters: brightness, max_brightness, percentage (default: `{brightness}/{max_brightness}`) -* `backlight` — backlight, see `/sys/class/backlight/` (default: `acpi_video0`) -* `color` — (default: `#FFFFFF`) +:format: format string, formatters: brightness, max_brightness, percentage (default: '{brightness}/{max_brightness}') +:backlight: backlight, see `/sys/class/backlight/` (default: 'acpi_video0') +:color: (default: '#FFFFFF') -### battery +battery ++++++++ This class uses the /sys/class/power_supply/…/uevent interface to check for the @@ -322,32 +319,34 @@ Available formatters: * `{battery_ident}` — the same as the setting -__Settings:__ +Settings: -* `battery_ident` — The name of your battery, usually BAT0 or BAT1 (default: `BAT0`) -* `format` — (default: `{status} {remaining}`) -* `alert` — Display a libnotify-notification on low battery (default: `False`) -* `alert_percentage` — (default: `10`) -* `alert_format_title` — The title of the notification, all formatters can be used (default: `Low battery`) -* `alert_format_body` — The body text of the notification, all formatters can be used (default: `Battery {battery_ident} has only {percentage:.2f}% ({remaining:%E%hh:%Mm}) remaining!`) -* `path` — Override the default-generated path (default: `None`) -* `status` — A dictionary mapping ('DIS', 'CHR', 'FULL') to alternative names (default: `{'FULL': 'FULL', 'DIS': 'DIS', 'CHR': 'CHR'}`) +:battery_ident: The name of your battery, usually BAT0 or BAT1 (default: 'BAT0') +:format: (default: '{status} {remaining}') +:alert: Display a libnotify-notification on low battery (default: 'False') +:alert_percentage: (default: '10') +:alert_format_title: The title of the notification, all formatters can be used (default: 'Low battery') +:alert_format_body: The body text of the notification, all formatters can be used (default: 'Battery {battery_ident} has only {percentage:.2f}% ({remaining:%E%hh:%Mm}) remaining!') +:path: Override the default-generated path (default: 'None') +:status: A dictionary mapping ('DIS', 'CHR', 'FULL') to alternative names (default: '{'FULL': 'FULL', 'DIS': 'DIS', 'CHR': 'CHR'}') -### clock +clock ++++++ This class shows a clock -__Settings:__ +Settings: -* `format` — stftime format string, `None` means to use the default, locale-dependent format (default: `None`) +:format: stftime format string, `None` means to use the default, locale-dependent format (default: 'None') -### disk +disk +++++ Gets `{used}`, `{free}`, `{available}` and `{total}` amount of bytes on the given mounted filesystem. @@ -356,57 +355,62 @@ These values can also be expressed in percentages with the `{percentage_used}`, and `{percentage_avail}` formats. -__Settings:__ +Settings: -* `format` — (default: `{free}/{avail}`) -* `path` — (required) -* `divisor` — divide all byte values by this value, commonly 1024**3 (gigabyte) (default: `1073741824`) +:format: (default: '{free}/{avail}') +:path: (required) +:divisor: divide all byte values by this value, commonly 1024**3 (gigabyte) (default: '1073741824') -### file +file +++++ Rip information from text files components is a dict of pairs of the form: +:: + name => (callable, file) * Where `name` is a valid identifier, which is used in the format string to access -the value of that component. + the value of that component. * `callable` is some callable to convert the contents of `file`. A common choice is -float or int. + float or int. * `file` names a file, relative to `base_path`. transforms is a optional dict of callables taking a single argument (a dictionary containing the values of all components). The return value is bound to the key. -__Settings:__ +Settings: -* `format` — (required) -* `components` — (required) -* `transforms` — (default: `{}`) -* `base_path` — (default: `/`) -* `color` — (default: `#FFFFFF`) -* `interval` — (default: `5`) +:format: (required) +:components: (required) +:transforms: (default: '{}') +:base_path: (default: '/') +:color: (default: '#FFFFFF') +:interval: (default: '5') -### load +load +++++ Shows system load -__Settings:__ +Settings: -* `format` — format string used for output. {avg1}, {avg5} and {avg15} are the load average of the last one, five and fifteen minutes, respectively. {tasks} is the number of tasks (i.e. 1/285, which indiciates that one out of 285 total tasks is runnable). (default: `{avg1} {avg5}`) +:format: format string used for output. {avg1}, {avg5} and {avg15} are the load average of the last one, five and fifteen minutes, respectively. {tasks} is the number of tasks (i.e. 1/285, which indiciates that one out of 285 total tasks is runnable). (default: '{avg1} {avg5}') -### mail +mail +++++ Generic mail checker @@ -414,73 +418,77 @@ Generic mail checker The `backends` setting determines the backends to use. Currently available are: -__Settings:__ +Settings: -* `backends` — List of backends (instances of `i3pystatus.mail.xxx.zzz`) -* `color` — (default: `#ffffff`) -* `color_unread` — (default: `#ff0000`) -* `format` — (default: `{unread} new email`) -* `format_plural` — (default: `{unread} new emails`) -* `hide_if_null` — Don't output anything if there are no new mails (default: `True`) +:backends: List of backends (instances of `i3pystatus.mail.xxx.zzz`) +:color: (default: '#ffffff') +:color_unread: (default: '#ff0000') +:format: (default: '{unread} new email') +:format_plural: (default: '{unread} new emails') +:hide_if_null: Don't output anything if there are no new mails (default: 'True') Currently available backends are: -> ### imap.IMAP -> -> -> Checks for mail on a IMAP server -> -> -> __Settings:__ -> -> * `host` — (required) -> * `port` — (default: `993`) -> * `username` — (required) -> * `password` — (required) -> * `ssl` — (default: `True`) -> * `mailbox` — (default: `INBOX`) -> -> -> -> ### notmuchmail.Notmuch -> -> -> This class uses the notmuch python bindings to check for the -> number of messages in the notmuch database with the tags "inbox" -> and "unread" -> -> -> __Settings:__ -> -> * `db_path` — (required) -> -> -> -> ### thunderbird.Thunderbird -> -> -> This class listens for dbus signals emitted by -> the dbus-sender extension for thunderbird. -> -> Requires -> * python-dbus -> -> -> __Settings:__ -> -> -> -> -> +imap.IMAP +~~~~~~~~~ -### mem + +Checks for mail on a IMAP server + + +Settings: + +:host: (required) +:port: (default: '993') +:username: (required) +:password: (required) +:ssl: (default: 'True') +:mailbox: (default: 'INBOX') + + + +notmuchmail.Notmuch +~~~~~~~~~~~~~~~~~~~ + + +This class uses the notmuch python bindings to check for the +number of messages in the notmuch database with the tags "inbox" +and "unread" + + +Settings: + +:db_path: (required) + + + +thunderbird.Thunderbird +~~~~~~~~~~~~~~~~~~~~~~~ + + +This class listens for dbus signals emitted by +the dbus-sender extension for thunderbird. + +Requires python-dbus + + +Settings: + + + + + + +mem ++++ Shows memory load Available formatters: + * {avail_mem} * {percent_used_mem} * {used_mem} @@ -489,39 +497,42 @@ Available formatters: Requires psutil (from PyPI) -__Settings:__ +Settings: -* `format` — format string used for output. (default: `{avail_mem} MB`) +:format: format string used for output. (default: '{avail_mem} MB') -### modsde +modsde +++++++ This class returns i3status parsable output of the number of unread posts in any bookmark in the mods.de forums. -__Settings:__ +Settings: -* `format` — Use {unread} as the formatter for number of unread posts (default: `{unread} new posts in bookmarks`) -* `offset` — subtract number of posts before output (default: `0`) -* `color` — (default: `#7181fe`) -* `username` — (required) -* `password` — (required) +:format: Use {unread} as the formatter for number of unread posts (default: '{unread} new posts in bookmarks') +:offset: subtract number of posts before output (default: '0') +:color: (default: '#7181fe') +:username: (required) +:password: (required) -### mpd +mpd ++++ Displays various information from MPD (the music player daemon) -Available formatters (uses formatp) +Available formatters (uses `formatp`_) + * `{title}` — (the title of the current song) * `{album}` — (the album of the current song, can be an empty string (e.g. for online streams)) * `{artist}` — (can be empty, too) -* `{song_elapsed}` — (Position in the currently playing song, **uses TimeWrapper**, default is `%m:%S`) +* `{song_elapsed}` — (Position in the currently playing song, uses `TimeWrapper`_, default is `%m:%S`) * `{song_length}` — (Length of the current song, same as song_elapsed) * `{pos}` — (Position of current song in playlist, one-based) * `{len}` — (Songs in playlist) @@ -532,16 +543,17 @@ Available formatters (uses formatp) Left click on the module play/pauses, right click (un)mutes. -__Settings:__ +Settings: -* `host` — (default: `localhost`) -* `port` — MPD port (default: `6600`) -* `format` — formatp string (default: `{title} {status}`) -* `status` — Dictionary mapping pause, play and stop to output (default: `{'pause': '▷', 'stop': '◾', 'play': '▶'}`) +:host: (default: 'localhost') +:port: MPD port (default: '6600') +:format: formatp string (default: '{title} {status}') +:status: Dictionary mapping pause, play and stop to output (default: '{'play': '▶', 'stop': '◾', 'pause': '▷'}') -### network +network ++++++++ Display network information about a interface. @@ -549,6 +561,7 @@ Display network information about a interface. Requires the PyPI package `netifaces-py3`. Available formatters: + * `{interface}` — same as setting * `{name}` — same as setting * `{v4}` — IPv4 address @@ -562,55 +575,61 @@ Available formatters: Not available addresses (i.e. no IPv6 connectivity) are replaced with empty strings. -__Settings:__ +Settings: -* `interface` — Interface to obtain information for (default: `eth0`) -* `format_up` — (default: `{interface}: {v4}`) -* `color_up` — (default: `#00FF00`) -* `format_down` — (default: `{interface}`) -* `color_down` — (default: `#FF0000`) -* `name` — (default: `eth0`) +:interface: Interface to obtain information for (default: 'eth0') +:format_up: (default: '{interface}: {v4}') +:color_up: (default: '#00FF00') +:format_down: (default: '{interface}') +:color_down: (default: '#FF0000') +:detached_down: If the interface doesn't exist, display it as if it were down (default: 'False') +:name: (default: 'eth0') -### parcel +parcel +++++++ -__Settings:__ +Settings: -* `instance` — Tracker instance -* `format` — (default: `{name}:{progress}`) -* `name` +:instance: Tracker instance +:format: (default: '{name}:{progress}') +:name: -### pulseaudio +pulseaudio +++++++++++ Shows volume of default PulseAudio sink (output). Available formatters: + * `{volume}` — volume in percent (0...100) * `{db}` — volume in decibels relative to 100 %, i.e. 100 % = 0 dB, 50 % = -18 dB, 0 % = -infinity dB -(the literal value for -infinity is `-∞`) + (the literal value for -infinity is `-∞`) * `{muted}` — the value of one of the `muted` or `unmuted` settings -__Settings:__ +Settings: -* `format` — (default: `♪: {volume}`) -* `muted` — (default: `M`) -* `unmuted` — (default: ``) +:format: (default: '♪: {volume}') +:muted: (default: 'M') +:unmuted: (default: '') -### pyload +pyload +++++++ Shows pyLoad status Available formatters: + * `{captcha}` (see captcha_true and captcha_false, which are the values filled in for this formatter) * `{progress}` (average over all running downloads) * `{progress_all}` (percentage of completed files/links in queue) @@ -620,20 +639,21 @@ Available formatters: * `{free_space}` (free space in download directory in gigabytes) -__Settings:__ +Settings: -* `address` — Address of pyLoad webinterface (default: `http://127.0.0.1:8000`) -* `format` — (default: `{captcha} {progress_all:.1f}% {speed:.1f} kb/s`) -* `captcha_true` — (default: `Captcha waiting`) -* `captcha_false` — (default: ``) -* `download_true` — (default: `Downloads enabled`) -* `download_false` — (default: `Downloads disabled`) -* `username` — (required) -* `password` — (required) +:address: Address of pyLoad webinterface (default: 'http://127.0.0.1:8000') +:format: (default: '{captcha} {progress_all:.1f}% {speed:.1f} kb/s') +:captcha_true: (default: 'Captcha waiting') +:captcha_false: (default: '') +:download_true: (default: 'Downloads enabled') +:download_false: (default: 'Downloads disabled') +:username: (required) +:password: (required) -### regex +regex ++++++ Simple regex file watcher @@ -641,16 +661,17 @@ Simple regex file watcher The groups of the regex are passed to the format string as positional arguments. -__Settings:__ +Settings: -* `format` — format string used for output (default: `{0}`) -* `regex` — (required) -* `file` — file to search for regex matches -* `flags` — Python.re flags (default: `0`) +:format: format string used for output (default: '{0}') +:regex: (required) +:file: file to search for regex matches +:flags: Python.re flags (default: '0') -### runwatch +runwatch +++++++++ Expands the given path using glob to a pidfile and checks @@ -662,18 +683,19 @@ such as a VPN client or your DHCP client is running. Available formatters are {pid} and {name}. -__Settings:__ +Settings: -* `format_up` — (default: `{name}`) -* `format_down` — (default: `{name}`) -* `color_up` — (default: `#00FF00`) -* `color_down` — (default: `#FF0000`) -* `path` — (required) -* `name` — (required) +:format_up: (default: '{name}') +:format_down: (default: '{name}') +:color_up: (default: '#00FF00') +:color_down: (default: '#FF0000') +:path: (required) +:name: (required) -### temp +temp +++++ Shows CPU temperature of Intel processors @@ -681,49 +703,53 @@ Shows CPU temperature of Intel processors AMD is currently not supported as they can only report a relative temperature, which is pretty useless -__Settings:__ +Settings: -* `format` — format string used for output. {temp} is the temperature in degrees celsius, {critical} and {high} are the trip point temps. (default: `{temp} °C`) -* `color` — (default: `#FFFFFF`) -* `color_critical` — (default: `#FF0000`) -* `high_factor` — (default: `0.7`) +:format: format string used for output. {temp} is the temperature in degrees celsius, {critical} and {high} are the trip point temps. (default: '{temp} °C') +:color: (default: '#FFFFFF') +:color_critical: (default: '#FF0000') +:high_factor: (default: '0.7') -### text +text +++++ Display static, colored text. -__Settings:__ +Settings: -* `text` — (required) -* `color` — HTML color code #RRGGBB (default: `None`) +:text: (required) +:color: HTML color code #RRGGBB (default: 'None') -### weather +weather ++++++++ This module gets the weather from weather.com using pywapi module First, you need to get the code for the location from the www.weather.com Available formatters: - {current_temp} - {humidity} + +* {current_temp} +* {humidity} Requires pywapi from PyPI. -__Settings:__ +Settings: -* `location_code` — (required) -* `units` — *C*elsius or *F*ahrenheit (default: `C`) -* `format` — (default: `{current_temp}`) +:location_code: (required) +:units: Celsius (C) or Fahrenheit (F) (default: 'C') +:format: (default: '{current_temp}') -### wireless +wireless +++++++++ Display network information about a interface. @@ -731,37 +757,41 @@ Display network information about a interface. Requires the PyPI packages `netifaces-py3` and `basiciw`. This is based on the network module, so all options and formatters are -the same, except for these additional formatters: +the same, except for these additional formatters and that detached_down doesn't work. + * `{essid}` — ESSID of currently connected wifi * `{freq}` — Current frequency * `{quality}` — Link quality in percent -__Settings:__ +Settings: -* `interface` — Interface to obtain information for (default: `wlan0`) -* `format_up` — (default: `{interface}: {v4}`) -* `color_up` — (default: `#00FF00`) -* `format_down` — (default: `{interface}`) -* `color_down` — (default: `#FF0000`) -* `name` — (default: `eth0`) +:interface: Interface to obtain information for (default: 'wlan0') +:format_up: (default: '{interface}: {v4}') +:color_up: (default: '#00FF00') +:format_down: (default: '{interface}') +:color_down: (default: '#FF0000') +:detached_down: If the interface doesn't exist, display it as if it were down (default: 'False') +:name: (default: 'eth0') -### xrandr +xrandr +++++++ Do Not Publish, private hack of it's own -__Settings:__ +Settings: -## Contribute +Contribute +---------- To contribute a module, make sure it uses one of the Module classes. Most modules use IntervalModule, which just calls a function repeatedly in a specified interval. @@ -771,8 +801,3 @@ the protocol is documented [here](http://i3wm.org/docs/i3bar-protocol.html). **Patches and pull requests are very welcome :-)** -### The README - -The README.md file is generated from the README.tpl.md file; only edit the latter -and run `python -m i3pystatus.mkdocs`. - diff --git a/README.tpl.md b/README.tpl.rst similarity index 79% rename from README.tpl.md rename to README.tpl.rst index c6cb3b0..3407d13 100644 --- a/README.tpl.md +++ b/README.tpl.rst @@ -1,15 +1,15 @@ - +.. Always edit README.tpl.md and create README.md by running + python -m i3pystatus.mkdocs You can also let the maintainer do the + latter :) -# i3pystatus +i3pystatus +========== i3pystatus is a (hopefully growing) collection of python scripts for status output compatible to i3status / i3bar of the i3 window manager. -## Installation +Installation +------------ Note: i3pystatus requires Python 3.2 or newer and is not compatible with Python 2.x. @@ -22,9 +22,11 @@ Python 2.x. * [Arch Linux](https://aur.archlinux.org/packages/i3pystatus-git/) -### Release Notes +Release Notes +------------- -#### 3.28 +3.28 (not released yet) ++++++++++++++++++++++++ * **If you're currently using the `i3pystatus` command to run your i3bar**: Replace `i3pystatus` command in your i3 configuration with `python ~/path/to/your/i3pystatus.py` @@ -33,33 +35,40 @@ Python 2.x. * pulseaudio: changed context name to "i3pystatus_pulseaudio" * Code changes -#### 3.27 +3.27 +++++ * Add weather module * Add text module * PulseAudio module: Add muted/unmuted options -#### 3.26 +3.26 +++++ * Add mem module -#### 3.24 +3.24 +++++ **This release introduced changes that may require manual changes to your configuration file** * Introduced TimeWrapper -* battery module: removed remaining_\* formatters in favor of TimeWrapper, -as it can not only reproduce all the variants removed, but can do much more. +* battery module: removed remaining\_* formatters in favor of + TimeWrapper, as it can not only reproduce all the variants removed, + but can do much more. * mpd: Uses TimeWrapper for song_length, song_elapsed -## Configuration +Configuration +------------- The config file is just a normal Python script. A simple configuration file could look like this (note the additional dependencies from network, wireless and pulseaudio in this example): +:: + # -*- coding: utf-8 -*- import subprocess @@ -165,6 +174,8 @@ from network, wireless and pulseaudio in this example): Also change your i3wm config to the following: +:: + # i3bar bar { status_command python ~/.path/to/your/config/file.py @@ -172,23 +183,26 @@ Also change your i3wm config to the following: workspace_buttons yes } -### Formatting +Formatting +++++++++++ All modules let you specifiy the exact output formatting using a [format string](http://docs.python.org/3/library/string.html#formatstrings), which gives you a great deal of flexibility. -Some common stuff: +If a module gives you a float, it probably has a ton of +uninteresting decimal places. Use `{somefloat:.0f}` to get the integer +value, `{somefloat:0.2f}` gives you two decimal places after the +decimal dot -* If a module gives you a float, it probably has a ton of uninteresting decimal -places. Use `{somefloat:.0f}` to get the integer value, `{somefloat:0.2f}` gives -you two decimal places after the decimal dot - -#### formatp +formatp +~~~~~~~ Some modules use an extended format string syntax (the mpd module, for example). Given the format string below the output adapts itself to the available data. +:: + [{artist}/{album}/]{title}{status} Only if both the artist and album is known they're displayed. If only one or none @@ -202,7 +216,8 @@ Inside a group always all format specifiers must evaluate to true (logical and). You can nest groups. The inner group will only become part of the output if both the outer group and the inner group are eligible for output. -#### TimeWrapper +TimeWrapper +~~~~~~~~~~~ Some modules that output times use TimeWrapper to format these. TimeWrapper is a mere extension of the standard formatting method. @@ -211,55 +226,35 @@ The time format that should be used is specified using the format specifier, i.e with some_time being 3951 seconds a format string like `{some_time:%h:%m:%s}` would produce `1:5:51` -* `%h`, `%m` and `%s` are the hours, minutes and seconds without leading zeros -(i.e. 0 to 59 for minutes and seconds) -* `%H`, `%M` and `%S` are padded with a leading zero to two digits, i.e. 00 to 59 -* `%l` and `%L` produce hours non-padded and padded but only if hours is not zero. -If the hours are zero it produces an empty string. +* `%h`, `%m` and `%s` are the hours, minutes and seconds without + leading zeros (i.e. 0 to 59 for minutes and seconds) +* `%H`, `%M` and `%S` are padded with a leading zero to two digits, + i.e. 00 to 59 +* `%l` and `%L` produce hours non-padded and padded but only if hours + is not zero. If the hours are zero it produces an empty string. * `%%` produces a literal % -* `%E` (only valid on beginning of the string) if the time is null, don't format -anything but rather produce an empty string. If the time is non-null it is -removed from the string. -* When the module in question also uses formatp, 0 seconds counts as "not known". -* The formatted time is stripped, i.e. spaces on both ends of the result are removed +* `%E` (only valid on beginning of the string) if the time is null, + don't format anything but rather produce an empty string. If the + time is non-null it is removed from the string. +* When the module in question also uses formatp, 0 seconds counts as + "not known". +* The formatted time is stripped, i.e. spaces on both ends of the + result are removed -## Modules +Modules +------- -System: -[Clock](#clock) - -[Free space](#disk) - -[System load](#load) - -[Memory usage](#mem) - -Audio: -[ALSA](#alsa) - -[PulseAudio](#pulseaudio) - -Hardware: -[Battery](#battery) - -[Screen brightness](#backlight) - -[CPU temperature (Intel)](#temp) - -Network: -[Wired](#network) - -[Wireless](#wireless) - -Other: -[Unread mail](#mail) - -[Tracking parcels](#parcel) - -[pyLoad](#pyload) - -[Weather](#weather) - -[Music Player Daemon (MPD)](#mpd) - -[Simple text](#text) - -Advanced: -[Rip info from files](#file) - -[Regular expressions](#regex) - -[Run watcher](#runwatch) +:System: `clock`_ - `disk`_ - `load`_ - `mem`_ +:Audio: `alsa`_ - `pulseaudio`_ +:Hardware: `battery`_ - `backlight`_ - `temp`_ +:Network: `network`_ - `wireless`_ +:Other: `mail`_ - `parcel`_ - `pyload`_ - `weather`_ - `mpd`_ - `text`_ +:Advanced: `file`_ - `regex`_ - `runwatch`_ !!module_doc!! -## Contribute +Contribute +---------- To contribute a module, make sure it uses one of the Module classes. Most modules use IntervalModule, which just calls a function repeatedly in a specified interval. @@ -268,8 +263,3 @@ The output attribute should be set to a dictionary which represents your modules the protocol is documented [here](http://i3wm.org/docs/i3bar-protocol.html). **Patches and pull requests are very welcome :-)** - -### The README - -The README.md file is generated from the README.tpl.md file; only edit the latter -and run `python -m i3pystatus.mkdocs`. diff --git a/i3pystatus/file.py b/i3pystatus/file.py index 1044893..251c78f 100644 --- a/i3pystatus/file.py +++ b/i3pystatus/file.py @@ -9,13 +9,15 @@ class File(IntervalModule): Rip information from text files components is a dict of pairs of the form: + + :: name => (callable, file) * Where `name` is a valid identifier, which is used in the format string to access - the value of that component. + the value of that component. * `callable` is some callable to convert the contents of `file`. A common choice is - float or int. + float or int. * `file` names a file, relative to `base_path`. transforms is a optional dict of callables taking a single argument (a dictionary containing the values diff --git a/i3pystatus/mail/thunderbird.py b/i3pystatus/mail/thunderbird.py index 0f16eee..ffe08ba 100644 --- a/i3pystatus/mail/thunderbird.py +++ b/i3pystatus/mail/thunderbird.py @@ -22,8 +22,7 @@ class Thunderbird(Backend): This class listens for dbus signals emitted by the dbus-sender extension for thunderbird. - Requires - * python-dbus + Requires python-dbus """ _unread = set() diff --git a/i3pystatus/mem.py b/i3pystatus/mem.py index c747598..daf6c54 100644 --- a/i3pystatus/mem.py +++ b/i3pystatus/mem.py @@ -9,6 +9,7 @@ class Mem(IntervalModule): Shows memory load Available formatters: + * {avail_mem} * {percent_used_mem} * {used_mem} diff --git a/i3pystatus/mkdocs.py b/i3pystatus/mkdocs.py index 2d992f5..9ff8808 100755 --- a/i3pystatus/mkdocs.py +++ b/i3pystatus/mkdocs.py @@ -10,11 +10,12 @@ from .core.imputil import ClassFinder IGNORE = ("__main__", "mkdocs", "core") MODULE_FORMAT = """ -{heading} {name} +{name} +{heading} {doc} -__Settings:__ +Settings: {settings} @@ -56,7 +57,7 @@ class Module: name=self.name, doc=textwrap.dedent(self.doc), settings=self.format_settings(), - heading=self.heading, + heading=self.heading * len(self.name), endstring=self.endstring ) @@ -83,15 +84,11 @@ class Setting: if self.required: attrs.append("required") if self.default is not self.sentinel: - attrs.append("default: `{default}`".format(default=self.default)) + attrs.append("default: '{default}'".format(default=self.default)) - formatted = "* `{name}` ".format(name=self.name) - if self.doc or attrs: - formatted += "— " - if self.doc: - formatted += self.doc - if attrs: - formatted += " ({attrs})".format(attrs=", ".join(attrs)) + formatted = ":{name}: {doc}".format(name=self.name, doc=self.doc) + if attrs: + formatted += " ({attrs})".format(attrs=", ".join(attrs)) return formatted @@ -126,15 +123,15 @@ def get_all(module_path, heading, finder=None, ignore=None): return sorted(mods, key=lambda module: module.name) -def generate_doc_for_module(module_path, heading="###", finder=None, ignore=None): +def generate_doc_for_module(module_path, heading="+", finder=None, ignore=None): return "".join(map(str, get_all(module_path, heading, finder, ignore or []))) -with open("README.tpl.md", "r") as template: +with open("README.tpl.rst", "r") as template: tpl = template.read() tpl = tpl.replace( "!!module_doc!!", generate_doc_for_module(i3pystatus.__path__)) finder = ClassFinder(baseclass=i3pystatus.mail.Backend) tpl = tpl.replace("!!i3pystatus.mail!!", generate_doc_for_module( - i3pystatus.mail.__path__, "###", finder, ["Backend"]).replace("\n", "\n> ")) - with open("README.md", "w") as output: + i3pystatus.mail.__path__, "~", finder, ["Backend"]).replace("\n", "\n")) + with open("README.rst", "w") as output: output.write(tpl + "\n") diff --git a/i3pystatus/mpd.py b/i3pystatus/mpd.py index baf7702..78a1ac8 100644 --- a/i3pystatus/mpd.py +++ b/i3pystatus/mpd.py @@ -14,11 +14,12 @@ class MPD(IntervalModule): """ Displays various information from MPD (the music player daemon) - Available formatters (uses formatp) + Available formatters (uses `formatp`_) + * `{title}` — (the title of the current song) * `{album}` — (the album of the current song, can be an empty string (e.g. for online streams)) * `{artist}` — (can be empty, too) - * `{song_elapsed}` — (Position in the currently playing song, **uses TimeWrapper**, default is `%m:%S`) + * `{song_elapsed}` — (Position in the currently playing song, uses `TimeWrapper`_, default is `%m:%S`) * `{song_length}` — (Length of the current song, same as song_elapsed) * `{pos}` — (Position of current song in playlist, one-based) * `{len}` — (Songs in playlist) diff --git a/i3pystatus/network.py b/i3pystatus/network.py index 8211012..974617d 100644 --- a/i3pystatus/network.py +++ b/i3pystatus/network.py @@ -54,6 +54,7 @@ class Network(IntervalModule): Requires the PyPI package `netifaces-py3`. Available formatters: + * `{interface}` — same as setting * `{name}` — same as setting * `{v4}` — IPv4 address @@ -71,6 +72,7 @@ class Network(IntervalModule): ("interface", "Interface to obtain information for"), "format_up", "color_up", "format_down", "color_down", + ("detached_down", "If the interface doesn't exist, display it as if it were down"), "name", ) @@ -79,24 +81,28 @@ class Network(IntervalModule): format_down = "{interface}" color_up = "#00FF00" color_down = "#FF0000" + detached_down = False def init(self): - if self.interface not in netifaces.interfaces(): + if self.interface not in netifaces.interfaces() and not self.detached_down: raise RuntimeError( "Unknown interface {iface}!".format(iface=self.interface)) - self.baseinfo = { - "interface": self.interface, - "name": self.name, - "mac": netifaces.ifaddresses(self.interface)[netifaces.AF_PACKET][0]["addr"], - } - def collect(self): + if self.interface not in netifaces.interfaces() and self.detached_down: + self.format = self.format_down + color = self.color_down + return self.color_down, self.format_down, {"interface": self.interface, "name": self.name}, False + info = netifaces.ifaddresses(self.interface) up = netifaces.AF_INET in info or netifaces.AF_INET6 in info fdict = dict( zip_longest(["v4", "v4mask", "v4cidr", "v6", "v6mask", "v6cidr"], [], fillvalue="")) - fdict.update(self.baseinfo) + fdict.update({ + "interface": self.interface, + "name": self.name, + "mac": info[netifaces.AF_PACKET][0]["addr"], + }) if up: format = self.format_up @@ -115,7 +121,7 @@ class Network(IntervalModule): format = self.format_down color = self.color_down - return (color, format, fdict, up) + return color, format, fdict, up def run(self): color, format, fdict, up = self.collect() diff --git a/i3pystatus/pulseaudio/__init__.py b/i3pystatus/pulseaudio/__init__.py index cec8bee..3a0e261 100644 --- a/i3pystatus/pulseaudio/__init__.py +++ b/i3pystatus/pulseaudio/__init__.py @@ -9,9 +9,10 @@ class PulseAudio(Module): Shows volume of default PulseAudio sink (output). Available formatters: + * `{volume}` — volume in percent (0...100) * `{db}` — volume in decibels relative to 100 %, i.e. 100 % = 0 dB, 50 % = -18 dB, 0 % = -infinity dB - (the literal value for -infinity is `-∞`) + (the literal value for -infinity is `-∞`) * `{muted}` — the value of one of the `muted` or `unmuted` settings """ diff --git a/i3pystatus/pyload.py b/i3pystatus/pyload.py index 79c9789..2be5a0b 100644 --- a/i3pystatus/pyload.py +++ b/i3pystatus/pyload.py @@ -15,6 +15,7 @@ class pyLoad(IntervalModule): Shows pyLoad status Available formatters: + * `{captcha}` (see captcha_true and captcha_false, which are the values filled in for this formatter) * `{progress}` (average over all running downloads) * `{progress_all}` (percentage of completed files/links in queue) diff --git a/i3pystatus/weather.py b/i3pystatus/weather.py index b6687f1..1b838de 100644 --- a/i3pystatus/weather.py +++ b/i3pystatus/weather.py @@ -9,8 +9,9 @@ class Weather(IntervalModule): This module gets the weather from weather.com using pywapi module First, you need to get the code for the location from the www.weather.com Available formatters: - {current_temp} - {humidity} + + * {current_temp} + * {humidity} Requires pywapi from PyPI. """ @@ -19,7 +20,7 @@ class Weather(IntervalModule): settings = ( "location_code", - ("units", "*C*elsius or *F*ahrenheit"), + ("units", "Celsius (C) or Fahrenheit (F)"), "format", ) required = ("location_code",) diff --git a/i3pystatus/wireless.py b/i3pystatus/wireless.py index 7ac9a02..595cb26 100644 --- a/i3pystatus/wireless.py +++ b/i3pystatus/wireless.py @@ -12,7 +12,8 @@ class Wireless(Network): Requires the PyPI packages `netifaces-py3` and `basiciw`. This is based on the network module, so all options and formatters are - the same, except for these additional formatters: + the same, except for these additional formatters and that detached_down doesn't work. + * `{essid}` — ESSID of currently connected wifi * `{freq}` — Current frequency * `{quality}` — Link quality in percent @@ -37,4 +38,4 @@ class Wireless(Network): fdict["essid"] = "" fdict["freq"] = fdict["quality"] = 0.0 - return (color, format, fdict, up) + return color, format, fdict, up diff --git a/setup.py b/setup.py index 78535d0..02caf07 100755 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ from setuptools import setup setup(name="i3pystatus", - version="3.27", + version="3.28", description="Like i3status, this generates status line for i3bar / i3wm", url="http://github.com/enkore/i3pystatus", license="MIT",