Twitter reader and personal manager

TweeTabs Reference

This project implements a Twitter reader and manager over GTK notebook tabs, hence its name. Each tab represents a set of so-called strips (like users or tweets). The graphical user interface also allows you to define tabs as function of other tabs. These tab operations help you at managing your Twitter life overall.

  • In this manual, the TweeTabs user is referred to as you.
  • There are FIXME notes next to every lie below ☺.




1   Introduction

If you are new to TweeTabs, you might prefer to read the TweeTabs Tutorial first.

1.1   Current status

This is early alpha software. I do have a need as a user for a TweeTabs alike tool, but I'm not especially starving for developing it myself. So, if another Twitter tool suddenly appears with similar capabilities, and is usable enough, I might just switch to using it instead. But as things have been going, it now seems that TweeTabs is not far from being fairly usable.

The project has administrative and technical aspects.

  • Technically, the three main components are the flow of strips through interconnected tabs and associated logic, the graphical user interface, and the management of the Twitter API.
  • Administratively, the project has its own Web site. The documentation only exists as a collection of notes, so postponing more formal writing. The distribution uses a clonable Git repository.

Tweetabs merely begins to be usable, yet very humbly. I may temporarily suffer many deficiencies, knowing that I'll adress them over time. Here are a few uneasy problems which I find especially annoying currently:

  • When the Twitter site becomes slow, TweeTabs becomes unbearable. The story is that I deactivated threading. In pre-alpha, TweeTabs used one thread for the GUI and another for Twitter management, but this induced serious GTK problems, and some others.
  • The URLs within the tweets are still not clickable. It should ideally be as easy as possible to launch the loading of referenced pages in a nearby brower.

1.2   Installation

I could check that TweeTabs works with:

  • Python 2.5 or 2.6
  • pygtk 2.12 (package python-gtk or python-gtk2)
  • PIL 1.1.6 (package python-imaging)
  • simple JSON 1.9.1 or 2.0.9 (package python-simplejson)
  • twyt 0.9.2 (see python-twyt for some more details)

It might likely work with other versions of these, of course.

There is a reachable copy of my own sandbox repository for TweeTabs. To get and install your own copy, once you have the above pre-requisites, try these commands:

git clone git://github.com/pinard/TweeTabs.git

cd Tweetabs

python setup.py install



If you prefer a snapshot packed with tar or zip, just ask, and I'll happily provide one! ☺

2   User documentation

2.1   Usage

Calling tweetabs with the -h option produces the following output:

A Twitter reader and personal manager.



Usage: tweetabs [OPTION]...



Options:

  -h                Print this help and exit

  -g WIDTHxHEIGHT   Set minimum geometry (default 300x200)

  -c CONFIG_DIR     Configuration directory (default ~/.tweetabs
)

  -n                Do not use any default tab setup



Debugging options:

  -d   Disable tweet sending or destructive operations

  -t   Use a separate thread for the Twitter manager

  -i   Stay in Python when the program exits

2.2   The main window

TweeTabs should normally be executed in a bit-mapped display. For now at least, it is preferrable to call it from a terminal emulator, as trace diagnostics may be sent to standard output.

When TweeTabs starts, it displays a window consisting of a menu bar at the top, an area for notebooks in the middle, and an interaction area at the bottom. The notebooks contain tabs, which in turn contain strips, as explained later, these altogether occupy the bulk of the TweeTabs window, and resizing that window mainly changes the region used for displaying notebooks.

2.3   Menu bar

Above the notebooks area, there is an horizontal set of pull-down menus, these allow for triggering various actions. The menu heads are File, Tab, Strip and Help.

The File menu contains:

  • Quit, for exiting the application.

The Help menu contains:

  • (nothing so far)

The other menus are described in the appropriate sections, below.

2.4   Notebooks

A notebook is a collection of pages such than only one is displayed at a given time. Each page has a labelled tab to its top, or FIXME optionally any other side, and these labelled tabs do not overlap. Selecting a particular tab label displays its associated page, hiding the others.

There are plans for allowing more than one notebook from left to right, but there is only one currently. We do not overly try to distinguish between a page and its labelled tab, using tab as a comprehensive term for both. So, we merely say that the all notebooks (or the sole one) hold a number of tabs.

2.5   Tabs

Tabs have a few attributes, and contents in the form of strips.

