“Natural Language” Representation of Messages

fedmsg.meta handles the conversion of fedmsg messages (dict-like json objects) into internationalized human-readable strings: strings like "nirik voted on a tag in tagger" and "lmacken commented on a bodhi update."

The intent is to use the module 1) in the fedmsg-irc bot and 2) in the gnome-shell desktop notification widget. The sky is the limit, though.

The primary entry point is fedmsg.meta.msg2repr() which takes a dict and returns the string representation. Portions of that string are in turn produced by fedmsg.meta.msg2title(), fedmsg.meta.msg2subtitle(), and fedmsg.meta.msg2link().

Message processing is handled by a list of MessageProcessors (instances of fedmsg.meta.base.BaseProcessor) which are discovered on a setuptools entry-point. Messages for which no MessageProcessor exists are handled gracefully.

The original deployment of fedmsg in Fedora Infrastructure uses metadata providers/message processors from a plugin called fedmsg_meta_fedora_infrastructure. If you’d like to add your own processors for your own deployment, you’ll need to extend fedmsg.meta.base.BaseProcessor and override the appropriate methods. If you package up your processor and expose it on the fedmsg.meta entry-point, your new class will need to be added to the fedmsg.meta.processors list at runtime.

End users can have multiple plugin sets installed simultaneously.

exception fedmsg.meta.ProcessorsNotInitialized

Bases: exceptions.Exception

fedmsg.meta.conglomerate(messages, subject=None, lexers=False, **config)

Return a list of messages with some of them grouped into conglomerate messages. Conglomerate messages represent several other messages.

For example, you might pass this function a list of 40 messages. 38 of those are git.commit messages, 1 is a bodhi.update message, and 1 is a badge.award message. This function could return a list of three messages, one representing the 38 git commit messages, one representing the bodhi.update message, and one representing the badge.award message.

The subject argument is optional and will return “subjective” representations if possible (see msg2subjective(...)).

Functionality is provided by fedmsg.meta plugins on a “best effort” basis.

fedmsg.meta.legacy_condition(cls)
fedmsg.meta.make_processors(**config)

Initialize all of the text processors.

You’ll need to call this once before using any of the other functions in this module.

>>> import fedmsg.config
>>> import fedmsg.meta
>>> config = fedmsg.config.load_config([], None)
>>> fedmsg.meta.make_processors(**config)
>>> text = fedmsg.meta.msg2repr(some_message_dict, **config)
fedmsg.meta.msg2agent(msg, processor=None, **config)

Return the single username who is the “agent” for an event.

An “agent” is the one responsible for the event taking place, for example, if one person gives karma to another, then both usernames are returned by msg2usernames, but only the one who gave the karma is returned by msg2agent.

If the processor registered to handle the message does not provide an agent method, then the first user returned by msg2usernames is returned (whether that is correct or not). Here we assume that if a processor implements agent, then it knows what it is doing and we should trust that. But if it does not implement it, we’ll try our best guess.

If there are no users returned by msg2usernames, then None is returned.

fedmsg.meta.msg2avatars(msg, legacy=False, **config)

Return a dict mapping of usernames to avatar URLs.

fedmsg.meta.msg2emails(msg, legacy=False, **config)

Return a dict mapping of usernames to email addresses.

fedmsg.meta.msg2icon(msg, legacy=False, **config)

Return a primary icon associated with a message.

fedmsg.meta.msg2lexer(msg, processor=None, **config)

Return a Pygments lexer able to parse the long_form of this message.

Return a URL associated with a message.

fedmsg.meta.msg2long_form(msg, legacy=False, **config)

Return a ‘long form’ text representation of a message.

For most message, this will just default to the terse subtitle, but for some messages a long paragraph-structured block of text may be returned.

fedmsg.meta.msg2objects(msg, legacy=False, **config)

Return a set of objects associated with a message.

“objects” here is the “objects” from english grammar.. meaning, the thing in the message upon which action is being done. The “subject” is the user and the “object” is the packages, or the wiki articles, or the blog posts.

Where possible, use slash-delimited names for objects (as in wiki URLs).

fedmsg.meta.msg2packages(msg, legacy=False, **config)

Return a set of package names associated with a message.

fedmsg.meta.msg2processor(msg, **config)

For a given message return the text processor that can handle it.

This will raise a fedmsg.meta.ProcessorsNotInitialized exception if fedmsg.meta.make_processors() hasn’t been called yet.

fedmsg.meta.msg2repr(msg, legacy=False, **config)

Return a human-readable or “natural language” representation of a dict-like fedmsg message. Think of this as the ‘top-most level’ function in this module.

fedmsg.meta.msg2secondary_icon(msg, legacy=False, **config)

Return a secondary icon associated with a message.

fedmsg.meta.msg2subjective(msg, legacy=False, **config)

Return a human-readable text representation of a dict-like fedmsg message from the subjective perspective of a user.

For example, if the subject viewing the message is “oddshocks” and the message would normally translate into “oddshocks commented on ticket #174”, it would instead translate into “you commented on ticket #174”.

fedmsg.meta.msg2subtitle(msg, legacy=False, **config)

