Source code for pkgwat.api

# -*- coding: utf-8 -*-
# This file is part of pkgwat.
# Copyright (C) 2012 Red Hat, Inc.
#
# pkgwat is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# pkgwat is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with pkgwat; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
""" This is a python API for https://apps.fedoraproject.org/packages

That webapp is a replacement for the `old fedora-community
<https://admin.fedoraproject.org/community/>`_.  It indexes a ton of
information from Fedora Infrastructure and presents it in a
package-centric way.  It was developed by `J5 <http://www.j5live.com/>`_,
`Luke Macken <http://lewk.org>`_, and `Máirín Duffy
<http://blog.linuxgrrl.com/>`_.

In this module, almost all of the methods have a similar signature for limiting
the number of rows, paging data results, specifying releases to query against,
etc.  If the results are problematic (or awesome), you can drop a note in
``#fedora-apps`` on freenode.

You can find the source for this project at
http://github.com/ralphbean/pkgwat.api

:Author: Ralph Bean <rbean@redhat.com>

"""

import collections
import json
import requests

import pkgwat.api
import pkgwat.api.utils

# TODO -- how can this be dynamically linked to setup.py?
__version__ = "0.4"

try:
    # This only works on older versions of python-requests
    import requests.defaults
    requests.defaults.defaults['base_headers']['User-Agent'] = \
            'pkgwat/' + __version__
except ImportError:
    # If it doesn't exist, no biggie.  But we should fix this in the future.
    pass


# TODO -- Tie this into cliff's verbosity options
DEBUG_REQUESTS = False
if DEBUG_REQUESTS:
    import sys

    class myobj(object):
        def write(self, message):
            print("DEBUG:", message)

    try:
        requests.defaults.defaults['verbose'] = myobj()
    except AttributeError:
        pass


BASE_URL = "https://apps.fedoraproject.org/packages/fcomm_connector"

koji_build_states = collections.OrderedDict((
    ('all', ''),
    ('building', '0'),
    ('success', '1'),
    ('failed', '3'),
    ('cancelled', '4'),
    ('deleted', '2'),
))

bodhi_releases = [
    "all",
    "f17",
    "f16",
    "f15",
    "el6",
    "el5",
]

bodhi_statuses = [
    "all",
    "stable",
    "testing",
    "pending",
    "obsolete",
]

yum_releases = [
    'Rawhide',
    'Fedora 16',
    'Fedora 16 Testing',
    'Fedora 15',
    'Fedora 15 Testing',
    'Fedora 14',
    'Fedora 14 Testing',
]

yum_arches = [
    'x86_64',
    'i686',
]

bugzilla_releases = collections.OrderedDict((
    ('all', ''),
    ('f17', '17'),
    ('f16', '16'),
    ('f15', '15'),
    ('el6', '6'),
    ('el5', '5'),
))


def _make_request(path, query, strip_tags):
    """ Internal util function to make a request of the connector API. """
    query_as_json = json.dumps(query)
    url = "/".join([BASE_URL, path, query_as_json])
    response = requests.get(url)
    d = response.json

    if callable(d):
        d = d()

    if strip_tags:
        d = pkgwat.api.utils.strip_tags(d)

    return d