In most cases, a new tab is automatically given a unique name. You FIXME may rename a tab, or delete its name. An unnamed tab label displays an italicized N, where N is some distinguishing integer. The displayed name is followed by the number of included strips. If a tab is selected, the tab label is colored. If the tab is frozen, it is displayed using a thinner font.

Within a notebook, one tab is the current tab, this is the tab for which strips are being displayed. For making a tab current, you left-click on a tab label. If the window height is not sufficient for showing all tab labels, there are two ways for accessing tabs which are not visible:

  • using the arrows above and below tab labels,
  • using the scroll wheel when the mouse is over the tab labels

Tabs may be reordered by dragging the tab labels and dropping them in their new place.

Tabs are inter-connected, so one tab may read strips from its input tabs and send strips to its output tabs. Strips dynamically flow along these connections. Each tab, depending on its nature and parameters, controls which strips it accepts, and which strips it propagates.

Tabs are indirectly typed from the type of strips they contain. All strips in a tab should share the same tab strip type, yet some strips may pertain to a sub-type of the tab strip type. The strip type of a tab is generally the same as the strip type of its first input, and the strip type of other inputs should be either the same, or a sub-type of the same. There might be exceptions to the preceding rules, as some operators require inputs of different types. The important things to remember is that tabs are strongly typed, and the tab strip type is fixed when tabs get created.

Tabs may be selected, or not. By selecting a tab, you identifiy that tab as one of the arguments for some special operations on tabs, when such operations require arguments. When the operation is later executed, it uses all selected tabs as arguments, and then clears all tab selections. However, if no tab was selected prior to such an operation, that operation uses the current tab as its sole argument.

Tabs may be hidden, or not. A hidden tab still exists and has its usual behaviour, except that it is not shown in any notebook. This is to avoid visual pollution from tabs which are used as intermediary steps in more complex tab computations, but are not of direct interest to you. A hidden tab may not be the current tab as it is not displayed, and consequently, it may not be directly selected. However, a hidden tab is revealed through indirect selection — for example, you may click on Tab / Select / Add inputs from a tab being among the hidden tab's outputs.

Tabs may be frozen, or not. A frozen tab becomes logically immune to any change in its input tabs. A change in any input has not effect on the frozen tab contents, and is not propagated further down to its own output tags. Unfreezing a tab, however, catches up on all input changes and propagate them (save, of course, for its output tabs which are themselves frozen).

Each tab may have associated added and deleted strips, for keeping track of all those strips you FIXME interactively forced into that tab or out of a that tab. A strip may not be part of both, the last forced addition or removal wins. Freezing has no effect on added or deleted strips, these are always effective, and propagated.

The Tab menu contains:

  • Toggle select, repeated for convenience from the Select sub-menu.
  • Configure, which gives access to a sub-menu for tab configuration related matters:
    • Rename, for FIXME changing the name of the current tab. An empty name means that the name gets removed, defaulting to an internally generated name.
    • Toggle frozen, which changes the frozen state of the argument tabs.
    • Hide, which merely removes all argument tabs from the display, yet without destroying them, and keeping all their other effects.
  • Select, which gives access to a sub-menu for selecting or unselecting tabs:
    • Add inputs, which adds to selected tabs all input tabs for any of the argument tabs. If any such input tab was hidden, it is also revealed. Negative inputs to a difference show a different selection color.
    • Add outputs, which adds to selected tabs all output tabs for any of the argument tabs. If any such output tab was hidden, it is also revealed.
    • Clear all, which deselects all tabs being selected, so none remain selected after this action.
    • Inverse, which toggles the selected state for all existing tabs. Hidden tabs are unaffected by this operation, they remain hidden.
    • Toggle select, which has an effect on the current tab only.
  • Timeline, which gives access to a sub-menu for loading tweets, and periodically updating them afterwards, from Twitter timelines. The timeline tabs have an artificial limit to their capacity. The limit is preset to 200 tweets, and FIXME is configurable:
    • Direct, for a tab containing direct messages you recently received from other users.
    • Direct sent, for a tab containing direct messages you recently sent to other users.
    • Friends, for a tab containing tweets recently sent by any of those users you follow. However, you do not see the replies they send to other users, unless you follow them as well.
    • Public, for a tab containing recent public tweets, irrelevant to whether you follow the originator or not.
    • Replies, for a tab showing tweets which are replies to you, or which mention your Twitter name.
    • User, for a tab containing recent tweets originating from you, or FIXME under option, from any other specific user.
  • Users, which gives access to a sub-menu for creating new tabs which contents represent a set of users (FIXME: this is not usable yet, as only the user ids are shown):
    • Followers, for a tab containing the ids of Twitter users which subscribed to your own tweets.
    • Following, for a tab containing the ids of Twitter users you decided to follow.
    • Id input, for a tab containing the lines of some input file. Argument tabs are ignored, and not cleared. The name of the file is FIXME requested interactively.
    • Id output, for a tab which contents gets written to an output file. The name of the file is FIXME requested interactively. The argument tabs which will be union-merged into the newly created tab.
  • Compose, which gives access to a sub-menu for creating new tabs for which contents are dynamically derived from the contents of other tabs:
    • FIXME Added, for a tab created out from all forcibly added strips from the current tab. As a side effect, the added set is cleared, and replaced by enough tab plumbery to dynamically get the same effect.
    • FIXME Deleted, for a tab created out from all forcibly deleted strips from the current tab. As a side effect, the deleted set is cleared, and replaced by enough tab plumbery to dynamically get the same effect.
    • Union, for a tab holding all the strips from all argument tabs.
    • Intersection, for a tab holding only those strips common to all argument tabs.
    • Difference, for a tab holding a copy of the current tab, yet without those strips which appear somewhere in the other argument tabs. For this operation, it does not matter whether if the current tab is selected or not.
  • Delete, which FIXME deletes the argument tabs, after due confirmation. When a tab is deleted, each of its inputs is redirected to all of its outputs. (Surely, there are case where this is not the appropriate thing to do.)

