python-debianbts-1.11/0000755000000000000000000000000011742765227011611 5ustar python-debianbts-1.11/src/0000755000000000000000000000000011531435600012361 5ustar python-debianbts-1.11/src/__init__.py0000644000000000000000000000000011212725613014462 0ustar python-debianbts-1.11/src/debianbts.py0000644000000000000000000002267211531435600014677 0ustar #!/usr/bin/env python # debianbts.py - Methods to query Debian's BTS. # Copyright (C) 2007-2010 Bastian Venthur # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program 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 General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. """Query Debian's Bug Tracking System (BTS). This module provides a layer between Python and Debian's BTS. It provides methods to query the BTS using the BTS' SOAP interface, and the Bugreport class which represents a bugreport from the BTS. """ from datetime import datetime import SOAPpy # Setup the soap server # TODO: recognize HTTP proxy environment variable # Default values URL = 'http://bugs.debian.org/cgi-bin/soap.cgi' NS = 'Debbugs/SOAP/V1' server = SOAPpy.SOAPProxy(URL, NS) BTS_URL = 'http://bugs.debian.org/' class Bugreport(object): """Represents a bugreport from Debian's Bug Tracking System. A bugreport object provides all attributes provided by the SOAP interface. Most of the attributs are strings, the others are marked. * bug_num: The bugnumber (int) * severity: Severity of the bugreport * tags: List of tags of the bugreport (list of strings) * subject: The subject/title of the bugreport * originator: Submitter of the bugreport * mergedwith: List of bugnumbers this bug was merged with (list of ints) * package: Package of the bugreport * source: Source package of the bugreport * date: Date of bug creation (datetime) * log_modified: Date of update of the bugreport (datetime) * done: Is the bug fixed or not (bool) * archived: Is the bug archived or not (bool) * unarchived: Was the bug unarchived or not (bool) * fixed_versions: List of versions, can be empty even if bug is fixed (list of strings) * found_versions: List of version numbers where bug was found (list of strings) * forwarded: A URL or email address * blocks: List of bugnumbers this bug blocks (list of ints) * blockedby: List of bugnumbers which block this bug (list of ints) * pending: Either 'pending' or 'done' * msgid: Message ID of the bugreport * owner: Who took responsibility for fixing this bug * location: Either 'db-h' or 'archive' * affects: List of Packagenames (list of strings) * summary: Arbitrary text """ def __init__(self): self.originator = None self.date = None self.subject = None self.msgid = None self.package = None self.tags = None self.done = None self.forwarded = None self.mergedwith = None self.severity = None self.owner = None self.found_versions = None self.fixed_versions = None self.blocks = None self.blockedby = None self.unarchived = None self.summary = None self.affects = None self.log_modified = None self.location = None self.archived = None self.bug_num = None self.source = None self.pending = None # The ones below are also there but not used #self.fixed = None #self.found = None #self.fixed_date = None #self.found_date = None #self.keywords = None #self.id = None def __str__(self): s = "" for key, value in self.__dict__.iteritems(): if type(value) == type(unicode()): value = value.encode('utf-8') s += "%s: %s\n" % (key, str(value)) return s def __cmp__(self, other): """Compare a bugreport with another. The more open and and urgent a bug is, the greater the bug is: outstanding > resolved > archived critical > grave > serious > important > normal > minor > wishlist. Openness always beats urgency, eg an archived bug is *always* smaller than an outstanding bug. This sorting is useful for displaying bugreports in a list and sorting them in a useful way. """ myval = self._get_value() otherval = other._get_value() if myval < otherval: return -1 elif myval == otherval: return 0 else: return 1 def _get_value(self): if self.archived: # archived and done val = 0 elif self.done: # not archived and done val = 10 else: # not done val = 20 val += {u"critical" : 7, u"grave" : 6, u"serious" : 5, u"important" : 4, u"normal" : 3, u"minor" : 2, u"wishlist" : 1}[self.severity] return val def get_status(*nr): """Returns a list of Bugreport objects.""" reply = server.get_status(*nr) # If we called get_status with one single bug, we get a single bug, # if we called it with a list of bugs, we get a list, # No available bugreports returns an enmpy list bugs = [] if not reply: pass elif type(reply[0]) == type([]): for elem in reply[0]: bugs.append(_parse_status(elem)) else: bugs.append(_parse_status(reply[0])) return bugs def get_usertag(email, *tags): """Return a dictionary of "usertag" => buglist mappings. If tags are given the dictionary is limited to the matching tags, if no tags are given all available tags are returned. """ reply = server.get_usertag(email, *tags) # reply is an empty string if no bugs match the query return dict() if reply == "" else reply._asdict() def get_bug_log(nr): """Return a list of Buglogs. A buglog is a dictionary with the following mappings: "header" => string "body" => string "attachments" => list "msg_num" => int """ reply = server.get_bug_log(nr) buglog = [i._asdict() for i in reply._aslist()] for b in buglog: b["header"] = _uc(b["header"]) b["body"] = _uc(b["body"]) b["msg_num"] = int(b["msg_num"]) b["attachments"] = b["attachments"]._aslist() return buglog def newest_bugs(amount): """Returns a list of bugnumbers of the `amount` newest bugs.""" reply = server.newest_bugs(amount) return reply._aslist() def get_bugs(*key_value): """Returns a list of bugnumbers, that match the conditions given by the key-value pair(s). Possible keys are: "package": bugs for the given package "submitter": bugs from the submitter "maint": bugs belonging to a maintainer "src": bugs belonging to a source package "severity": bugs with a certain severity "status": can be either "done", "forwarded", or "open" "tag": see http://www.debian.org/Bugs/Developer#tags for available tags "owner": bugs which are assigned to `owner` "bugs": takes list of bugnumbers, filters the list according to given criteria "correspondent": bugs where `correspondent` has sent a mail to Example: get_bugs('package', 'gtk-qt-engine', 'severity', 'normal') """ reply = server.get_bugs(*key_value) return reply._aslist() def _parse_status(status): """Return a bugreport object from a given status.""" status = status._asdict() bug = Bugreport() tmp = status['value'] bug.originator = _uc(tmp['originator']) bug.date = datetime.utcfromtimestamp(tmp['date']) bug.subject = _uc(tmp['subject']) bug.msgid = _uc(tmp['msgid']) bug.package = _uc(tmp['package']) bug.tags = _uc(tmp['tags']).split() bug.done = bool(tmp['done']) bug.forwarded = _uc(tmp['forwarded']) bug.mergedwith = [int(i) for i in str(tmp['mergedwith']).split()] bug.severity = _uc(tmp['severity']) bug.owner = _uc(tmp['owner']) bug.found_versions = [_uc(str(i)) for i in tmp['found_versions']] bug.fixed_versions = [_uc(str(i)) for i in tmp['fixed_versions']] bug.blocks = [int(i) for i in str(tmp['blocks']).split()] bug.blockedby = [int(i) for i in str(tmp['blockedby']).split()] bug.unarchived = bool(tmp["unarchived"]) bug.summary = _uc(tmp['summary']) bug.affects = [_uc(i) for i in tmp['affects']] bug.log_modified = datetime.utcfromtimestamp(tmp['log_modified']) bug.location = _uc(tmp['location']) bug.archived = bool(tmp["archived"]) bug.bug_num = int(tmp['bug_num']) bug.source = _uc(tmp['source']) bug.pending = _uc(tmp['pending']) # Also available, but unused or broken #bug.fixed = _parse_crappy_soap(tmp, "fixed") #bug.found = _parse_crappy_soap(tmp, "found") #bug.found_date = [datetime.utcfromtimestamp(i) for i in tmp["found_date"]] #bug.fixed_date = [datetime.utcfromtimestamp(i) for i in tmp["fixed_date"]] #bug.keywords = _uc(tmp['keywords']).split() #bug.id = int(tmp['id']) return bug def _uc(string): """Convert string to unicode. This method only exists to unify the unicode conversion in this module. """ return unicode(string, 'utf-8', 'replace') python-debianbts-1.11/setup.py0000755000000000000000000000140211742765220013314 0ustar from distutils.core import setup setup( name='python-debianbts', version='1.11', description='Python interface to Debians Bug Tracking System', keywords='debian, soap, bts', author='Bastian Venthur', author_email='venthur@debian.org', url='https://github.com/venthur/python-debianbts', license='GPL2', package_dir = {'': 'src'}, py_modules = ['debianbts'], classifiers=[ "Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Intended Audience :: Developers", "License :: OSI Approved :: GNU General Public License (GPL)", "Programming Language :: Python", "Topic :: Communications", "Topic :: Software Development :: Bug Tracking", ], ) python-debianbts-1.11/MANIFEST.in0000644000000000000000000000006311531435600013327 0ustar include MANIFEST.in include test/test_debianbts.py python-debianbts-1.11/test/0000755000000000000000000000000011531435632012556 5ustar python-debianbts-1.11/test/test_debianbts.py0000755000000000000000000001204711531435600016124 0ustar #!/usr/bin/env python # debianbts_test.py - Unittests for debianbts.py. # Copyright (C) 2009 Bastian Venthur # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program 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 General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import unittest import debianbts as bts class DebianBtsTestCase(unittest.TestCase): def setUp(self): self.b1 = bts.Bugreport() self.b1.severity = 'normal' self.b2 = bts.Bugreport() self.b2.severity = 'normal' def testGetUsertagEmpty(self): """get_usertag should return empty dict if no bugs are found.""" d = bts.get_usertag("thisisatest@debian.org") self.assertEqual(d, dict()) def testGetUsertag(self): """get_usertag should return dict with tag(s) and buglist(s).""" d = bts.get_usertag("debian-python@lists.debian.org") self.assertEqual(type(d), type(dict())) for k, v in d.iteritems(): self.assertEqual(type(""), type(k)) self.assertEqual(type([]), type([])) def testGetBugsEmpty(self): """get_bugs should return empty list if no matching bugs where found.""" l = bts.get_bugs("package", "thisisatest") self.assertEqual(l, []) def testGetBugs(self): """get_bugs should return list of bugnumbers.""" l = bts.get_bugs("owner", "venthur@debian.org") self.assertEqual(type(l), type([])) for i in l: self.assertEqual(type(i), type(int())) def testNewestBugs(self): """newest_bugs shoudl return list of bugnumbers.""" l = bts.newest_bugs(10) self.assertEqual(type(l), type([])) for i in l: self.assertEqual(type(i), type(int())) def testNewestBugsAmount(self): """newest_bugs(amount) should return a list of len 'amount'. """ for i in 0, 1, 10: l = bts.newest_bugs(i) self.assertEqual(len(l), i) def testGetBugLog(self): """get_bug_log should return the correct data types.""" bl = bts.get_bug_log(223344) self.assertEqual(type(bl), type([])) for i in bl: self.assertEqual(type(i), type(dict())) self.assertTrue(i.has_key("attachments")) self.assertEqual(type(i["attachments"]), type(list())) self.assertTrue(i.has_key("body")) self.assertEqual(type(i["body"]), type(unicode())) self.assertTrue(i.has_key("header")) self.assertEqual(type(i["header"]), type(unicode())) self.assertTrue(i.has_key("msg_num")) self.assertEqual(type(i["msg_num"]), type(int())) def testComparison(self): self.b1.archived = True self.b2.done = True self.assertTrue(self.b2 > self.b1) def test_mergedwith(self): """Mergedwith is always a list of int.""" # this one is merged with two other bugs m = bts.get_status(486212)[0].mergedwith self.assertTrue(len(m) == 2) for i in m: self.assertEqual(type(i), type(int())) # this one was merged with one bug m = bts.get_status(433550)[0].mergedwith self.assertTrue(len(m) == 1) self.assertEqual(type(m[0]), type(int())) # this one was not merged m = bts.get_status(474955)[0].mergedwith self.assertEqual(m, list()) def test_affects(self): """affects is a list of str.""" # this one affects one bug #a = bts.get_status(290501)[0].affects #self.assertTrue(len(a) == 1) #self.assertEqual(type(a[0]), type(str())) # this one affects no other bug a = bts.get_status(437154)[0].affects self.assertEqual(a, []) def test_regression_588954(self): """Get_bug_log must convert the body correctly to unicode.""" try: bts.get_bug_log(582010) except UnicodeDecodeError: self.fail() def test_regression_590073(self): """bug.blocks is sometimes a str sometimes an int.""" try: # test the int case # TODO: test the string case bts.get_status(568657) except TypeError: self.fail() def test_regression_590725(self): """bug.body utf sometimes contains invalid continuation bytes.""" try: bts.get_bug_log(578363) bts.get_bug_log(570825) except UnicodeDecodeError: self.fail() if __name__ == "__main__": unittest.main() python-debianbts-1.11/debian/0000755000000000000000000000000011742765116013030 5ustar python-debianbts-1.11/debian/control0000644000000000000000000000126111742764542014435 0ustar Source: python-debianbts Section: python Priority: optional Maintainer: Bastian Venthur Build-Depends: debhelper (>= 9), python-support (>= 0.6), python Standards-Version: 3.9.3.1 Vcs-Git: git://github.com/venthur/python-debianbts.git Vcs-Browser: http://github.com/venthur/python-debianbts Package: python-debianbts Architecture: all Depends: ${shlibs:Depends}, ${misc:Depends}, ${python:Depends}, python-soappy Provides: ${python:Provides} Description: Python interface to Debian's Bug Tracking System This package provides the debianbts module, which allows one to query Debian's BTS via it's SOAP-inteface and returns the answer in Python's native data types. python-debianbts-1.11/debian/changelog0000644000000000000000000001505511742765116014710 0ustar python-debianbts (1.11) unstable; urgency=low * Uploaded lots of changes contributed by Jari Aalto. Thank you very much man! * Remove unused dpatch and upgrade to packaging format "3.0 (native)". * Update to Standards-Version to 3.9.3.1 and debhelper to 9. * Add build-arch and build-indep targets to rules file. * Fix copyright-with-old-dh-make-debian-copyright (Lintian). * Fix spelling-error-in-description (Lintian). * Fix copyright-refers-to-symlink-license (Lintian). * Merged with patch from Michael, improving distutils setup. -- Bastian Venthur Mon, 16 Apr 2012 10:40:08 +0100 python-debianbts (1.10) unstable; urgency=low * Switched to distutils -- Bastian Venthur Thu, 24 Feb 2011 10:04:22 +0100 python-debianbts (1.9) unstable; urgency=low * Fixed issue in unicode handling in Bugreport.__str__ method * Added documentation for 'bugs' keyword in get_bugs -- Bastian Venthur Fri, 06 Aug 2010 21:38:29 -0400 python-debianbts (1.8) unstable; urgency=low * Fix "please add a Vcs-Browser field in source stanza" (Closes: #590929) * Fixed the types of the mergedwith-, blocks-, blockedby-, and affects-fields of the Bugreport class: the first three changed from "String" to "list of Strings" the last one from "String" to list of Strings" * Removed the keywords-, found_date-, fixed_date-, and id-attributs as they are either not fully implemented in the BTS or superflouos * Added Unittests to ensure the above works as expected * Furhter improved the documentation of the methods and the Bugreport class -- Bastian Venthur Sun, 01 Aug 2010 22:47:06 -0400 python-debianbts (1.7) unstable; urgency=low * Fix "remove *.pyc from source package" Added rm *.pyc rule in clean targets. (Closes: #590722) * Fix "UnicodeDecodeError: 'utf8' codec can't decode byte 0xe4 in position 44: invalid continuation byte" We replace invalid unicode characters now (Closes: #590725) -- Bastian Venthur Thu, 29 Jul 2010 22:21:01 +0200 python-debianbts (1.6) unstable; urgency=low * Fix "reportbug-ng: coercing to Unicode: need string or buffer, int found", apparently "blocks" is sometimes a string and sometimes an int. (Closes: #590073) -- Bastian Venthur Sat, 24 Jul 2010 15:01:00 +0200 python-debianbts (1.5) unstable; urgency=low * Fix "UnicodeDecodeError on get_bug_log() and other methods", added regression test for this bug. (Closes: #588954) -- Bastian Venthur Sat, 17 Jul 2010 14:59:17 +0200 python-debianbts (1.4~bpo50+1) lenny-backports; urgency=low * Rebuild for lenny-backports. -- Bastian Venthur Tue, 22 Jun 2010 23:00:05 +0200 python-debianbts (1.4) unstable; urgency=low * Fix "[python-debianbts] Typo that generates incorrect output" Fixed trivial typo (Closes: #566554) -- Bastian Venthur Sun, 24 Jan 2010 12:51:03 +0100 python-debianbts (1.3) unstable; urgency=low * Removed id, found and fixed (Closes: #550945) - According to Don id is superflous and will vanish, use bug_num instead - found and fixed are only partly implemented in debbugs, found_versions and fixed_versions give the information you need. -- Bastian Venthur Wed, 14 Oct 2009 23:52:19 +0200 python-debianbts (1.2) unstable; urgency=low * Fixed typo in debian/pyversions -- Bastian Venthur Sun, 11 Oct 2009 13:14:57 +0200 python-debianbts (1.1) unstable; urgency=low * Make python-debianbts depend on python >= 2.5 - (Closes: #550569) python-debianbts: fails to compile with Python 2.4!! - (Closes: #550571) python-debianbts: Incompatible with python2.4!! -- Bastian Venthur Sun, 11 Oct 2009 12:34:03 +0200 python-debianbts (1.0) unstable; urgency=low * Major version number jump breaks backwards compatibility * Added support for usertags * Bugreport class provides exactly the members, provided by SOAP even if they don't make sense: - id and bug_nr seem to be identical all the time - found and found_versions as well - keywords and tags also - even fixed and fixed date - summary is always empty, but subject gives the summary - ... and probably some other quirks * get_bug_log now returns a dict instead of an object * removed HTMLStripper class -- we use SOAP for a while now * removed get_html_fulltext -- bugs.debian.org/bugnr does the trick too * Major refactings * Added unittests -- Bastian Venthur Sat, 10 Oct 2009 20:20:31 +0200 python-debianbts (0.6) unstable; urgency=low * Updated VCS-git field in debian/control, we moved to github * Bumped standards version (no changes) -- Bastian Venthur Sat, 19 Sep 2009 16:29:45 +0200 python-debianbts (0.5) unstable; urgency=low The "greetings from Graz" release * Fix "python-glpk and python-debianbts: error when trying to install together" Removed __init__.py (Closes: #546561) * Fix "submitter field is always None" (Closes: #542651) -- Bastian Venthur Mon, 14 Sep 2009 10:59:30 +0200 python-debianbts (0.4) unstable; urgency=low * Fix "incomplete documentation for debianbts.get_bugs()", added "correspondent" to docstring (Closes: #529588) * Fix "timestamps represented as strings", first- and lastaction are now datetimeobjects, thanks Jakub (Closes: #529488) * Added VCS-git field to debian/control * Bumped standards version * Replaced dh_clean -k with dh_prep in debian/rules * Replaced Author(s) with Author in debian/copyright -- Bastian Venthur Sun, 07 Jun 2009 15:03:52 +0200 python-debianbts (0.3) unstable; urgency=low * Added support for Tags -- Bastian Venthur Sat, 11 Oct 2008 17:16:38 +0200 python-debianbts (0.2.1) unstable; urgency=low * Corrected priority from extra to optional * Fixed short and long package description to make lintian happy -- Bastian Venthur Fri, 11 Jul 2008 14:38:17 +0200 python-debianbts (0.2) unstable; urgency=low * Changed SOAP namespace to Debbugs/SOAP/V1, thanks Don for the hint! * Added values for Bugreports to compare their severities * Added HTML Parser and get_html_fulltext(bugnr) -- Bastian Venthur Mon, 07 Jul 2008 23:26:58 +0200 python-debianbts (0.1) unstable; urgency=low * Initial Release. -- Bastian Venthur Sun, 06 Jul 2008 19:40:04 +0200 python-debianbts-1.11/debian/pyversions0000644000000000000000000000000511264337053015161 0ustar 2.5- python-debianbts-1.11/debian/compat0000644000000000000000000000000211742763773014235 0ustar 9 python-debianbts-1.11/debian/rules0000755000000000000000000000353111742763773014121 0ustar #!/usr/bin/make -f # -*- makefile -*- # Sample debian/rules that uses debhelper. # This file was originally written by Joey Hess and Craig Small. # As a special exception, when this file is copied by dh-make into a # dh-make output file, you may use that output file without restriction. # This special exception was added by Craig Small in version 0.37 of dh-make. # Uncomment this to turn on verbose mode. #export DH_VERBOSE=1 configure: configure-stamp configure-stamp: dh_testdir # Add here commands to configure the package. touch configure-stamp build-arch: build build-indep: build build: build-stamp build-stamp: configure-stamp dh_testdir # Add here commands to compile the package. python setup.py build #docbook-to-man debian/python-debianbts.sgml > python-debianbts.1 touch $@ clean: dh_testdir dh_testroot rm -f build-stamp configure-stamp # Add here commands to clean up after the build process. python setup.py clean dh_clean install: build dh_testdir dh_testroot dh_prep dh_installdirs # Add here commands to install the package into debian/python-debianbts. python setup.py install --install-layout=deb --root=debian/python-debianbts # Build architecture-independent files here. binary-indep: build install dh_testdir dh_testroot dh_installchangelogs dh_installdocs dh_installexamples # dh_install # dh_installmenu # dh_installdebconf # dh_installlogrotate # dh_installemacsen # dh_installpam # dh_installmime dh_pysupport # dh_python # dh_installinit # dh_installcron # dh_installinfo dh_installman dh_link dh_strip dh_compress dh_fixperms # dh_perl # dh_makeshlibs dh_installdeb dh_shlibdeps dh_gencontrol dh_md5sums dh_builddeb # Build architecture-dependent files here. binary-arch: build install binary: binary-indep binary-arch .PHONY: build clean binary-indep binary-arch binary install configure python-debianbts-1.11/debian/source/0000755000000000000000000000000011742763773014337 5ustar python-debianbts-1.11/debian/source/format0000644000000000000000000000001511742763773015546 0ustar 3.0 (native) python-debianbts-1.11/debian/copyright0000644000000000000000000000236411742763773014777 0ustar This package was debianized by Bastian Venthur on Sun, 06 Jul 2008 19:40:04 +0200. It was downloaded from Upstream Author: Bastian Venthur Copyright: Copyright (C) 2007-2008 Bastian Venthur License: This package is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This package 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this package; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA On Debian systems, the complete text of the GNU General Public License can be found in `/usr/share/common-licenses/GPL-2'. The Debian packaging is Copyright (C) 2008, Bastian Venthur and is licensed under the GPL, see above. python-debianbts-1.11/debian/docs0000644000000000000000000000000011212725613013657 0ustar