[docs]def releases(package, rows_per_page=10, start_row=0, strip_tags=True): """ Search for a pattern in package names, descriptions, and tags :view: https://apps.fedoraproject.org/packages/nethack >>> import pkgwat.api >>> pkgwat.api.releases("nethack") The above will return a list of release information:: {u'rows': [{u'release': u'Rawhide', u'stable_version': u'3.4.3-27.fc18', u'testing_version': u'Not Applicable'}, {u'release': u'Fedora 18', u'stable_version': u'3.4.3-27.fc18', u'testing_version': u'None'}, {u'release': u'Fedora 17', u'stable_version': u'3.4.3-26.fc17', u'testing_version': u'None'}, {u'release': u'Fedora 16', u'stable_version': u'3.4.3-25.fc15', u'testing_version': u'None'}, {u'release': u'Fedora EPEL 6', u'stable_version': u'None', u'testing_version': u'None'}, {u'release': u'Fedora EPEL 5', u'stable_version': u'3.4.3-12.el5.1', u'testing_version': u'None'}], u'rows_per_page': 10, u'start_row': 0, u'total_rows': 6, u'visible_rows': 6} """ path = "bodhi/query/query_active_releases" query = { "filters": {"package": package}, "rows_per_page": rows_per_page, "start_row": start_row, } return _make_request(path, query, strip_tags)
[docs]def builds(package, state='all', rows_per_page=10, start_row=0, strip_tags=True): """ Retrieve a list of the latest koji builds for a package. :view: https://apps.fedoraproject.org/packages/ccze/builds >>> import pkgwat.api >>> pkgwat.api.builds("ccze", rows_per_page=2) The above will return a list of koji builds that looks like:: {u'rows': [{u'build_id': 332286, u'completion_time': u'2012-07-19 04:01:20.495063', u'completion_time_display': {u'elapsed': u'4 minutes', u'time': u'04:01 AM UTC', u'when': u'27 days ago'}, u'completion_ts': 1342670480.49506, u'creation_event_id': 4896507, u'creation_time': u'2012-07-19 03:57:20.152193', u'creation_ts': 1342670240.15219, u'epoch': None, u'name': u'ccze', u'nvr': u'ccze-0.2.1-10.fc18', u'owner_id': 131, u'owner_name': u'ausil', u'package_id': 8962, u'package_name': u'ccze', u'release': u'10.fc18', u'state': 1, u'state_str': u'complete', u'task_id': 4250727, u'version': u'0.2.1', u'volume_id': 0, u'volume_name': u'DEFAULT'}, {u'build_id': 298617, u'completion_time': u'2012-02-10 13:15:51.600556', u'completion_time_display': {u'elapsed': u'3 minutes', u'time': u'01:15 PM UTC', u'when': u'6 months ago'}, u'completion_ts': 1328879751.60056, u'creation_event_id': 4407860, u'creation_time': u'2012-02-10 13:12:44.186579', u'creation_ts': 1328879564.18658, u'epoch': None, u'name': u'ccze', u'nvr': u'ccze-0.2.1-9.fc18', u'owner_id': 1374, u'owner_name': u'ppisar', u'package_id': 8962, u'package_name': u'ccze', u'release': u'9.fc18', u'state': 1, u'state_str': u'complete', u'task_id': 3778561, u'version': u'0.2.1', u'volume_id': 0, u'volume_name': u'DEFAULT'}], u'rows_per_page': 2, u'start_row': 0, u'total_rows': 15, u'visible_rows': 2} """ if state not in koji_build_states.values(): state = koji_build_states[state] path = "koji/query/query_builds" query = { "filters": { "package": package, "state": state, }, "rows_per_page": rows_per_page, "start_row": start_row, } return _make_request(path, query, strip_tags)
[docs]def updates(package, release="all", status="all", rows_per_page=10, start_row=0, strip_tags=True): """ Retrieve a list of bodhi updates for a package. :view: https://apps.fedoraproject.org/packages/ccze/updates >>> import pkgwat.api >>> pkgwat.api.updates("ccze") The above will return a list of updates with comments and more:: {u'rows': [{u'actions': '', u'date_pushed': u'10 Aug 2010', u'date_pushed_display': u'2 years ago', u'date_submitted_display': u'2 years ago', u'details': u'10 Aug 2010', u'dist_updates': [{ u'approved': None, u'bugs': [ {u'bz_id': 578958, u'parent': False, u'security': False, u'title': u'[abrt] crash in ccze-0.2.1-5.fc12: Process \ /usr/bin/ccze was killed by signal 11'}, {u'bz_id': 612866, u'parent': False, u'security': False, u'title': u'[abrt] crash in ccze-0.2.1-5.fc12: \ parse_opt: Process /usr/bin/ccze was killed by signal 11 (SIGSEGV)'}], u'builds': [{u'nvr': u'ccze-0.2.1-6.el5', u'package': { u'committers': [u'hubbitus'], u'name': u'ccze', u'suggest_reboot': False}}], u'close_bugs': True, u'comments': [{u'anonymous': False, u'author': u'bodhi', u'group': None, u'karma': 0, u'text': u'This update has been submitted for \ testing by hubbitus. ', u'timestamp': u'2010-08-10 07:30:07', u'update_title': u'ccze-0.2.1-6.el5'}, {u'anonymous': False, u'author': u'bodhi', u'group': None, u'karma': 0, u'text': u'This update has been pushed to testing', u'timestamp': u'2010-08-10 17:55:25', u'update_title': u'ccze-0.2.1-6.el5'}, {u'anonymous': False, u'author': u'bodhi', u'group': None, u'karma': 0, u'text': u'This update has reached 14 days in \ testing and can be pushed to stable now if the maintainer wishes', u'timestamp': u'2010-08-24 23:06:30', u'update_title': u'ccze-0.2.1-6.el5'}, {u'anonymous': False, u'author': u'bodhi', u'group': None, u'karma': 0, u'text': u'This update has been submitted for \ stable by hubbitus. ', u'timestamp': u'2010-08-25 08:00:11', u'update_title': u'ccze-0.2.1-6.el5'}, {u'anonymous': False, u'author': u'bodhi', u'group': None, u'karma': 0, u'text': u'This update has been pushed to stable', u'timestamp': u'2010-08-25 18:54:46', u'update_title': u'ccze-0.2.1-6.el5'}], u'critpath': False, u'critpath_approved': True, u'date_modified': None, u'date_pushed': u'2010-08-10 17:23:39', u'date_submitted': u'2010-08-10 07:29:56', u'karma': 0, u'nagged': None, u'notes': '', u'release': { u'dist_tag': u'dist-5E-epel', u'id_prefix': u'FEDORA-EPEL', u'locked': False, u'long_name': u'Fedora EPEL 5', u'name': u'EL-5'}, u'release_name': u'Fedora EPEL 5', u'request': None, u'stable_karma': 3, u'status': u'stable', u'submitter': u'hubbitus', u'title': u'ccze-0.2.1-6.el5', u'type': u'bugfix', u'unstable_karma': -3, u'updateid': u'FEDORA-EPEL-2010-3205', u'version': u'0.2.1-6.el5'}], u'id': u'ccze-0.2.1-6.el5', u'karma_level': u'meh', u'karma_str': u' 0', u'name': u'ccze', u'nvr': u'ccze-0.2.1-6.el5', u'package_name': u'ccze', u'releases': [u'Fedora EPEL 5'], u'request_id': u'ccze021-6el5', u'status': u'stable', u'title': u'ccze-0.2.1-6.el5', u'versions': [u'0.2.1-6.el5']}], u'rows_per_page': 10, u'start_row': 0, u'total_rows': 2, u'visible_rows': 1} """ if release not in bodhi_releases: raise ValueError("Invalid bodhi release. %r %r" % ( release, bodhi_releases)) if status not in bodhi_statuses: raise ValueError("Invalid bodhi status. %r %r" % ( status, bodhi_statuses)) if release == "all": release = "" if status == "all": status = "" path = "bodhi/query/query_updates" query = { "filters": { "package": package, "release": release, "status": status, }, "rows_per_page": rows_per_page, "start_row": start_row, } return _make_request(path, query, strip_tags)
[docs]def bugs(package, release="all", rows_per_page=10, start_row=0, strip_tags=True): """ Return a list of bugs for a given package and release. :view: https://apps.fedoraproject.org/packages/python-prettytable/bugs >>> import pkgwat.api >>> pkgwat.api.bugs("python-prettytable") The above will yield a list of bugs on the given package:: {u'rows': [{u'bug_class': '', u'description': u'Python3 support', u'id': 837087, u'last_modified': u'4 decades, 2 years, 7 months, \ 14 days and 22 hours', u'release': u'Fedora 17', u'status': u'Assigned'}], u'rows_per_page': 10, u'start_row': 0, u'total_rows': 1, u'visible_rows': 1} """ if release not in bugzilla_releases.values(): release = bugzilla_releases[release] path = "bugzilla/query/query_bugs" query = { "filters": { "package": package, "version": release, }, "rows_per_page": rows_per_page, "start_row": start_row, } return _make_request(path, query, strip_tags)
[docs]def contents(package, arch="x86_64", release="Rawhide", strip_tags=True): """ Returns the contents of a package. :view: https://apps.fedoraproject.org/packages/mutt/contents :warning: This one behaves a little differently. """ if release not in yum_releases: raise ValueError("Invalid yum release. %r %r" % ( release, yum_releases)) if arch not in yum_arches: raise ValueError("Invalid yum arch. %r %r" % ( arch, yum_arches)) path = "yum/get_file_tree" query = { "package": package, "arch": arch, "repo": release, } url = "/".join([BASE_URL, path]) response = requests.get(url, params=query) d = response.json # In newer versions of python-requests, response.json is a method and must # be invoked. In older versions, it was just an attribute to be accessed. if callable(d): d = d() if strip_tags: d = pkgwat.api.utils.strip_tags(d) return d
[docs]def changelog(package, rows_per_page=10, start_row=0, strip_tags=True): """ Returns the changelog of a package. :view: https://apps.fedoraproject.org/packages/vim/changelog >>> import pkgwat.api >>> pkgwat.api.changelog("vim", rows_per_page=2) The above will return the changelog of a package.. something like:: {u'rows': [{u'author': u'Karsten Hopp ', u'date': u'2012-08-06 12:00:00', u'date_ts': 1344254400, u'display_date': u'06 Aug 2012', u'email': u'karsten@redhat.com', u'text': u'- drop vim-6.1-rh3.patch, (bz #754801)', u'version': u'7.3.604-1'}, {u'author': u'Karsten Hopp ', u'date': u'2012-08-06 12:00:00', u'date_ts': 1344254400, u'display_date': u'06 Aug 2012', u'email': u'karsten@redhat.com', u'text': u'- patchlevel 622', u'version': u'7.3.622-1'}], u'rows_per_page': 2, u'start_row': 0, u'total_rows': 71, u'visible_rows': 2} """ build_id = builds(package)['rows'][0]['build_id'] path = "koji/query/query_changelogs" query = { "filters": { "build_id": build_id, }, "rows_per_page": rows_per_page, "start_row": start_row, } return _make_request(path, query, strip_tags)

This Page