2.6   Strips

Each tab is able to display a set of strips, vertically, from top to bottom. A strip is usually a short text running over one or very few lines, possibly assorted with other widgets, like images or buttons. If there are more strips than the tab may display at once, an elevator bar gets added to the right of the tab, which can be used to scroll strips in and out of the window. The mouse wheel is usable as well.

Strips added to a tab are always added at its end, or bottom. Strips have a natural ordering. When strips get inserted in bulk within a tab instead of one at a time, they are inserted in natural order.

Strips may be selected, or not. By selecting a strip, you identifiy that strip as one of the arguments for some special operations on strips, when such operations require arguments. When the operation is later executed, it uses all selected strips as arguments, and then clears all strip selections.

Each user strip shows information about a specific user. As long as these elements are found, a user strip displays the profile image, the screen name, the real name, the geographical location, an own description, and the home Web site, using the text as the user entered it to the Twitter site. When the strip is selected, the image is surrounded by two colored vertical basrs. The screen name and the URL reference are bolded — there is no attempt to check that the URL exists. The natural order for user strips is alphabetical by screen name.

Each tweet strip shows the sender profile image, the screen name of the originator, the tweet text, the date sent, and the Twitter tool used to send. When the strip is selected, the image is surrounded by two colored vertical bars. URL references, Twitter users and hash tags are bolded in some way — yet there is no attempt to check that these actually exist. The natural order for tweet strips is chronological (or more precisely, by increasing id).

The Strip menu contains:

  • Sort all, which put back all strips of the current tab in their natural order.
  • Select, which gives access to a sub-menu for selecting or unselecting strips:
    • Clear all, which deselects all strips being selected, so none remain selected after this action.
    • Inverse, which toggles the selected state for all existing strips.

2.7   Interaction area

The interaction area is made of two lines: the message line and the entry line. The first is meant for TweeTabs to write informative messages or error diagnostics. The second is meant for you to enter a new tweet. (In Twitter terminology, a tweet is also called a status.)

  • The message line has a left side and a right side.
    • The left side is used to display either a message for a completed GUI action, or a diagnostic as a result of an interrupted GUI action. This message or diagnostic is cleared when you interact again with TweeTabs.
    • The right side is used by the Twitter management. As such, it is somewhat asynchronous with your interactions It may display a message about what is going on, a diagnostic shown in red for any seen problem, and two counters. The counters show how many allowed interactions still remain, as the Twitter site does not allow more than 100 authentified interactions per hour, and another 100 un-authentified interactions per hour. .
  • The entry line allows you to type some text, with basic editing capabilities as common for text entry. The ready tweet is sent when the Enter key is pressed, unless read-only mode (option -r) is in effect. A Twitter tweet may not exceed 140 characters, and a count of the remaining space gets updated on the entry line as you type. Some characters which graphically display as a single character may consume two or three characters, this is related to UTF-8 coding.

