Bladeren bron

Merge upstream.

Pierre Bellec 12 jaren geleden
bovenliggende
commit
e5bc06bc73
7 gewijzigde bestanden met toevoegingen van 138 en 76 verwijderingen
  1. 8 0
      CHANGES.txt
  2. 33 17
      README.rst
  3. 13 2
      howdoi.rb
  4. 1 1
      howdoi/__init__.py
  5. 47 34
      howdoi/howdoi.py
  6. 1 0
      requirements.txt
  7. 35 22
      setup.py

+ 8 - 0
CHANGES.txt

@@ -1,3 +1,11 @@
+1.0
+------
+
+-  Added support for Python3
+-  Switched to the requests library instead of urllib2
+-  Project status changed to Production/Stable
+-  Added troubleshooting steps to the README
+
 0.2
 ------
 

+ 33 - 17
README.rst

@@ -9,15 +9,10 @@ browser and read through blogs when you can just...
 
 ::
 
-    $ howdoi format string bash
-    > [foo@bar ~]$date --date "2012-02-13" +%s
-    > 1329055200
-    > [foo@bar ~]$date --date @1329055200
-    > Mon Feb 13 00:00:00 EST 2012
-    > [foo@bar ~]$date --date @1329055200 +"%Y-%m-%d"
-    > 2012-02-13
+    $ howdoi format date bash
+    > DATE=`date +%Y-%m-%d`
 
-howdoi will answer all sorts of queries
+howdoi will answer all sorts of queries:
 
 ::
 
@@ -69,18 +64,20 @@ Usage
 
 ::
 
-    howdoi [-h] [-p POS] [-a] [-l] QUERY [QUERY ...]
+    usage: howdoi.py [-h] [-p POS] [-a] [-l] [-n NUM_ANSWERS] QUERY [QUERY ...]
 
     code search tool
 
     positional arguments:
-      QUERY              the question to answer
+      QUERY                 the question to answer
 
     optional arguments:
-      -h, --help         show this help message and exit
-      -p POS, --pos POS  select answer in specified position (default: 1)
-      -a, --all          display the full text of the answer
-      -l, --link         display only the answer link
+      -h, --help            show this help message and exit
+      -p POS, --pos POS     select answer in specified position (default: 1)
+      -a, --all             display the full text of the answer
+      -l, --link            display only the answer link
+      -n NUM_ANSWERS, --num-answers NUM_ANSWERS
+                            number of answers to return
 
 Author
 ------
@@ -91,7 +88,26 @@ Author
 Notes
 -----
 
--  Requires Python <= 2.7 (pull requests for a Python 3 version certainly accepted)
--  Requires `PyQuery <http://pypi.python.org/pypi/pyquery>`_
+-  Works with Python2 and Python3
+-  A standalone Windows executable with the howdoi application `is available here <https://dl.dropbox.com/u/101688/website/misc/howdoi.exe>`_.
 -  Special thanks to Rich Jones
-   (`@miserlou <https://github.com/miserlou>`_) for the idea
+   (`@miserlou <https://github.com/miserlou>`_) for the idea.
+
+Troubleshooting
+---------------
+
+You might get the following error when installing with Homebrew:
+
+::
+
+    ==> python setup.py install
+
+    http://peak.telecommunity.com/EasyInstall.html
+
+    Please make the appropriate changes for your system and try again.
+
+Fix the error by executing the following command:
+
+::
+
+    sudo chmod -R go+w /Library/Python/2.7/site-packages/

+ 13 - 2
howdoi.rb

@@ -2,11 +2,22 @@ require 'formula'
 
 class Howdoi < Formula
   homepage 'https://github.com/gleitz/howdoi/'
-  url 'http://pypi.python.org/packages/source/h/howdoi/howdoi-0.2.tar.gz'
-  sha1 '69feff9525279641ccbf94995c0a047c5775eac7'
+  url 'http://pypi.python.org/packages/source/h/howdoi/howdoi-1.0.tar.gz'
+  sha1 'a074e523b7e00c5ab42b9539694bc37071d3363c'
 
   def install
     setup_args = ['setup.py', 'install']
     system "python", *setup_args
   end
