diff options
author | SVN-Git Migration <python-modules-team@lists.alioth.debian.org> | 2015-10-08 12:22:08 -0700 |
---|---|---|
committer | SVN-Git Migration <python-modules-team@lists.alioth.debian.org> | 2015-10-08 12:22:08 -0700 |
commit | 8ed2cc710534c26eccf3f1dd2496051a30160960 (patch) | |
tree | 052a6b0576d14ffba448288c1a974f9974077c38 /src | |
parent | b085813b5ad94d4e2c30702b8a8a3378b836f650 (diff) |
Imported Upstream version 1.10.3
Diffstat (limited to 'src')
-rw-r--r-- | src/launchpadlib.egg-info/PKG-INFO | 7 | ||||
-rw-r--r-- | src/launchpadlib.egg-info/SOURCES.txt | 221 | ||||
-rw-r--r-- | src/launchpadlib.egg-info/requires.txt | 3 | ||||
-rw-r--r-- | src/launchpadlib/NEWS.txt | 5 | ||||
-rw-r--r-- | src/launchpadlib/__init__.py | 2 | ||||
-rw-r--r-- | src/launchpadlib/apps.py | 7 | ||||
-rw-r--r-- | src/launchpadlib/credentials.py | 90 | ||||
-rw-r--r-- | src/launchpadlib/docs/command-line.txt | 14 | ||||
-rw-r--r-- | src/launchpadlib/launchpad.py | 26 | ||||
-rw-r--r-- | src/launchpadlib/testing/launchpad.py | 15 | ||||
-rw-r--r-- | src/launchpadlib/testing/tests/test_launchpad.py | 2 | ||||
-rw-r--r-- | src/launchpadlib/tests/test_credential_store.py | 42 | ||||
-rw-r--r-- | src/launchpadlib/tests/test_http.py | 30 | ||||
-rw-r--r-- | src/launchpadlib/tests/test_launchpad.py | 54 | ||||
-rw-r--r-- | src/launchpadlib/uris.py | 11 |
15 files changed, 204 insertions, 325 deletions
diff --git a/src/launchpadlib.egg-info/PKG-INFO b/src/launchpadlib.egg-info/PKG-INFO index a615c78..c8634b2 100644 --- a/src/launchpadlib.egg-info/PKG-INFO +++ b/src/launchpadlib.egg-info/PKG-INFO @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: launchpadlib -Version: 1.10.2 +Version: 1.10.3 Summary: Script Launchpad through its web services interfaces. Officially supported. Home-page: https://help.launchpad.net/API/launchpadlib Author: LAZR Developers @@ -31,6 +31,11 @@ Description: .. NEWS for launchpadlib ===================== + 1.10.3 (2014-12-05) + =================== + - Port to Python3. + - Detect proxies from the environment by default. + 1.10.2 (2012-07-05) =================== - Typo in the doctest fix, discovered when trying to integrate with launchpad diff --git a/src/launchpadlib.egg-info/SOURCES.txt b/src/launchpadlib.egg-info/SOURCES.txt index 25b9ba8..572e8ad 100644 --- a/src/launchpadlib.egg-info/SOURCES.txt +++ b/src/launchpadlib.egg-info/SOURCES.txt @@ -1,228 +1,7 @@ COPYING.txt HACKING.txt README.txt -ez_setup.py setup.py -eggs/docutils-0.9.1-py2.7.egg/EGG-INFO/SOURCES.txt -eggs/docutils-0.9.1-py2.7.egg/EGG-INFO/dependency_links.txt -eggs/docutils-0.9.1-py2.7.egg/EGG-INFO/top_level.txt -eggs/docutils-0.9.1-py2.7.egg/docutils/parsers/rst/include/README.txt -eggs/docutils-0.9.1-py2.7.egg/docutils/parsers/rst/include/isoamsa.txt -eggs/docutils-0.9.1-py2.7.egg/docutils/parsers/rst/include/isoamsb.txt -eggs/docutils-0.9.1-py2.7.egg/docutils/parsers/rst/include/isoamsc.txt -eggs/docutils-0.9.1-py2.7.egg/docutils/parsers/rst/include/isoamsn.txt -eggs/docutils-0.9.1-py2.7.egg/docutils/parsers/rst/include/isoamso.txt -eggs/docutils-0.9.1-py2.7.egg/docutils/parsers/rst/include/isoamsr.txt -eggs/docutils-0.9.1-py2.7.egg/docutils/parsers/rst/include/isobox.txt -eggs/docutils-0.9.1-py2.7.egg/docutils/parsers/rst/include/isocyr1.txt -eggs/docutils-0.9.1-py2.7.egg/docutils/parsers/rst/include/isocyr2.txt -eggs/docutils-0.9.1-py2.7.egg/docutils/parsers/rst/include/isodia.txt -eggs/docutils-0.9.1-py2.7.egg/docutils/parsers/rst/include/isogrk1.txt -eggs/docutils-0.9.1-py2.7.egg/docutils/parsers/rst/include/isogrk2.txt -eggs/docutils-0.9.1-py2.7.egg/docutils/parsers/rst/include/isogrk3.txt -eggs/docutils-0.9.1-py2.7.egg/docutils/parsers/rst/include/isogrk4-wide.txt -eggs/docutils-0.9.1-py2.7.egg/docutils/parsers/rst/include/isogrk4.txt -eggs/docutils-0.9.1-py2.7.egg/docutils/parsers/rst/include/isolat1.txt -eggs/docutils-0.9.1-py2.7.egg/docutils/parsers/rst/include/isolat2.txt -eggs/docutils-0.9.1-py2.7.egg/docutils/parsers/rst/include/isomfrk-wide.txt -eggs/docutils-0.9.1-py2.7.egg/docutils/parsers/rst/include/isomfrk.txt -eggs/docutils-0.9.1-py2.7.egg/docutils/parsers/rst/include/isomopf-wide.txt -eggs/docutils-0.9.1-py2.7.egg/docutils/parsers/rst/include/isomopf.txt -eggs/docutils-0.9.1-py2.7.egg/docutils/parsers/rst/include/isomscr-wide.txt -eggs/docutils-0.9.1-py2.7.egg/docutils/parsers/rst/include/isomscr.txt -eggs/docutils-0.9.1-py2.7.egg/docutils/parsers/rst/include/isonum.txt -eggs/docutils-0.9.1-py2.7.egg/docutils/parsers/rst/include/isopub.txt -eggs/docutils-0.9.1-py2.7.egg/docutils/parsers/rst/include/isotech.txt -eggs/docutils-0.9.1-py2.7.egg/docutils/parsers/rst/include/mmlalias.txt -eggs/docutils-0.9.1-py2.7.egg/docutils/parsers/rst/include/mmlextra-wide.txt -eggs/docutils-0.9.1-py2.7.egg/docutils/parsers/rst/include/mmlextra.txt -eggs/docutils-0.9.1-py2.7.egg/docutils/parsers/rst/include/s5defs.txt -eggs/docutils-0.9.1-py2.7.egg/docutils/parsers/rst/include/xhtml1-lat1.txt -eggs/docutils-0.9.1-py2.7.egg/docutils/parsers/rst/include/xhtml1-special.txt -eggs/docutils-0.9.1-py2.7.egg/docutils/parsers/rst/include/xhtml1-symbol.txt -eggs/docutils-0.9.1-py2.7.egg/docutils/writers/html4css1/template.txt -eggs/docutils-0.9.1-py2.7.egg/docutils/writers/pep_html/template.txt -eggs/docutils-0.9.1-py2.7.egg/docutils/writers/s5_html/themes/README.txt -eggs/httplib2-0.7.4-py2.7.egg/EGG-INFO/SOURCES.txt -eggs/httplib2-0.7.4-py2.7.egg/EGG-INFO/dependency_links.txt -eggs/httplib2-0.7.4-py2.7.egg/EGG-INFO/top_level.txt -eggs/httplib2-0.7.4-py2.7.egg/httplib2/cacerts.txt -eggs/keyring-0.9.2-py2.7.egg/EGG-INFO/SOURCES.txt -eggs/keyring-0.9.2-py2.7.egg/EGG-INFO/dependency_links.txt -eggs/keyring-0.9.2-py2.7.egg/EGG-INFO/requires.txt -eggs/keyring-0.9.2-py2.7.egg/EGG-INFO/top_level.txt -eggs/lazr.authentication-0.1.2-py2.7.egg/EGG-INFO/SOURCES.txt -eggs/lazr.authentication-0.1.2-py2.7.egg/EGG-INFO/dependency_links.txt -eggs/lazr.authentication-0.1.2-py2.7.egg/EGG-INFO/namespace_packages.txt -eggs/lazr.authentication-0.1.2-py2.7.egg/EGG-INFO/requires.txt -eggs/lazr.authentication-0.1.2-py2.7.egg/EGG-INFO/top_level.txt -eggs/lazr.authentication-0.1.2-py2.7.egg/lazr/authentication/NEWS.txt -eggs/lazr.authentication-0.1.2-py2.7.egg/lazr/authentication/README.txt -eggs/lazr.authentication-0.1.2-py2.7.egg/lazr/authentication/version.txt -eggs/lazr.restfulclient-0.13.0-py2.7.egg/EGG-INFO/SOURCES.txt -eggs/lazr.restfulclient-0.13.0-py2.7.egg/EGG-INFO/dependency_links.txt -eggs/lazr.restfulclient-0.13.0-py2.7.egg/EGG-INFO/namespace_packages.txt -eggs/lazr.restfulclient-0.13.0-py2.7.egg/EGG-INFO/requires.txt -eggs/lazr.restfulclient-0.13.0-py2.7.egg/EGG-INFO/top_level.txt -eggs/lazr.restfulclient-0.13.0-py2.7.egg/lazr/restfulclient/NEWS.txt -eggs/lazr.restfulclient-0.13.0-py2.7.egg/lazr/restfulclient/README.txt -eggs/lazr.restfulclient-0.13.0-py2.7.egg/lazr/restfulclient/version.txt -eggs/lazr.restfulclient-0.13.0-py2.7.egg/lazr/restfulclient/docs/authorizer.standalone.txt -eggs/lazr.restfulclient-0.13.0-py2.7.egg/lazr/restfulclient/docs/caching.txt -eggs/lazr.restfulclient-0.13.0-py2.7.egg/lazr/restfulclient/docs/collections.txt -eggs/lazr.restfulclient-0.13.0-py2.7.egg/lazr/restfulclient/docs/entries.txt -eggs/lazr.restfulclient-0.13.0-py2.7.egg/lazr/restfulclient/docs/hosted-files.txt -eggs/lazr.restfulclient-0.13.0-py2.7.egg/lazr/restfulclient/docs/operations.txt -eggs/lazr.restfulclient-0.13.0-py2.7.egg/lazr/restfulclient/docs/retry.standalone.txt -eggs/lazr.restfulclient-0.13.0-py2.7.egg/lazr/restfulclient/docs/toplevel.txt -eggs/lazr.uri-1.0.3-py2.7.egg/EGG-INFO/SOURCES.txt -eggs/lazr.uri-1.0.3-py2.7.egg/EGG-INFO/dependency_links.txt -eggs/lazr.uri-1.0.3-py2.7.egg/EGG-INFO/namespace_packages.txt -eggs/lazr.uri-1.0.3-py2.7.egg/EGG-INFO/requires.txt -eggs/lazr.uri-1.0.3-py2.7.egg/EGG-INFO/top_level.txt -eggs/lazr.uri-1.0.3-py2.7.egg/lazr/uri/NEWS.txt -eggs/lazr.uri-1.0.3-py2.7.egg/lazr/uri/README.txt -eggs/lazr.uri-1.0.3-py2.7.egg/lazr/uri/version.txt -eggs/oauth-1.0.1-py2.7.egg/EGG-INFO/SOURCES.txt -eggs/oauth-1.0.1-py2.7.egg/EGG-INFO/dependency_links.txt -eggs/oauth-1.0.1-py2.7.egg/EGG-INFO/top_level.txt -eggs/setuptools-0.6c12dev_r88846-py2.7.egg/EGG-INFO/SOURCES.txt -eggs/setuptools-0.6c12dev_r88846-py2.7.egg/EGG-INFO/dependency_links.txt -eggs/setuptools-0.6c12dev_r88846-py2.7.egg/EGG-INFO/entry_points.txt -eggs/setuptools-0.6c12dev_r88846-py2.7.egg/EGG-INFO/top_level.txt -eggs/simplejson-2.6.0-py2.7-linux-i686.egg/EGG-INFO/SOURCES.txt -eggs/simplejson-2.6.0-py2.7-linux-i686.egg/EGG-INFO/dependency_links.txt -eggs/simplejson-2.6.0-py2.7-linux-i686.egg/EGG-INFO/native_libs.txt -eggs/simplejson-2.6.0-py2.7-linux-i686.egg/EGG-INFO/top_level.txt -eggs/testresources-0.2.5-py2.7.egg/EGG-INFO/SOURCES.txt -eggs/testresources-0.2.5-py2.7.egg/EGG-INFO/dependency_links.txt -eggs/testresources-0.2.5-py2.7.egg/EGG-INFO/top_level.txt -eggs/wadllib-1.3.1-py2.7.egg/EGG-INFO/SOURCES.txt -eggs/wadllib-1.3.1-py2.7.egg/EGG-INFO/dependency_links.txt -eggs/wadllib-1.3.1-py2.7.egg/EGG-INFO/requires.txt -eggs/wadllib-1.3.1-py2.7.egg/EGG-INFO/top_level.txt -eggs/wadllib-1.3.1-py2.7.egg/wadllib/NEWS.txt -eggs/wadllib-1.3.1-py2.7.egg/wadllib/README.txt -eggs/wadllib-1.3.1-py2.7.egg/wadllib/version.txt -eggs/wsgi_intercept-0.5.1-py2.7.egg/EGG-INFO/SOURCES.txt -eggs/wsgi_intercept-0.5.1-py2.7.egg/EGG-INFO/dependency_links.txt -eggs/wsgi_intercept-0.5.1-py2.7.egg/EGG-INFO/top_level.txt -eggs/z3c.recipe.scripts-1.0.1-py2.7.egg/EGG-INFO/SOURCES.txt -eggs/z3c.recipe.scripts-1.0.1-py2.7.egg/EGG-INFO/dependency_links.txt -eggs/z3c.recipe.scripts-1.0.1-py2.7.egg/EGG-INFO/entry_points.txt -eggs/z3c.recipe.scripts-1.0.1-py2.7.egg/EGG-INFO/namespace_packages.txt -eggs/z3c.recipe.scripts-1.0.1-py2.7.egg/EGG-INFO/requires.txt -eggs/z3c.recipe.scripts-1.0.1-py2.7.egg/EGG-INFO/top_level.txt -eggs/z3c.recipe.scripts-1.0.1-py2.7.egg/z3c/recipe/scripts/README.txt -eggs/z3c.recipe.tag-0.4.1-py2.7.egg/EGG-INFO/SOURCES.txt -eggs/z3c.recipe.tag-0.4.1-py2.7.egg/EGG-INFO/dependency_links.txt -eggs/z3c.recipe.tag-0.4.1-py2.7.egg/EGG-INFO/entry_points.txt -eggs/z3c.recipe.tag-0.4.1-py2.7.egg/EGG-INFO/namespace_packages.txt -eggs/z3c.recipe.tag-0.4.1-py2.7.egg/EGG-INFO/requires.txt -eggs/z3c.recipe.tag-0.4.1-py2.7.egg/EGG-INFO/top_level.txt -eggs/zc.buildout-1.5.2-py2.7.egg/README.txt -eggs/zc.buildout-1.5.2-py2.7.egg/EGG-INFO/SOURCES.txt -eggs/zc.buildout-1.5.2-py2.7.egg/EGG-INFO/dependency_links.txt -eggs/zc.buildout-1.5.2-py2.7.egg/EGG-INFO/entry_points.txt -eggs/zc.buildout-1.5.2-py2.7.egg/EGG-INFO/namespace_packages.txt -eggs/zc.buildout-1.5.2-py2.7.egg/EGG-INFO/requires.txt -eggs/zc.buildout-1.5.2-py2.7.egg/EGG-INFO/top_level.txt -eggs/zc.buildout-1.5.2-py2.7.egg/zc/buildout/allowhosts.txt -eggs/zc.buildout-1.5.2-py2.7.egg/zc/buildout/bootstrap.txt -eggs/zc.buildout-1.5.2-py2.7.egg/zc/buildout/buildout.txt -eggs/zc.buildout-1.5.2-py2.7.egg/zc/buildout/debugging.txt -eggs/zc.buildout-1.5.2-py2.7.egg/zc/buildout/dependencylinks.txt -eggs/zc.buildout-1.5.2-py2.7.egg/zc/buildout/distribute.txt -eggs/zc.buildout-1.5.2-py2.7.egg/zc/buildout/download.txt -eggs/zc.buildout-1.5.2-py2.7.egg/zc/buildout/downloadcache.txt -eggs/zc.buildout-1.5.2-py2.7.egg/zc/buildout/easy_install.txt -eggs/zc.buildout-1.5.2-py2.7.egg/zc/buildout/extends-cache.txt -eggs/zc.buildout-1.5.2-py2.7.egg/zc/buildout/repeatable.txt -eggs/zc.buildout-1.5.2-py2.7.egg/zc/buildout/runsetup.txt -eggs/zc.buildout-1.5.2-py2.7.egg/zc/buildout/setup.txt -eggs/zc.buildout-1.5.2-py2.7.egg/zc/buildout/testing.txt -eggs/zc.buildout-1.5.2-py2.7.egg/zc/buildout/testing_bugfix.txt -eggs/zc.buildout-1.5.2-py2.7.egg/zc/buildout/unzip.txt -eggs/zc.buildout-1.5.2-py2.7.egg/zc/buildout/update.txt -eggs/zc.buildout-1.5.2-py2.7.egg/zc/buildout/upgrading_distribute.txt -eggs/zc.buildout-1.5.2-py2.7.egg/zc/buildout/virtualenv.txt -eggs/zc.buildout-1.5.2-py2.7.egg/zc/buildout/windows.txt -eggs/zc.recipe.egg-1.3.2-py2.7.egg/EGG-INFO/SOURCES.txt -eggs/zc.recipe.egg-1.3.2-py2.7.egg/EGG-INFO/dependency_links.txt -eggs/zc.recipe.egg-1.3.2-py2.7.egg/EGG-INFO/entry_points.txt -eggs/zc.recipe.egg-1.3.2-py2.7.egg/EGG-INFO/namespace_packages.txt -eggs/zc.recipe.egg-1.3.2-py2.7.egg/EGG-INFO/requires.txt -eggs/zc.recipe.egg-1.3.2-py2.7.egg/EGG-INFO/top_level.txt -eggs/zc.recipe.egg-1.3.2-py2.7.egg/zc/recipe/egg/README.txt -eggs/zc.recipe.egg-1.3.2-py2.7.egg/zc/recipe/egg/api.txt -eggs/zc.recipe.egg-1.3.2-py2.7.egg/zc/recipe/egg/custom.txt -eggs/zc.recipe.egg-1.3.2-py2.7.egg/zc/recipe/egg/selecting-python.txt -eggs/zc.recipe.testrunner-1.4.0-py2.7.egg/EGG-INFO/SOURCES.txt -eggs/zc.recipe.testrunner-1.4.0-py2.7.egg/EGG-INFO/dependency_links.txt -eggs/zc.recipe.testrunner-1.4.0-py2.7.egg/EGG-INFO/entry_points.txt -eggs/zc.recipe.testrunner-1.4.0-py2.7.egg/EGG-INFO/namespace_packages.txt -eggs/zc.recipe.testrunner-1.4.0-py2.7.egg/EGG-INFO/requires.txt -eggs/zc.recipe.testrunner-1.4.0-py2.7.egg/EGG-INFO/top_level.txt -eggs/zc.recipe.testrunner-1.4.0-py2.7.egg/zc/recipe/testrunner/README.txt -eggs/zc.recipe.testrunner-1.4.0-py2.7.egg/zc/recipe/testrunner/bugfixes.txt -eggs/zope.exceptions-4.0.0.1-py2.7.egg/EGG-INFO/SOURCES.txt -eggs/zope.exceptions-4.0.0.1-py2.7.egg/EGG-INFO/dependency_links.txt -eggs/zope.exceptions-4.0.0.1-py2.7.egg/EGG-INFO/namespace_packages.txt -eggs/zope.exceptions-4.0.0.1-py2.7.egg/EGG-INFO/requires.txt -eggs/zope.exceptions-4.0.0.1-py2.7.egg/EGG-INFO/top_level.txt -eggs/zope.interface-4.0.1-py2.7-linux-i686.egg/EGG-INFO/SOURCES.txt -eggs/zope.interface-4.0.1-py2.7-linux-i686.egg/EGG-INFO/dependency_links.txt -eggs/zope.interface-4.0.1-py2.7-linux-i686.egg/EGG-INFO/namespace_packages.txt -eggs/zope.interface-4.0.1-py2.7-linux-i686.egg/EGG-INFO/native_libs.txt -eggs/zope.interface-4.0.1-py2.7-linux-i686.egg/EGG-INFO/requires.txt -eggs/zope.interface-4.0.1-py2.7-linux-i686.egg/EGG-INFO/top_level.txt -eggs/zope.testrunner-4.0.4-py2.7.egg/EGG-INFO/SOURCES.txt -eggs/zope.testrunner-4.0.4-py2.7.egg/EGG-INFO/dependency_links.txt -eggs/zope.testrunner-4.0.4-py2.7.egg/EGG-INFO/entry_points.txt -eggs/zope.testrunner-4.0.4-py2.7.egg/EGG-INFO/namespace_packages.txt -eggs/zope.testrunner-4.0.4-py2.7.egg/EGG-INFO/requires.txt -eggs/zope.testrunner-4.0.4-py2.7.egg/EGG-INFO/top_level.txt -eggs/zope.testrunner-4.0.4-py2.7.egg/zope/testrunner/testrunner-arguments.txt -eggs/zope.testrunner-4.0.4-py2.7.egg/zope/testrunner/testrunner-colors.txt -eggs/zope.testrunner-4.0.4-py2.7.egg/zope/testrunner/testrunner-coverage-win32.txt -eggs/zope.testrunner-4.0.4-py2.7.egg/zope/testrunner/testrunner-coverage.txt -eggs/zope.testrunner-4.0.4-py2.7.egg/zope/testrunner/testrunner-debugging.txt -eggs/zope.testrunner-4.0.4-py2.7.egg/zope/testrunner/testrunner-discovery.txt -eggs/zope.testrunner-4.0.4-py2.7.egg/zope/testrunner/testrunner-edge-cases.txt -eggs/zope.testrunner-4.0.4-py2.7.egg/zope/testrunner/testrunner-errors.txt -eggs/zope.testrunner-4.0.4-py2.7.egg/zope/testrunner/testrunner-gc.txt -eggs/zope.testrunner-4.0.4-py2.7.egg/zope/testrunner/testrunner-knit.txt -eggs/zope.testrunner-4.0.4-py2.7.egg/zope/testrunner/testrunner-layers-api.txt -eggs/zope.testrunner-4.0.4-py2.7.egg/zope/testrunner/testrunner-layers-buff.txt -eggs/zope.testrunner-4.0.4-py2.7.egg/zope/testrunner/testrunner-layers-ntd.txt -eggs/zope.testrunner-4.0.4-py2.7.egg/zope/testrunner/testrunner-layers.txt -eggs/zope.testrunner-4.0.4-py2.7.egg/zope/testrunner/testrunner-leaks-err.txt -eggs/zope.testrunner-4.0.4-py2.7.egg/zope/testrunner/testrunner-leaks.txt -eggs/zope.testrunner-4.0.4-py2.7.egg/zope/testrunner/testrunner-profiling-cprofiler.txt -eggs/zope.testrunner-4.0.4-py2.7.egg/zope/testrunner/testrunner-profiling.txt -eggs/zope.testrunner-4.0.4-py2.7.egg/zope/testrunner/testrunner-progress.txt -eggs/zope.testrunner-4.0.4-py2.7.egg/zope/testrunner/testrunner-repeat.txt -eggs/zope.testrunner-4.0.4-py2.7.egg/zope/testrunner/testrunner-shuffle.txt -eggs/zope.testrunner-4.0.4-py2.7.egg/zope/testrunner/testrunner-simple.txt -eggs/zope.testrunner-4.0.4-py2.7.egg/zope/testrunner/testrunner-subunit-err.txt -eggs/zope.testrunner-4.0.4-py2.7.egg/zope/testrunner/testrunner-subunit-leaks.txt -eggs/zope.testrunner-4.0.4-py2.7.egg/zope/testrunner/testrunner-subunit.txt -eggs/zope.testrunner-4.0.4-py2.7.egg/zope/testrunner/testrunner-tb-format.txt -eggs/zope.testrunner-4.0.4-py2.7.egg/zope/testrunner/testrunner-test-selection.txt -eggs/zope.testrunner-4.0.4-py2.7.egg/zope/testrunner/testrunner-unexpected-success.txt -eggs/zope.testrunner-4.0.4-py2.7.egg/zope/testrunner/testrunner-verbose.txt -eggs/zope.testrunner-4.0.4-py2.7.egg/zope/testrunner/testrunner-wo-source.txt -eggs/zope.testrunner-4.0.4-py2.7.egg/zope/testrunner/testrunner.txt -eggs/zope.testrunner-4.0.4-py2.7.egg/zope/testrunner/testrunner-ex/README.txt -eggs/zope.testrunner-4.0.4-py2.7.egg/zope/testrunner/testrunner-ex/sampletests.txt -eggs/zope.testrunner-4.0.4-py2.7.egg/zope/testrunner/testrunner-ex/sampletestsl.txt -eggs/zope.testrunner-4.0.4-py2.7.egg/zope/testrunner/testrunner-ex/sample2/e.txt -eggs/zope.testrunner-4.0.4-py2.7.egg/zope/testrunner/testrunner-ex/sample3/post_mortem5.txt -eggs/zope.testrunner-4.0.4-py2.7.egg/zope/testrunner/testrunner-ex/sample3/post_mortem6.txt -eggs/zope.testrunner-4.0.4-py2.7.egg/zope/testrunner/testrunner-ex/sample3/post_mortem_failure.txt -eggs/zope.testrunner-4.0.4-py2.7.egg/zope/testrunner/testrunner-ex/sample3/set_trace5.txt -eggs/zope.testrunner-4.0.4-py2.7.egg/zope/testrunner/testrunner-ex/sample3/set_trace6.txt -eggs/zope.testrunner-4.0.4-py2.7.egg/zope/testrunner/testrunner-ex/usecompiled/README.txt src/launchpadlib/NEWS.txt src/launchpadlib/README.txt src/launchpadlib/__init__.py diff --git a/src/launchpadlib.egg-info/requires.txt b/src/launchpadlib.egg-info/requires.txt index 312b7e8..aeb2b64 100644 --- a/src/launchpadlib.egg-info/requires.txt +++ b/src/launchpadlib.egg-info/requires.txt @@ -4,6 +4,5 @@ lazr.restfulclient>=0.9.19 lazr.uri oauth setuptools -simplejson testresources -wadllib
\ No newline at end of file +wadllib diff --git a/src/launchpadlib/NEWS.txt b/src/launchpadlib/NEWS.txt index 7638735..946d7d0 100644 --- a/src/launchpadlib/NEWS.txt +++ b/src/launchpadlib/NEWS.txt @@ -2,6 +2,11 @@ NEWS for launchpadlib ===================== +1.10.3 (2014-12-05) +=================== +- Port to Python3. +- Detect proxies from the environment by default. + 1.10.2 (2012-07-05) =================== - Typo in the doctest fix, discovered when trying to integrate with launchpad diff --git a/src/launchpadlib/__init__.py b/src/launchpadlib/__init__.py index 39b2de0..b5315ba 100644 --- a/src/launchpadlib/__init__.py +++ b/src/launchpadlib/__init__.py @@ -14,4 +14,4 @@ # You should have received a copy of the GNU Lesser General Public License # along with launchpadlib. If not, see <http://www.gnu.org/licenses/>. -__version__ = '1.10.2' +__version__ = '1.10.3' diff --git a/src/launchpadlib/apps.py b/src/launchpadlib/apps.py index 4e42bf6..ae87139 100644 --- a/src/launchpadlib/apps.py +++ b/src/launchpadlib/apps.py @@ -28,7 +28,10 @@ __all__ = [ import getpass import sys -import simplejson +try: + import json +except ImportError: + import simplejson as json from launchpadlib.credentials import ( Credentials, RequestTokenAuthorizationEngine, TokenAuthorizationException) @@ -49,6 +52,6 @@ class RequestTokenApp(object): token = self.credentials.get_request_token( self.context, self.web_root, token_format=Credentials.DICT_TOKEN_FORMAT) - return simplejson.dumps(token) + return json.dumps(token) diff --git a/src/launchpadlib/credentials.py b/src/launchpadlib/credentials.py index d43bc7d..aff7569 100644 --- a/src/launchpadlib/credentials.py +++ b/src/launchpadlib/credentials.py @@ -14,6 +14,8 @@ # You should have received a copy of the GNU Lesser General Public License # along with launchpadlib. If not, see <http://www.gnu.org/licenses/>. +from __future__ import print_function + """launchpadlib credentials and authentication support.""" __metaclass__ = type @@ -28,21 +30,44 @@ __all__ = [ ] import cgi -from cStringIO import StringIO +try: + from cStringIO import StringIO +except ImportError: + from io import StringIO + import httplib2 import os +from select import select import stat +from sys import stdin import time -from urllib import urlencode -from urlparse import urljoin +try: + from urllib.parse import urlencode +except ImportError: + from urllib import urlencode +try: + from urllib.parse import urljoin +except ImportError: + from urlparse import urljoin import webbrowser from base64 import ( b64decode, b64encode, ) -import simplejson - +try: + import json +except ImportError: + import simplejson as json + +if bytes is str: + # Python 2 + unicode_type = unicode + binary_type = str +else: + unicode_type = str + binary_type = bytes + from lazr.restfulclient.errors import HTTPError from lazr.restfulclient.authorize.oauth import ( AccessToken as _AccessToken, @@ -113,6 +138,8 @@ class Credentials(OAuthAuthorizer): sio = StringIO() self.save(sio) serialized = sio.getvalue() + if isinstance(serialized, unicode_type): + serialized = serialized.encode('utf-8') return serialized @classmethod @@ -122,6 +149,8 @@ class Credentials(OAuthAuthorizer): This should probably be moved into OAuthAuthorizer. """ credentials = cls() + if not isinstance(value, unicode_type): + value = value.decode('utf-8') credentials.load(StringIO(value)) return credentials @@ -161,8 +190,10 @@ class Credentials(OAuthAuthorizer): if token_format == self.DICT_TOKEN_FORMAT: headers['Accept'] = 'application/json' response, content = _http_post(url, headers, params) + if isinstance(content, binary_type): + content = content.decode('utf-8') if token_format == self.DICT_TOKEN_FORMAT: - params = simplejson.loads(content) + params = json.loads(content) if context is not None: params["lp.context"] = context self._request_token = AccessToken.from_params(params) @@ -269,7 +300,7 @@ class CredentialStore(object): self.do_save(credentials, unique_consumer_id) except EXPLOSIVE_ERRORS: raise - except Exception, e: + except Exception as e: if self.credential_save_failed is None: raise e self.credential_save_failed() @@ -324,7 +355,7 @@ class KeyringCredentialStore(CredentialStore): integrating third-party websites into Launchpad. """ - B64MARKER = "<B64>" + B64MARKER = b"<B64>" @staticmethod def _ensure_keyring_imported(): @@ -356,7 +387,8 @@ class KeyringCredentialStore(CredentialStore): credential_string = keyring.get_password( 'launchpadlib', unique_key) if credential_string is not None: - credential_string = credential_string.encode('utf8') + if isinstance(credential_string, unicode_type): + credential_string = credential_string.encode('utf8') if credential_string.startswith(self.B64MARKER): try: credential_string = b64decode( @@ -553,7 +585,17 @@ class AuthorizeRequestTokenWithBrowser(RequestTokenAuthorizationEngine): themselves. """ - WAITING_FOR_USER = "The authorization page:\n (%s)\nshould be opening in your browser. Use your browser to authorize\nthis program to access Launchpad on your behalf. \n\nWaiting to hear from Launchpad about your decision..." + WAITING_FOR_USER = ( + "The authorization page:\n" + " (%s)\n" + "should be opening in your browser. Use your browser to authorize\n" + "this program to access Launchpad on your behalf.") + TIMEOUT_MESSAGE = "Press Enter to continue or wait (%d) seconds..." + TIMEOUT = 5 + WAITING_FOR_LAUNCHPAD = ( + "Waiting to hear from Launchpad about your decision...") + TERMINAL_BROWSERS = ('www-browser', 'links', 'links2', 'lynx', + 'elinks', 'elinks-lite', 'netrik', 'w3m') def __init__(self, service_root, application_name, consumer_name=None, credential_save_failed=None, allow_access_levels=None): @@ -583,21 +625,39 @@ class AuthorizeRequestTokenWithBrowser(RequestTokenAuthorizationEngine): does not require any user interaction--it's solely informative. """ - print message + print(message) def make_end_user_authorize_token(self, credentials, request_token): """Have the end-user authorize the token in their browser.""" authorization_url = self.authorization_url(request_token) - webbrowser.open(authorization_url) self.output(self.WAITING_FOR_USER % authorization_url) + + try: + browser = webbrowser.get().basename + console_browser = browser in self.TERMINAL_BROWSERS + except webbrowser.Error: + browser = None + console_browser = False + + if console_browser: + self.output(self.TIMEOUT_MESSAGE % self.TIMEOUT) + # Wait a little time before attempting to launch browser, + # give users the chance to press a key to skip it anyway. + rlist, _, _ = select([stdin], [], [], self.TIMEOUT) + if rlist: + stdin.readline() + + self.output(self.WAITING_FOR_LAUNCHPAD) + if browser is not None: + webbrowser.open(authorization_url) while credentials.access_token is None: time.sleep(access_token_poll_time) try: credentials.exchange_request_token_for_access_token( self.web_root) break - except HTTPError, e: + except HTTPError as e: if e.response.status == 403: # The user decided not to authorize this # application. @@ -607,8 +667,8 @@ class AuthorizeRequestTokenWithBrowser(RequestTokenAuthorizationEngine): pass else: # There was an error accessing the server. - print "Unexpected response from Launchpad:" - print e + print("Unexpected response from Launchpad:") + print(e) class TokenAuthorizationException(Exception): diff --git a/src/launchpadlib/docs/command-line.txt b/src/launchpadlib/docs/command-line.txt index 433ff20..5027845 100644 --- a/src/launchpadlib/docs/command-line.txt +++ b/src/launchpadlib/docs/command-line.txt @@ -17,21 +17,23 @@ launchpad-request-token. It creates a request token on a given Launchpad installation, and returns a JSON description of the request token and the available access levels. - >>> import simplejson + >>> try: + ... import json + ... except ImportError: + ... import simplejson as json >>> from launchpadlib.apps import RequestTokenApp >>> web_root = "http://launchpad.dev:8085/" >>> consumer_name = "consumer" >>> token_app = RequestTokenApp(web_root, consumer_name, "context") - >>> json = simplejson.loads(token_app.run()) + >>> token_json = json.loads(token_app.run()) - >>> sorted(json.keys()) + >>> sorted(token_json.keys()) ['access_levels', 'lp.context', 'oauth_token', 'oauth_token_consumer', 'oauth_token_secret'] - >>> print json['lp.context'] + >>> print token_json['lp.context'] context - >>> print json['oauth_token_consumer'] + >>> print token_json['oauth_token_consumer'] consumer - diff --git a/src/launchpadlib/launchpad.py b/src/launchpadlib/launchpad.py index e42d4fc..337e015 100644 --- a/src/launchpadlib/launchpad.py +++ b/src/launchpadlib/launchpad.py @@ -22,9 +22,14 @@ __all__ = [ ] import os -import urlparse +try: + from urllib.parse import urlsplit +except: + from urlparse import urlsplit import warnings +from httplib2 import proxy_info_from_environment + from lazr.restfulclient.resource import ( CollectionWithKeyBasedLookup, HostedFile, # Re-import for client convenience @@ -162,7 +167,7 @@ class Launchpad(ServiceRoot): def __init__(self, credentials, authorization_engine, credential_store, service_root=uris.STAGING_SERVICE_ROOT, - cache=None, timeout=None, proxy_info=None, + cache=None, timeout=None, proxy_info=proxy_info_from_environment, version=DEFAULT_VERSION): """Root access to the Launchpad API. @@ -213,7 +218,7 @@ class Launchpad(ServiceRoot): @classmethod def login(cls, consumer_name, token_string, access_secret, service_root=uris.STAGING_SERVICE_ROOT, - cache=None, timeout=None, proxy_info=None, + cache=None, timeout=None, proxy_info=proxy_info_from_environment, authorization_engine=None, allow_access_levels=None, max_failed_attempts=None, credential_store=None, credential_save_failed=None, version=DEFAULT_VERSION): @@ -265,7 +270,7 @@ class Launchpad(ServiceRoot): @classmethod def get_token_and_login(cls, consumer_name, service_root=uris.STAGING_SERVICE_ROOT, - cache=None, timeout=None, proxy_info=None, + cache=None, timeout=None, proxy_info=proxy_info_from_environment, authorization_engine=None, allow_access_levels=[], max_failed_attempts=None, credential_store=None, credential_save_failed=None, @@ -361,7 +366,7 @@ class Launchpad(ServiceRoot): @classmethod def login_anonymously( cls, consumer_name, service_root=uris.STAGING_SERVICE_ROOT, - launchpadlib_dir=None, timeout=None, proxy_info=None, + launchpadlib_dir=None, timeout=None, proxy_info=proxy_info_from_environment, version=DEFAULT_VERSION): """Get access to Launchpad without providing any credentials.""" (service_root, launchpadlib_dir, cache_path, @@ -375,7 +380,7 @@ class Launchpad(ServiceRoot): @classmethod def login_with(cls, application_name=None, service_root=uris.STAGING_SERVICE_ROOT, - launchpadlib_dir=None, timeout=None, proxy_info=None, + launchpadlib_dir=None, timeout=None, proxy_info=proxy_info_from_environment, authorization_engine=None, allow_access_levels=None, max_failed_attempts=None, credentials_file=None, version=DEFAULT_VERSION, consumer_name=None, @@ -596,15 +601,14 @@ class Launchpad(ServiceRoot): raise ValueError("Must set $HOME or pass 'launchpadlib_dir' to " "indicate location to store cached data") if not os.path.exists(launchpadlib_dir): - os.makedirs(launchpadlib_dir, 0700) - os.chmod(launchpadlib_dir, 0700) + os.makedirs(launchpadlib_dir, 0o700) + os.chmod(launchpadlib_dir, 0o700) # Determine the real service root. service_root = uris.lookup_service_root(service_root) # Each service root has its own cache and credential dirs. - scheme, host_name, path, query, fragment = urlparse.urlsplit( - service_root) + scheme, host_name, path, query, fragment = urlsplit(service_root) service_root_dir = os.path.join(launchpadlib_dir, host_name) cache_path = os.path.join(service_root_dir, 'cache') if not os.path.exists(cache_path): - os.makedirs(cache_path, 0700) + os.makedirs(cache_path, 0o700) return (service_root, launchpadlib_dir, cache_path, service_root_dir) diff --git a/src/launchpadlib/testing/launchpad.py b/src/launchpadlib/testing/launchpad.py index 0da882b..711fb96 100644 --- a/src/launchpadlib/testing/launchpad.py +++ b/src/launchpadlib/testing/launchpad.py @@ -66,7 +66,10 @@ also in the WADL file itelf. """ from datetime import datetime - +import collections +import sys +if sys.version_info[0] >= 3: + basestring = str JSON_MEDIA_TYPE = "application/json" @@ -202,7 +205,7 @@ class FakeResource(object): result = self._children.get(name, _marker) if result is _marker: result = self._values.get(name, _marker) - if callable(result): + if isinstance(result, collections.Callable): return self._wrap_method(name, result) if name in self.special_methods: return lambda: True @@ -276,8 +279,8 @@ class FakeResource(object): @param partial_object: A dict with key/value pairs representing attributes and methods. """ - for name, value in partial_object.iteritems(): - if callable(value): + for name, value in partial_object.items(): + if isinstance(value, collections.Callable): # Performs an integrity check. self._get_method(resource_type, name) else: @@ -299,11 +302,11 @@ class FakeResource(object): """ name = None child_resource_type = None - for name, value in partial_object.iteritems(): + for name, value in partial_object.items(): if name == "entries": name, child_resource_type = ( self._check_entries(resource_type, value)) - elif callable(value): + elif isinstance(value, collections.Callable): # Performs an integrity check. self._get_method(resource_type, name) else: diff --git a/src/launchpadlib/testing/tests/test_launchpad.py b/src/launchpadlib/testing/tests/test_launchpad.py index 1b6591c..387751b 100644 --- a/src/launchpadlib/testing/tests/test_launchpad.py +++ b/src/launchpadlib/testing/tests/test_launchpad.py @@ -109,7 +109,7 @@ class FakeLaunchpadTest(ResourcedTestCase): A L{FakeLaunchpad} instantiated without credentials has its C{credentials} attribute set to C{None}. """ - self.assertEqual(None, self.launchpad.credentials) + self.assertIsNone(self.launchpad.credentials) def test_set_undefined_property(self): """ diff --git a/src/launchpadlib/tests/test_credential_store.py b/src/launchpadlib/tests/test_credential_store.py index d764267..a48c0a2 100644 --- a/src/launchpadlib/tests/test_credential_store.py +++ b/src/launchpadlib/tests/test_credential_store.py @@ -22,6 +22,12 @@ import unittest from base64 import b64decode +if bytes is str: + # Python 2 + unicode_type = unicode +else: + unicode_type = str + from launchpadlib.testing.helpers import ( fake_keyring, InMemoryKeyring, @@ -60,7 +66,7 @@ class TestUnencryptedFileCredentialStore(CredentialStoreTestCase): credential = self.make_credential("consumer key") self.store.save(credential, "unique key") credential2 = self.store.load("unique key") - self.assertEquals(credential.consumer.key, credential2.consumer.key) + self.assertEqual(credential.consumer.key, credential2.consumer.key) def test_unique_id_doesnt_matter(self): # If a file contains a credential, that credential will be @@ -68,7 +74,7 @@ class TestUnencryptedFileCredentialStore(CredentialStoreTestCase): credential = self.make_credential("consumer key") self.store.save(credential, "some key") credential2 = self.store.load("some other key") - self.assertEquals(credential.consumer.key, credential2.consumer.key) + self.assertEqual(credential.consumer.key, credential2.consumer.key) def test_file_only_contains_one_credential(self): # A credential file may contain only one credential. If you @@ -80,7 +86,7 @@ class TestUnencryptedFileCredentialStore(CredentialStoreTestCase): self.store.save(credential1, "unique key 1") self.store.save(credential1, "unique key 2") loaded = self.store.load("unique key 1") - self.assertEquals(loaded.consumer.key, credential2.consumer.key) + self.assertEqual(loaded.consumer.key, credential2.consumer.key) class TestKeyringCredentialStore(CredentialStoreTestCase): @@ -96,7 +102,7 @@ class TestKeyringCredentialStore(CredentialStoreTestCase): credential = self.make_credential("consumer key") self.store.save(credential, "unique key") credential2 = self.store.load("unique key") - self.assertEquals( + self.assertEqual( credential.consumer.key, credential2.consumer.key) def test_lookup_by_unique_key(self): @@ -110,11 +116,12 @@ class TestKeyringCredentialStore(CredentialStoreTestCase): self.store.save(credential2, "key 2") loaded1 = self.store.load("key 1") - self.assertEquals( + self.assertTrue(loaded1) + self.assertEqual( credential1.consumer.key, loaded1.consumer.key) loaded2 = self.store.load("key 2") - self.assertEquals( + self.assertEqual( credential2.consumer.key, loaded2.consumer.key) def test_reused_unique_id_overwrites_old_credential(self): @@ -129,14 +136,14 @@ class TestKeyringCredentialStore(CredentialStoreTestCase): self.store.save(credential2, "the only key") loaded = self.store.load("the only key") - self.assertEquals( + self.assertEqual( credential2.consumer.key, loaded.consumer.key) def test_bad_unique_id_returns_none(self): # Trying to load a credential without providing a good unique # ID will get you None. with fake_keyring(self.keyring): - self.assertEquals(None, self.store.load("no such key")) + self.assertIsNone(self.store.load("no such key")) def test_keyring_returns_unicode(self): # Kwallet is reported to sometimes return Unicode, which broke the @@ -144,18 +151,23 @@ class TestKeyringCredentialStore(CredentialStoreTestCase): # handled correctly. (See bug lp:877374) class UnicodeInMemoryKeyring(InMemoryKeyring): def get_password(self, service, username): - return unicode( - super(UnicodeInMemoryKeyring, self).get_password( - service, username)) + password = super(UnicodeInMemoryKeyring, self).get_password( + service, username) + if isinstance(password, unicode_type): + password = password.encode('utf-8') + return password self.keyring = UnicodeInMemoryKeyring() with fake_keyring(self.keyring): credential = self.make_credential("consumer key") + self.assertTrue(credential) + # Shouldn't this test actually use a unicodish key?! self.store.save(credential, "unique key") credential2 = self.store.load("unique key") - self.assertEquals( + self.assertTrue(credential2) + self.assertEqual( credential.consumer.key, credential2.consumer.key) - self.assertEquals( + self.assertEqual( credential.consumer.secret, credential2.consumer.secret) def test_nonencoded_key_handled(self): @@ -172,9 +184,9 @@ class TestKeyringCredentialStore(CredentialStoreTestCase): credential = self.make_credential("consumer key") self.store.save(credential, "unique key") credential2 = self.store.load("unique key") - self.assertEquals( + self.assertEqual( credential.consumer.key, credential2.consumer.key) - self.assertEquals( + self.assertEqual( credential.consumer.secret, credential2.consumer.secret) def test_corrupted_key_handled(self): diff --git a/src/launchpadlib/tests/test_http.py b/src/launchpadlib/tests/test_http.py index 4ed95d6..0357962 100644 --- a/src/launchpadlib/tests/test_http.py +++ b/src/launchpadlib/tests/test_http.py @@ -20,7 +20,11 @@ from collections import deque import tempfile import unittest -from simplejson import dumps, JSONDecodeError +try: + from json import dumps + JSONDecodeError = ValueError +except ImportError: + from simplejson import dumps, JSONDecodeError from launchpadlib.errors import Unauthorized from launchpadlib.credentials import UnencryptedFileCredentialStore @@ -170,10 +174,10 @@ class TestTokenFailureDuringRequest(SimulatedResponsesTestCase): Response(200, SIMPLE_WADL), Response(200, SIMPLE_JSON)] - self.assertEquals(self.engine.access_tokens_obtained, 0) + self.assertEqual(self.engine.access_tokens_obtained, 0) launchpad = SimulatedResponsesLaunchpad.login_with( 'application name', authorization_engine=self.engine) - self.assertEquals(self.engine.access_tokens_obtained, 1) + self.assertEqual(self.engine.access_tokens_obtained, 1) def test_bad_token(self): """If our token is bad, we get another one.""" @@ -182,10 +186,10 @@ class TestTokenFailureDuringRequest(SimulatedResponsesTestCase): Response(200, SIMPLE_WADL), Response(200, SIMPLE_JSON)] - self.assertEquals(self.engine.access_tokens_obtained, 0) + self.assertEqual(self.engine.access_tokens_obtained, 0) launchpad = SimulatedResponsesLaunchpad.login_with( 'application name', authorization_engine=self.engine) - self.assertEquals(self.engine.access_tokens_obtained, 2) + self.assertEqual(self.engine.access_tokens_obtained, 2) def test_expired_token(self): """If our token is expired, we get another one.""" @@ -195,10 +199,10 @@ class TestTokenFailureDuringRequest(SimulatedResponsesTestCase): Response(200, SIMPLE_WADL), Response(200, SIMPLE_JSON)] - self.assertEquals(self.engine.access_tokens_obtained, 0) + self.assertEqual(self.engine.access_tokens_obtained, 0) launchpad = SimulatedResponsesLaunchpad.login_with( 'application name', authorization_engine=self.engine) - self.assertEquals(self.engine.access_tokens_obtained, 2) + self.assertEqual(self.engine.access_tokens_obtained, 2) def test_unknown_token(self): """If our token is unknown, we get another one.""" @@ -208,10 +212,10 @@ class TestTokenFailureDuringRequest(SimulatedResponsesTestCase): Response(200, SIMPLE_WADL), Response(200, SIMPLE_JSON)] - self.assertEquals(self.engine.access_tokens_obtained, 0) + self.assertEqual(self.engine.access_tokens_obtained, 0) launchpad = SimulatedResponsesLaunchpad.login_with( 'application name', authorization_engine=self.engine) - self.assertEquals(self.engine.access_tokens_obtained, 2) + self.assertEqual(self.engine.access_tokens_obtained, 2) def test_delayed_error(self): """We get another token no matter when the error happens.""" @@ -220,10 +224,10 @@ class TestTokenFailureDuringRequest(SimulatedResponsesTestCase): Response(401, "Expired token."), Response(200, SIMPLE_JSON)] - self.assertEquals(self.engine.access_tokens_obtained, 0) + self.assertEqual(self.engine.access_tokens_obtained, 0) launchpad = SimulatedResponsesLaunchpad.login_with( 'application name', authorization_engine=self.engine) - self.assertEquals(self.engine.access_tokens_obtained, 2) + self.assertEqual(self.engine.access_tokens_obtained, 2) def test_many_errors(self): """We'll keep getting new tokens as long as tokens are the problem.""" @@ -233,10 +237,10 @@ class TestTokenFailureDuringRequest(SimulatedResponsesTestCase): Response(401, "Expired token."), Response(401, "Invalid token."), Response(200, SIMPLE_JSON)] - self.assertEquals(self.engine.access_tokens_obtained, 0) + self.assertEqual(self.engine.access_tokens_obtained, 0) launchpad = SimulatedResponsesLaunchpad.login_with( 'application name', authorization_engine=self.engine) - self.assertEquals(self.engine.access_tokens_obtained, 4) + self.assertEqual(self.engine.access_tokens_obtained, 4) def test_other_unauthorized(self): """If the token is not at fault, a 401 error raises an exception.""" diff --git a/src/launchpadlib/tests/test_launchpad.py b/src/launchpadlib/tests/test_launchpad.py index ba3e4c3..c9c000b 100644 --- a/src/launchpadlib/tests/test_launchpad.py +++ b/src/launchpadlib/tests/test_launchpad.py @@ -82,7 +82,7 @@ class TestNameLookups(unittest.TestCase): self.assertEqual(len(caught), 1) warning, = caught self.assertTrue(issubclass(warning.category, DeprecationWarning)) - self.assertTrue("no longer exists" in warning.message.message) + self.assertIn("no longer exists", str(warning)) def test_short_names(self): # Ensure the short service names are all supported. @@ -96,7 +96,7 @@ class TestNameLookups(unittest.TestCase): self.assertEqual(uris.lookup_service_root('edge'), uris.lookup_service_root('production')) - def test_edge_service_root_is_production(self): + def test_edge_web_root_is_production(self): # The edge server no longer exists, so if the client wants # edge we give them production. with self.edge_deprecation_error(): @@ -180,7 +180,7 @@ class TestServiceNameWithEmbeddedVersion(unittest.TestCase): root = uris.service_roots['staging'] + version try: Launchpad(None, None, None, service_root=root, version=version) - except ValueError, e: + except ValueError as e: self.assertTrue(str(e).startswith( "It looks like you're using a service root that incorporates " 'the name of the web service version ("version-foo")')) @@ -239,7 +239,7 @@ class TestLaunchpadLoginWithCredentialsFile(unittest.TestCase): # The credentials are stored unencrypted in the file you # specify. credentials = Credentials.load_from_path(filename) - self.assertEquals(credentials.consumer.key, + self.assertEqual(credentials.consumer.key, launchpad.credentials.consumer.key) os.remove(filename) @@ -305,7 +305,7 @@ class TestLaunchpadLoginWith(KeyringTest): launchpadlib_dir = os.path.join(self.temp_dir, 'launchpadlib') # Verify a newly created-by-hand directory is insecure os.mkdir(launchpadlib_dir) - os.chmod(launchpadlib_dir, 0755) + os.chmod(launchpadlib_dir, 0o755) self.assertTrue(os.path.isdir(launchpadlib_dir)) statinfo = os.stat(launchpadlib_dir) mode = stat.S_IMODE(statinfo.st_mode) @@ -337,7 +337,7 @@ class TestLaunchpadLoginWith(KeyringTest): launchpad = NoNetworkLaunchpad.login_with( 'not important', service_root=SERVICE_ROOT, launchpadlib_dir=launchpadlib_dir, version="foo") - self.assertEquals(launchpad.passed_in_args['version'], 'foo') + self.assertEqual(launchpad.passed_in_args['version'], 'foo') # Now execute the same test a second time. This time, the # credentials are loaded from disk and a different code path @@ -346,7 +346,7 @@ class TestLaunchpadLoginWith(KeyringTest): launchpad = NoNetworkLaunchpad.login_with( 'not important', service_root=SERVICE_ROOT, launchpadlib_dir=launchpadlib_dir, version="bar") - self.assertEquals(launchpad.passed_in_args['version'], 'bar') + self.assertEqual(launchpad.passed_in_args['version'], 'bar') def test_application_name_is_propagated(self): # Create a Launchpad instance for a given application name. @@ -357,7 +357,7 @@ class TestLaunchpadLoginWith(KeyringTest): launchpad = NoNetworkLaunchpad.login_with( 'very important', service_root=SERVICE_ROOT, launchpadlib_dir=launchpadlib_dir) - self.assertEquals( + self.assertEqual( launchpad.credentials.consumer.application_name, 'very important') # Now execute the same test a second time. This time, the @@ -368,7 +368,7 @@ class TestLaunchpadLoginWith(KeyringTest): launchpad = NoNetworkLaunchpad.login_with( 'very important', service_root=SERVICE_ROOT, launchpadlib_dir=launchpadlib_dir) - self.assertEquals( + self.assertEqual( launchpad.credentials.consumer.application_name, 'very important') def test_authorization_engine_is_propagated(self): @@ -378,8 +378,8 @@ class TestLaunchpadLoginWith(KeyringTest): engine = NoNetworkAuthorizationEngine( SERVICE_ROOT, 'application name') NoNetworkLaunchpad.login_with(authorization_engine=engine) - self.assertEquals(engine.request_tokens_obtained, 1) - self.assertEquals(engine.access_tokens_obtained, 1) + self.assertEqual(engine.request_tokens_obtained, 1) + self.assertEqual(engine.access_tokens_obtained, 1) def test_login_with_must_identify_application(self): # If you call login_with without identifying your application @@ -443,10 +443,10 @@ class TestLaunchpadLoginWith(KeyringTest): # levels into login_with(). launchpad = NoNetworkLaunchpad.login_with( consumer_name="consumer", allow_access_levels=['FOO']) - self.assertEquals(launchpad.credentials.consumer.key, "consumer") - self.assertEquals(launchpad.credentials.consumer.application_name, + self.assertEqual(launchpad.credentials.consumer.key, "consumer") + self.assertEqual(launchpad.credentials.consumer.application_name, None) - self.assertEquals(launchpad.authorization_engine.allow_access_levels, + self.assertEqual(launchpad.authorization_engine.allow_access_levels, ['FOO']) def test_desktop_integration_doesnt_happen_without_consumer_name(self): @@ -456,7 +456,7 @@ class TestLaunchpadLoginWith(KeyringTest): # integration is performed. launchpad = NoNetworkLaunchpad.login_with( 'application name', allow_access_levels=['FOO']) - self.assertEquals(launchpad.authorization_engine.allow_access_levels, + self.assertEqual(launchpad.authorization_engine.allow_access_levels, ['DESKTOP_INTEGRATION']) def test_no_credentials_creates_new_credential(self): @@ -471,7 +471,7 @@ class TestLaunchpadLoginWith(KeyringTest): NoNetworkAuthorizationEngine.ACCESS_TOKEN_KEY) self.assertEqual(launchpad.credentials.consumer.application_name, 'app name') - self.assertEquals(launchpad.authorization_engine.allow_access_levels, + self.assertEqual(launchpad.authorization_engine.allow_access_levels, ['DESKTOP_INTEGRATION']) # The expected arguments were passed in to the Launchpad # constructor. @@ -580,16 +580,16 @@ class TestDeprecatedLoginMethods(KeyringTest): with warnings.catch_warnings(record=True) as caught: warnings.simplefilter("always") NoNetworkLaunchpad.login('consumer', 'token', 'secret') - self.assertEquals(len(caught), 1) - self.assertEquals(caught[0].category, DeprecationWarning) + self.assertEqual(len(caught), 1) + self.assertEqual(caught[0].category, DeprecationWarning) def test_get_token_and_login_is_deprecated(self): # get_token_and_login() works but triggers a deprecation warning. with warnings.catch_warnings(record=True) as caught: warnings.simplefilter("always") NoNetworkLaunchpad.get_token_and_login('consumer') - self.assertEquals(len(caught), 1) - self.assertEquals(caught[0].category, DeprecationWarning) + self.assertEqual(len(caught), 1) + self.assertEqual(caught[0].category, DeprecationWarning) class TestCredenitialSaveFailedCallback(unittest.TestCase): @@ -624,7 +624,7 @@ class TestCredenitialSaveFailedCallback(unittest.TestCase): 'not important', service_root=service_root, launchpadlib_dir=launchpadlib_dir, credential_save_failed=callback) - self.assertEquals(len(callback_called), 1) + self.assertEqual(len(callback_called), 1) def test_default_credentials_save_failed_is_to_raise_exception(self): # If saving the credentials did not succeed and no callback was @@ -666,18 +666,18 @@ class TestMultipleSites(unittest.TestCase): launchpadlib_dir=launchpadlib_dir) consumer_name = launchpad.credentials.consumer.key - application_key = keyring.data.keys()[0][1] + application_key = list(keyring.data.keys())[0][1] # Both the consumer name (normally the name of the application) and # the service root (the URL of the service being accessed) are # included in the key when storing credentials. - self.assert_(service_root in application_key) - self.assert_(consumer_name in application_key) + self.assertIn(service_root, application_key) + self.assertIn(consumer_name, application_key) # The key used to store the credentials is of this structure (and # shouldn't change between releases or stored credentials will be # "forgotten"). - self.assertEquals(application_key, consumer_name + '@' + service_root) + self.assertEqual(application_key, consumer_name + '@' + service_root) def test_same_app_different_servers(self): launchpadlib_dir = os.path.join(self.temp_dir, 'launchpadlib') @@ -698,8 +698,8 @@ class TestMultipleSites(unittest.TestCase): # is of the test mechanism, not a test assertion). assert len(keyring.data.keys()) == 2 - application_key_1 = keyring.data.keys()[0][1] - application_key_2 = keyring.data.keys()[1][1] + application_key_1 = list(keyring.data.keys())[0][1] + application_key_2 = list(keyring.data.keys())[1][1] self.assertNotEqual(application_key_1, application_key_2) diff --git a/src/launchpadlib/uris.py b/src/launchpadlib/uris.py index 17b8832..a4f0c6a 100644 --- a/src/launchpadlib/uris.py +++ b/src/launchpadlib/uris.py @@ -26,8 +26,11 @@ __all__ = [ 'lookup_web_root', 'web_root_for_service_root', ] - -from urlparse import urlparse +try: + from urllib.parse import urlparse +except ImportError: + from urlparse import urlparse + import warnings from lazr.uri import URI @@ -35,14 +38,14 @@ LPNET_SERVICE_ROOT = 'https://api.launchpad.net/' QASTAGING_SERVICE_ROOT = 'https://api.qastaging.launchpad.net/' STAGING_SERVICE_ROOT = 'https://api.staging.launchpad.net/' DEV_SERVICE_ROOT = 'https://api.launchpad.dev/' -DOGFOOD_SERVICE_ROOT = 'https://api.dogfood.launchpad.net/' +DOGFOOD_SERVICE_ROOT = 'https://api.dogfood.paddev.net/' TEST_DEV_SERVICE_ROOT = 'http://api.launchpad.dev:8085/' LPNET_WEB_ROOT = 'https://launchpad.net/' QASTAGING_WEB_ROOT = 'https://qastaging.launchpad.net/' STAGING_WEB_ROOT = 'https://staging.launchpad.net/' DEV_WEB_ROOT = 'https://launchpad.dev/' -DOGFOOD_WEB_ROOT = 'https://dogfood.launchpad.net/' +DOGFOOD_WEB_ROOT = 'https://dogfood.paddev.net/' TEST_DEV_WEB_ROOT = 'http://launchpad.dev:8085/' # If you use EDGE_SERVICE_ROOT, or its alias, or the equivalent |