3   Configuration

3.1   The configuration directory

The configuration directory, normally ~/.tweetabs/, holds startup directive files and cached data to speed up operations, you may also choose to add files on your own. TweeTabs does not requires that this directory exists. If you elect to delete it, you are responsible for saving your own files, that is, the files yourself crafted or saved in there. TweeTabs will happily rebuild its own caches.

Cache files may become corrupted if you start two TweeTabs instances using the same configuration directory. Some locking FIXME should be put in place to prevent this. Cache files in the configuration directory may not be portable between sites, as their format on each site depends on which database libraries were available when Python was installed. If cache files become corrupted, of if you move the ~/.tweetabs/ directory around, the simplest is to delete any file having -cache in its name.

Some configuration files use Python for a configuration language. This does not mean that you have to know or learn it. The normal usage may be very simple indeed. However, sophisticated users have a lot of power at their disposal if they want to do more fancy initialization. If you use local variables in such files, they get discarded as soon as the file is read.

3.2   The defaults.py file

The defaults.py file within the configuration directory holds Python code to be executed prior to initialization of the user interface. This code may force the value of some TweeTabs options. Here is an example:

# -*- coding: utf-8 -*-

Gui.minimum_height = 500

Twitter.user = "UserName"

Twitter.password = "UserPassword"



This merely forces the TweeTabs window to be at least 500 pixels high, and identifies the Twitter user, assuming that UserName is your Twitter user name and UserPassword is the associated password. The first line is a special comment for the Python interpreter, saying that the file uses Unicode UTF-8. This line is likely omitted in most cases.

I like to maintain my own user name and password in a different file ~/.tweetabs/user, which has been made unreadable by other users via the command chmod 600 ~/tweetabs/user. That file contains only the user name and the user password with some whitespace to separate them. I then replace the two lines beginning with Twitter., above, with:



import os

contents = file(os.path.expanduser('~/.tweetabs/user')).read
()

Twitter.user, Twitter.password = contents.split()

Here is a list of variables you can set in this way:

  • Gui.blanking_delay (default 4 seconds) — the lasting time, on the message line, for each error diagnostic issued by the Twitter manager.
  • Gui.minimum_width (default 300 pixels) — the window should have at least this width.
  • Gui.minimum_height (default 200 pixels) — the window should have at least this height.
  • Gui.spacing (default 7 pixels) — the amount of white space around widgets.
  • Gui.readonly_mode (default False) — if set to True, inhibits the actual sending of tweets from the user interface.
  • Gui.select_color (default "red") — the color of the label for selected tabs.
  • Gui.select2_color (default "darkmagenta") — the color of the label for selected tabs, when with a negative connoitation, like for supplementary arguments of a Difference.
  • Gui.user_color (default "brown") — the usual color for a Twitter user name.
  • Gui.tag_color (default "darkgreen") — the usual color for a Twitter hash tag name.
  • Gui.tag_url (default "blue") — the usual color for an HTTP link.
  • Strip.image_size (default 60 pixels) — the wanted side size of a Twitter user profile image. Images get resized as needed, using good anti-aliasing. However, as the originals are usually 48 pixels, you might prefer that size sharper resolution.
  • Strip.image_loader_capacity (default 800) — the maximum number of user profile images kept in the memory cache, before TweeTabs starts to forget least recently used images.
  • Twitter.user (default None, ought to be overriden) — a string naming your Twitter user.
  • Twitter.password (default None, ought to be overriden) — a string giving the associated Twitter password.

3.3   The tabsetup.py file

The tabsetup.py file within the configuration directory holds Python code to be executed once the user interface has been initialized. This code may automate the initial setup for tabs, and how they get computed from one another. If the tabsetup.py file is not found, some sensible implicit tab setup is executed instead so, by default, TweeTabs looks like a simple Twitter reader. If the -n option was given while calling TweeTabs, there is no initial tab setup, neither explicit nor implicit, and the notebook starts empty.

Here is a (debugging) example:

# -*- coding: utf-8 -*-

f01 = Id_input(configdir + '/01')

f02 = Id_input(configdir + '/02')

f03 = Id_input(configdir + '/03')

f10 = Id_input(configdir + '/10')

f20 = Id_input(configdir + '/20')

f30 = Id_input(configdir + '/30')

f01.set_name('F-01')

f02.set_name('F-02')

