Skip to content

Commit

Permalink
Merge upstream.
Browse files Browse the repository at this point in the history
  • Loading branch information
bellecp committed Feb 5, 2013
2 parents 48a665b + 8c7d0df commit e5bc06b
Show file tree
Hide file tree
Showing 7 changed files with 138 additions and 76 deletions.
8 changes: 8 additions & 0 deletions CHANGES.txt
Original file line number Diff line number Diff line change
@@ -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
------

Expand Down
50 changes: 33 additions & 17 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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:

::

Expand Down Expand Up @@ -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
------
Expand All @@ -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/
15 changes: 13 additions & 2 deletions howdoi.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,22 @@

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
2 changes: 1 addition & 1 deletion howdoi/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '0.2'
__version__ = '1.0'
81 changes: 47 additions & 34 deletions howdoi/howdoi.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,47 +8,45 @@
#
##################################################

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
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:
Expand Down Expand Up @@ -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)
Expand All @@ -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)

Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ pyquery==1.2.2
wsgiref==0.1.2
pygments==1.5
argparse
requests
57 changes: 35 additions & 22 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@
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']
Expand All @@ -27,34 +35,39 @@ def read(*names):
""" % 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='[email protected]',
maintainer='Benjamin Gleitzman',
maintainer_email='[email protected]',
url='https://github.com/gleitz/howdoi',
license='MIT',
packages=find_packages(),
entry_points={
],
keywords='howdoi help console',
author='Benjamin Gleitzman',
author_email='[email protected]',
maintainer='Benjamin Gleitzman',
maintainer_email='[email protected]',
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(),
)

0 comments on commit e5bc06b

Please sign in to comment.