+
+  def scripts_folder
+    HOMEBREW_PREFIX/"share/python"
+  end
+
+  def caveats
+    <<-EOS.undent
+      To run the `howdoi` command, you'll need to add Python's script directory to your PATH:
+        #{scripts_folder}
+    EOS
+  end
 end

+ 1 - 1
howdoi/__init__.py

@@ -1 +1 @@
-__version__ = '0.2'
+__version__ = '1.0'

+ 47 - 34
howdoi/howdoi.py

@@ -8,12 +8,14 @@
 #
 ##################################################
 
-import urllib
-import urllib2
-import sys
-import json
 import argparse
 import re
+import requests
+
+try:
+    from urllib.parse import quote as url_quote
+except ImportError:
+    from urllib import quote as url_quote
 
 from pygments import highlight
 from pygments.lexers import guess_lexer, get_lexer_by_name
@@ -21,34 +23,30 @@ from pygments.formatters import TerminalFormatter
 from pygments.util import ClassNotFound
 
 from pyquery import PyQuery as pq
+from requests.exceptions import ConnectionError
+
+SEARCH_URL = 'https://www.google.com/search?q=site:stackoverflow.com%20{0}'
+USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1309.0 Safari/537.17'
+ANSWER_HEADER = u'--- Answer {0} ---\n{1}'
 
-GOOGLE_SEARCH_URL = "https://www.google.com/search?q=site:stackoverflow.com%20{0}"
-DUCK_SEARCH_URL = "http://duckduckgo.com/html?q=site%3Astackoverflow.com%20{0}"
-USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1309.0 Safari/537.17"
 
 def get_result(url):
-    opener = urllib2.build_opener()
-    opener.addheaders = [('User-agent', USER_AGENT)]
-    result = opener.open(url)
-    return result.read()
+    return requests.get(url, headers={'User-Agent': USER_AGENT}).text
+
 
 def is_question(link):
     return re.search('questions/\d+/', link)
 
-def get_google_links(query):
-    url = GOOGLE_SEARCH_URL.format(urllib.quote(query))
+
+def get_links(query):
+    url = SEARCH_URL.format(url_quote(query))
     result = get_result(url)
     html = pq(result)
     return [a.attrib['href'] for a in html('.l')]
 
-def get_duck_links(query):
-    url = DUCK_SEARCH_URL.format(urllib.quote(query))
-    result = get_result(url)
-    html = pq(result)
-    links = [l.find('a').attrib['href'] for l in html('.links_main')]
 
 def get_link_at_pos(links, pos):
-    pos = int(pos) - 1
+    pos = pos - 1
     for link in links:
         if is_question(link):
             if pos == 0:
@@ -82,15 +80,10 @@ def colorize(code, tags=[], arguments=[]):
     )
 
 
-def get_instructions(args):
-    links = get_google_links(args['query'])
-    if not links:
-        return ''
-
+def get_answer(args, links):
     link = get_link_at_pos(links, args['pos'])
     if args.get('link'):
         return link
-
     link = link + '?answertab=votes'
     page = get_result(link)
     html = pq(page)
@@ -101,29 +94,49 @@ def get_instructions(args):
     if args['all'] or not instructions:
         text = first_answer.find('.post-text').eq(0).text()
     else:
-        text = colorize(instructions.eq(0).text(),
-                tags=[t.text for t in html('.post-tag')],
-                arguments=args['query'].split())
+        text = instructions.eq(0).text()
+    return text
+
 
-    if not text:
+def get_instructions(args):
+    links = get_links(args['query'])
+    if not links:
         return ''