Return a ‘subtitle’ or secondary text associated with a message.

fedmsg.meta.msg2title(msg, legacy=False, **config)

Return a ‘title’ or primary text associated with a message.

fedmsg.meta.msg2usernames(msg, legacy=False, **config)

Return a set of FAS usernames associated with a message.

fedmsg.meta.with_processor()
fedmsg.meta.processors = ProcessorsNotInitialized('You must first call fedmsg.meta.make_processors(**config)',)
class fedmsg.meta.base.BaseConglomerator(processor, internationalization_callable, **conf)

Bases: object

Base Conglomerator. This abstract base class must be extended.

fedmsg.meta “conglomerators” are similar to but different from the fedmsg.meta “processors”. Where processors take a single message are return metadata about them (subtitle, a list of usernames, etc..), conglomerators take multiple messages and return a reduced subset of “conglomerate” messages. Think: there are 100 messages where pbrobinson built 100 different packages in koji – we can just represent those in a UI somewhere as a single message “pbrobinson built 100 different packages (click for details)”.

This BaseConglomerator is meant to be extended many times over to provide plugins that know how to conglomerate different combinations of messages.

can_handle(msg, **config)

Return true if we should begin to consider a given message.

conglomerate(messages, subject=None, lexers=False, **conf)

Top-level API entry point. Given a list of messages, transform it into a list of conglomerates where possible.

static list_to_series(items, N=3, oxford_comma=True)

Convert a list of things into a comma-separated string.

>>> list_to_series(['a', 'b', 'c', 'd'])
'a, b, and 2 others'
>>> list_to_series(['a', 'b', 'c', 'd'], N=4, oxford_comma=False)
'a, b, c and d'
matches(a, b, **config)

Return true if message a can be paired with message b.

merge(constituents, subject, **config)

Given N presumably matching messages, return one merged message

classmethod produce_template(constituents, subject, lexers=False, **config)

Helper function used by merge. Produces the beginnings of a merged conglomerate message that needs to be later filled out by a subclass.

select_constituents(messages, **config)

From a list of messages, return a subset that can be merged

skip(message, **config)
class fedmsg.meta.base.BaseProcessor(internationalization_callable, **config)

Bases: object

Base Processor. Without being extended, this doesn’t actually handle any messages.

Processors require that an internationalization_callable be passed to them at instantiation. Internationalization is often done at import time, but we handle it at runtime so that a single process may translate fedmsg messages into multiple languages. Think: an IRC bot that runs #fedora-fedmsg, #fedora-fedmsg-es, #fedora-fedmsg-it. Or: a twitter bot that posts to multiple language-specific accounts.

That feature is currently unused, but fedmsg.meta supports future internationalization (there may be bugs to work out).

agent = NotImplemented
avatars(msg, **config)

Return a dict of avatar URLs associated with a message.

conglomerate(messages, **config)

Given N messages, return another list that has some of them grouped together into a common ‘item’.

A conglomeration of messages should be of the following form:

{
  'subtitle': 'relrod pushed commits to ghc and 487 other packages',
  'link': None,  # This could be something.
  'icon': 'https://that-git-logo',
  'secondary_icon': 'https://that-relrod-avatar',
  'start_time': some_timestamp,
  'end_time': some_other_timestamp,
  'human_time': '5 minutes ago',
  'usernames': ['relrod'],
  'packages': ['ghc', 'nethack', ... ],
  'topics': ['org.fedoraproject.prod.git.receive'],
  'categories': ['git'],
  'msg_ids': {
      '2014-abcde': {
          'subtitle': 'relrod pushed some commits to ghc',
          'title': 'git.receive',
          'link': 'http://...',
          'icon': 'http://...',
      },
      '2014-bcdef': {
          'subtitle': 'relrod pushed some commits to nethack',
          'title': 'git.receive',
          'link': 'http://...',
          'icon': 'http://...',
      },
  },
}

The telltale sign that an entry in a list of messages represents a conglomerate message is the presence of the plural msg_ids field. In contrast, ungrouped singular messages should bear a singular msg_id field.

conglomerators = None
emails(msg, **config)

Return a dict of emails associated with a message.

handle_msg(msg, **config)

If we can handle the given message, return the remainder of the topic.

Returns None if we can’t handle the message.

icon(msg, **config)

Return a “icon” for the message.

lexer(msg, **config)

Return a pygments lexer that can be applied to the long_form.

Returns None if no lexer is associated.

Return a “link” for the message.

long_form(msg, **config)

Return some paragraphs of text about a message.

objects(msg, **config)

Return a set of objects associated with a message.

packages(msg, **config)

Return a set of package names associated with a message.

secondary_icon(msg, **config)

Return a “secondary icon” for the message.

subjective(msg, subject, **config)

Return a “subjective” subtitle for the message.

subtitle(msg, **config)

Return a “subtitle” for the message.

title(msg, **config)
topic_prefix_re = None
usernames(msg, **config)

Return a set of FAS usernames associated with a message.

fedmsg.meta.base.add_metaclass(metaclass)

Compat shim for el7.