f03.set_name('F-03')

f10.set_name('F-10')

f20.set_name('F-20')

f30.set_name('F-30')

union = Union(f01, f02)

inter = Intersection(f02, f20)

diff = Difference(union, f20)

union.set_name('∨')

inter.set_name('∧')

diff.set_name('∧¬')

f99 = Id_output(configdir + '/99', diff)

le = Interactive(range(40, 43))

petit = Interactive(range(50, 55))

chaperon = Interactive(range(60, 80))

route = Interactive(range(90, 97))

The above reads six data files in the same number of tabs. It computes three new tabs from set operations on the data files, and saves one of these resultats on disk. It finally sets up four more tabs with varying amounts of strips, meant to be interactively altered.

f01, union, inter and petit are examples of local variables, which are only used to convey how tabs interact with one another. These variables have just no meaning outside this configuration file.

Here is a sorted list of identifiers having a preset meaning:

  • Difference — a tab maker function which is given a variable number of input tabs as arguments. The tab contents automatically copy the strips from the first input tab, except for those strips which appear in any other input tab.
  • Followers — a tab maker function yielding all current followers for the user.
  • Following — a tab maker function yielding all those being followed by the user.
  • Id_input — a tab maker function which is given a file name as an argument. The strips are derived from the file contents (currently, one line of the file to a strip).
  • Id_output — a tab maker function which is given a file name as a first argument, and a variable number of tabs as supplementary arguments. The created tab acts like an Union tab, and the contents is saved within the name filed, destroying any previous contents for this file (currently, each strip yields one line in the file).
  • Interactive — a tab maker function which is given an iterable sequence of values for the strips as an argument. This tab contents is meant to be modified interactively.
  • Intersection — a tab maker function which is given a variable number of tabs as arguments. The tab contents automatically reflects those strips which are simultaneously present in all input tabs.
  • Union — a tab maker function which is given a variable number of input tabs as arguments. The tab contents automatically reflects all strips from all input tabs, with duplicate removed.
  • configdir — this is the name of the configuration directory, either ~/.tweetabs or the value of the -c option on the tweetabs call.
  • delay — a function which accepts, for its first two arguments, a floating number of seconds and a function. This function is scheduled to be called after the time lapse, then passing it the remaining positional or keyword arguments, if any. The display is updated after the call; by using a sequence of delay(0, …) rather than using all functions directly, you get some feedback while launching a lengthy initial tab setup.

As shown above, tabs (as returned by the tab makers) also have methods, among which:

  • set_name — a method changing the tab label for the string given as an argument. The special value None removes the label.
  • select — a method selecting the tab. Tabs are not selected on creation.
  • freeze — a method freezing the tab. Tabs are not frozen on creation.
  • hide — a method hiding the tab. Tabs are not hidden on creation.

4   Miscellaneous

4.1   History

The idea popped in my mind on 2009-04-09. Five days later, I offered it as a "flash" TweeTabs as a project at MontrealPython 6, hoping that someone would pick it up and do it all for me ☺. The idea looked appealing: besides giving me a likely satisfying Twitter reader and versatile tool, it would have allowed me to explore the fun idea of strip flows, and to become more familiar with GTK. On the other hand, I did not intend to create the tool myself, as I just do not have enough time to work on it. I presented the idea so it does not get plainly lost.

On 2009-05-10, to take a rest from another duty, I took a few hours to ponder what would be implied by tab connections and logic in the Tweetabs idea, and merely to toy with this, wrote a few lines of Python code. I've been surprised by the expressiveness and density of the result.

Soon after, on 2009-05-18, still curious about if TweeTabs is doable or not, I undusted bits of my knowledge of pygtk. Years ago, I used it for a few smallish programs. Devising the skeleton of a GUI for TweeTabs yielded initial results quite fast, and this gave me more courage. Despite the Twitter side of the project had no code yet, I got some hope that I could create TweeTabs after all. So, the next day, I formalized the project setup, and made it visible, relying on the nice Tomboy and my tboy for publishing my scratch notes and raw sketches as they occur.

On 2009-05-26, I laid out the base of a Twitter management module to be run in its own thread, and once again, initial results looked promising. This was enough to get the ball rolling, and the project started for real. (However, threading brought annoying bugs, so I soon managed ways without it.) TweeTabs went from pre-alpha to alpha on 2009-05-31.

  • 2009-05-31 Version 0.1 — Initial release.