From ace6cc2eac8d664110599350b84edbbdcb8aff7b Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Wed, 27 Aug 2014 14:23:33 +0100 Subject: [PATCH] Changed name of doc to open_doc Rewrote to be testable Added method to choose stable or devel, with default to look at version Added tests Added compatibility code for Python2/3 urlencode --- statsmodels/api.py | 2 +- statsmodels/compat/python.py | 4 ++ statsmodels/tools/tests/test_web.py | 33 ++++++++++++ statsmodels/tools/web.py | 79 ++++++++++++++++++++--------- 4 files changed, 92 insertions(+), 26 deletions(-) create mode 100644 statsmodels/tools/tests/test_web.py diff --git a/statsmodels/api.py b/statsmodels/api.py index f391b2f3037..4eb242b03ae 100644 --- a/statsmodels/api.py +++ b/statsmodels/api.py @@ -30,7 +30,7 @@ from .iolib.smpickle import load_pickle as load from .tools.print_version import show_versions -from .tools.web import doc +from .tools.web import open_doc import os diff --git a/statsmodels/compat/python.py b/statsmodels/compat/python.py index 2b4b43ca60e..fa5a03e016e 100644 --- a/statsmodels/compat/python.py +++ b/statsmodels/compat/python.py @@ -5,6 +5,7 @@ import functools import itertools import sys +import urllib PY3 = (sys.version_info[0] >= 3) PY3_2 = sys.version_info[:2] == (3, 2) @@ -32,6 +33,7 @@ import urllib.parse from urllib.request import HTTPError, urlretrieve + if PY3: import io bytes = bytes @@ -90,6 +92,7 @@ def lfilter(*args, **kwargs): urlopen = urllib.request.urlopen urljoin = urllib.parse.urljoin urlretrieve = urllib.request.urlretrieve + urlencode = urllib.parse.urlencode string_types = str input = input @@ -130,6 +133,7 @@ def open_latin1(filename, mode='r'): urlopen = urllib2.urlopen urljoin = urlparse.urljoin + urlencode = urllib.urlencode HTTPError = urllib2.HTTPError string_types = basestring diff --git a/statsmodels/tools/tests/test_web.py b/statsmodels/tools/tests/test_web.py new file mode 100644 index 00000000000..2de51c23a27 --- /dev/null +++ b/statsmodels/tools/tests/test_web.py @@ -0,0 +1,33 @@ +from statsmodels.tools.web import _generate_url, open_doc +from statsmodels.regression.linear_model import OLS +from unittest import TestCase +from nose.tools import assert_equal, assert_raises +from numpy import array + +class TestWeb(TestCase): + def test_string(self): + url = _generate_url('arch',True) + assert_equal(url, 'http://statsmodels.sourceforge.net/stable/search.html?q=arch&check_keywords=yes&area=default') + url = _generate_url('arch',False) + assert_equal(url, 'http://statsmodels.sourceforge.net/devel/search.html?q=arch&check_keywords=yes&area=default') + url = _generate_url('dickey fuller',False) + assert_equal(url, 'http://statsmodels.sourceforge.net/devel/search.html?q=dickey+fuller&check_keywords=yes&area=default') + + def test_function(self): + url = _generate_url(OLS, True) + assert_equal(url, 'http://statsmodels.sourceforge.net/stable/generated/statsmodels.regression.linear_model.OLS.html') + url = _generate_url(OLS, False) + assert_equal(url, 'http://statsmodels.sourceforge.net/devel/generated/statsmodels.regression.linear_model.OLS.html') + + def test_nothing(self): + url = _generate_url(None, True) + assert_equal(url, 'http://statsmodels.sourceforge.net/stable/') + url = _generate_url(None, False) + assert_equal(url, 'http://statsmodels.sourceforge.net/devel/') + + def test_errors(self): + assert_raises(ValueError, open_doc, array, True) + assert_raises(ValueError, open_doc, 1, False) + + + diff --git a/statsmodels/tools/web.py b/statsmodels/tools/web.py index bc438609f8c..da8c4c691f3 100644 --- a/statsmodels/tools/web.py +++ b/statsmodels/tools/web.py @@ -3,46 +3,75 @@ to a function's reference """ import webbrowser -import urllib -BASE_URL = 'http://statsmodels.sourceforge.net/stable/' +from statsmodels.compat.python import urlencode +from statsmodels.version import release +BASE_URL = 'http://statsmodels.sourceforge.net/' -def doc(arg=None): - """ - Parameters - ---------- - arg, optional : string or statsmodels function - Either a string to search the documentation or a function - Examples - -------- - >>> import statsmodels.api as sm - >>> sm.doc() # Documention site - >>> sm.doc('glm') # Search for glm in docs - >>> sm.doc(sm.OLS) # Go to generated help for OLS - - Notes - ----- - Opens in the system default browser +def _generate_url(arg, stable): + """ + Parse inputs and return a correctly formatted URL or an error if the input + is not understandable """ + url = BASE_URL + if stable: + url += 'stable/' + else: + url += 'devel/' + if arg is None: - url = BASE_URL + return url elif type(arg) is str: - url = BASE_URL + 'search.html?' - url += urllib.urlencode({'q': arg}) + url += 'search.html?' + url += urlencode({'q': arg}) url += '&check_keywords=yes&area=default' else: try: func = arg func_name = func.__name__ func_module = func.__module__ - url = BASE_URL + 'generated/' + if not func_module.startswith('statsmodels.'): + return ValueError('Function must be from statsmodels') + url += 'generated/' url += func_module + '.' + func_name + '.html' except: - raise ValueError('Input not understood') - webbrowser.open(url) - return None + return ValueError('Input not understood') + return url +def open_doc(arg=None, stable=None): + """ + Opens a browser and displays online documentation + + Parameters + ---------- + arg, optional : string or statsmodels function + Either a string to search the documentation or a function + stable, optional : bool + Flag indicating whether to use the stable documentation (True) or + the development documentation (False). If not provided, opens + the stable documentation if the current version of statsmodels is a + release + Examples + -------- + >>> import statsmodels.api as sm + >>> sm.open_doc() # Documention site + >>> sm.open_doc('glm') # Search for glm in docs + >>> sm.open_doc(sm.OLS, stable=False) # Go to generated help for OLS, devel + + Notes + ----- + By default, open stable documentation if the current version of statsmodels + is a release. Otherwise opens the development documentation. + + Uses the default system browser. + """ + stable = release if stable is None else stable + url_or_error = _generate_url(arg, stable) + if isinstance(url_or_error, ValueError): + raise url_or_error + webbrowser.open(url_or_error) + return None