-    return text
+    answers = []
+    append_header = args['num_answers'] > 1
+    initial_position = args['pos']
+    for answer_number in range(args['num_answers']):
+        current_position = answer_number + initial_position
+        args['pos'] = current_position
+        answer = get_answer(args, links)
+        if not answer:
+            continue
+        if append_header:
+            answer = ANSWER_HEADER.format(current_position, answer)
+        answer = answer + '\n'
+        answers.append(answer)
+    return u'\n'.join(answers)
+
 
 def howdoi(args):
     args['query'] = ' '.join(args['query']).replace('?', '')
-    instructions = get_instructions(args) or 'Sorry, couldn\'t find any help with that topic'
+    try:
+        instructions = get_instructions(args) or 'Sorry, couldn\'t find any help with that topic\n'
+        print(instructions)
+    except ConnectionError:
+        print('Failed to establish network connection\n')
 
-    print instructions
 
 def command_line_runner():
     parser = argparse.ArgumentParser(description='code search tool')
-    parser.add_argument('query', metavar='QUERY', type=str, nargs=argparse.REMAINDER,
+    parser.add_argument('query', metavar='QUERY', type=str, nargs='+',
                         help='the question to answer')
-    parser.add_argument('-p','--pos', help='select answer in specified position (default: 1)', default=1)
+    parser.add_argument('-p','--pos', help='select answer in specified position (default: 1)', default=1, type=int)
     parser.add_argument('-a','--all', help='display the full text of the answer',
                         action='store_true')
     parser.add_argument('-l','--link', help='display only the answer link',
                         action='store_true')
+    parser.add_argument('-n','--num-answers', help='number of answers to return', default=1, type=int)
     args = vars(parser.parse_args())
     howdoi(args)
 

+ 1 - 0
requirements.txt

@@ -4,3 +4,4 @@ pyquery==1.2.2
 wsgiref==0.1.2
 pygments==1.5
 argparse
+requests

+ 35 - 22
setup.py

@@ -4,6 +4,14 @@ from setuptools import setup, find_packages
 import howdoi
 import os
 
+
+def extra_dependencies():
+    import sys
+    ret = []
+    if sys.version_info < (2,7):
+        ret.append('argparse')
+    return ret
+
 def read(*names):
     values = dict()
     extensions = ['.txt', '.rst']
@@ -27,34 +35,39 @@ News
 
 """ % read('README', 'CHANGES')
 
-setup(name='howdoi',
-      version=howdoi.__version__,
-      description='A code search tool',
-      long_description=long_description,
-      classifiers=[
-        "Development Status :: 4 - Beta",
+setup(
+    name='howdoi',
+    version=howdoi.__version__,
+    description='A code search tool',
+    long_description=long_description,
+    classifiers=[
+        "Development Status :: 5 - Production/Stable",
         "Environment :: Console",
         "Intended Audience :: Developers",
         "Programming Language :: Python :: 2",
+        "Programming Language :: Python :: 2.6",
         "Programming Language :: Python :: 2.7",
+        "Programming Language :: Python :: 3",
+        "Programming Language :: Python :: 3.2",
+        "Programming Language :: Python :: 3.3",
         "Topic :: Documentation",
-        ],
-      keywords='howdoi help console',
-      author='Benjamin Gleitzman',
-      author_email='gleitz@mit.edu',
-      maintainer='Benjamin Gleitzman',
-      maintainer_email='gleitz@mit.edu',
-      url='https://github.com/gleitz/howdoi',
-      license='MIT',
-      packages=find_packages(),
-      entry_points={
+    ],
+    keywords='howdoi help console',
+    author='Benjamin Gleitzman',
+    author_email='gleitz@mit.edu',
+    maintainer='Benjamin Gleitzman',
+    maintainer_email='gleitz@mit.edu',
+    url='https://github.com/gleitz/howdoi',
+    license='MIT',
+    packages=find_packages(),
+    entry_points={
         'console_scripts': [
             'howdoi = howdoi.howdoi:command_line_runner',
-            ]
-        },
-      install_requires=[
+        ]
+    },
+    install_requires=[
         'pyquery',
-        'argparse',
         'pygments',
-        ],
-      )
+        'requests'
+    ] + extra_dependencies(),
+)