Browse Source

turses

master
Shaggy 8 years ago
parent
commit
32d8bdb387
  1. BIN
      turses/pkg/turses/.MTREE
  2. 27
      turses/pkg/turses/.PKGINFO
  3. 10
      turses/pkg/turses/usr/bin/turses
  4. 50
      turses/pkg/turses/usr/lib/python2.7/site-packages/turses-0.2.23-py2.7.egg-info/PKG-INFO
  5. 33
      turses/pkg/turses/usr/lib/python2.7/site-packages/turses-0.2.23-py2.7.egg-info/SOURCES.txt
  6. 1
      turses/pkg/turses/usr/lib/python2.7/site-packages/turses-0.2.23-py2.7.egg-info/dependency_links.txt
  7. 3
      turses/pkg/turses/usr/lib/python2.7/site-packages/turses-0.2.23-py2.7.egg-info/entry_points.txt
  8. 3
      turses/pkg/turses/usr/lib/python2.7/site-packages/turses-0.2.23-py2.7.egg-info/requires.txt
  9. 1
      turses/pkg/turses/usr/lib/python2.7/site-packages/turses-0.2.23-py2.7.egg-info/top_level.txt
  10. 16
      turses/pkg/turses/usr/lib/python2.7/site-packages/turses/__init__.py
  11. BIN
      turses/pkg/turses/usr/lib/python2.7/site-packages/turses/__init__.pyc
  12. BIN
      turses/pkg/turses/usr/lib/python2.7/site-packages/turses/__init__.pyo
  13. 5
      turses/pkg/turses/usr/lib/python2.7/site-packages/turses/api/__init__.py
  14. BIN
      turses/pkg/turses/usr/lib/python2.7/site-packages/turses/api/__init__.pyc
  15. BIN
      turses/pkg/turses/usr/lib/python2.7/site-packages/turses/api/__init__.pyo
  16. 359
      turses/pkg/turses/usr/lib/python2.7/site-packages/turses/api/backends.py
  17. BIN
      turses/pkg/turses/usr/lib/python2.7/site-packages/turses/api/backends.pyc
  18. BIN
      turses/pkg/turses/usr/lib/python2.7/site-packages/turses/api/backends.pyo
  19. 469
      turses/pkg/turses/usr/lib/python2.7/site-packages/turses/api/base.py
  20. BIN
      turses/pkg/turses/usr/lib/python2.7/site-packages/turses/api/base.pyc
  21. BIN
      turses/pkg/turses/usr/lib/python2.7/site-packages/turses/api/base.pyo
  22. 199
      turses/pkg/turses/usr/lib/python2.7/site-packages/turses/api/debug.py
  23. BIN
      turses/pkg/turses/usr/lib/python2.7/site-packages/turses/api/debug.pyc
  24. BIN
      turses/pkg/turses/usr/lib/python2.7/site-packages/turses/api/debug.pyo
  25. 149
      turses/pkg/turses/usr/lib/python2.7/site-packages/turses/api/helpers.py
  26. BIN
      turses/pkg/turses/usr/lib/python2.7/site-packages/turses/api/helpers.pyc
  27. BIN
      turses/pkg/turses/usr/lib/python2.7/site-packages/turses/api/helpers.pyo
  28. 179
      turses/pkg/turses/usr/lib/python2.7/site-packages/turses/cli.py
  29. BIN
      turses/pkg/turses/usr/lib/python2.7/site-packages/turses/cli.pyc
  30. BIN
      turses/pkg/turses/usr/lib/python2.7/site-packages/turses/cli.pyo
  31. 778
      turses/pkg/turses/usr/lib/python2.7/site-packages/turses/config.py
  32. BIN
      turses/pkg/turses/usr/lib/python2.7/site-packages/turses/config.pyc
  33. BIN
      turses/pkg/turses/usr/lib/python2.7/site-packages/turses/config.pyo
  34. 1326
      turses/pkg/turses/usr/lib/python2.7/site-packages/turses/core.py
  35. BIN
      turses/pkg/turses/usr/lib/python2.7/site-packages/turses/core.pyc
  36. BIN
      turses/pkg/turses/usr/lib/python2.7/site-packages/turses/core.pyo
  37. 266
      turses/pkg/turses/usr/lib/python2.7/site-packages/turses/meta.py
  38. BIN
      turses/pkg/turses/usr/lib/python2.7/site-packages/turses/meta.pyc
  39. BIN
      turses/pkg/turses/usr/lib/python2.7/site-packages/turses/meta.pyo
  40. 615
      turses/pkg/turses/usr/lib/python2.7/site-packages/turses/models.py
  41. BIN
      turses/pkg/turses/usr/lib/python2.7/site-packages/turses/models.pyc
  42. BIN
      turses/pkg/turses/usr/lib/python2.7/site-packages/turses/models.pyo
  43. 200
      turses/pkg/turses/usr/lib/python2.7/site-packages/turses/session.py
  44. BIN
      turses/pkg/turses/usr/lib/python2.7/site-packages/turses/session.pyc
  45. BIN
      turses/pkg/turses/usr/lib/python2.7/site-packages/turses/session.pyo
  46. 1249
      turses/pkg/turses/usr/lib/python2.7/site-packages/turses/ui.py
  47. BIN
      turses/pkg/turses/usr/lib/python2.7/site-packages/turses/ui.pyc
  48. BIN
      turses/pkg/turses/usr/lib/python2.7/site-packages/turses/ui.pyo
  49. 80
      turses/pkg/turses/usr/lib/python2.7/site-packages/turses/utils.py
  50. BIN
      turses/pkg/turses/usr/lib/python2.7/site-packages/turses/utils.pyc
  51. BIN
      turses/pkg/turses/usr/lib/python2.7/site-packages/turses/utils.pyo
  52. BIN
      turses/turses-0.2.23-2-any.pkg.tar.xz
  53. BIN
      turses/turses-0.2.23-2.src.tar.gz
  54. BIN
      turses/turses-0.2.23.tar.gz

BIN
turses/pkg/turses/.MTREE

Binary file not shown.

27
turses/pkg/turses/.PKGINFO

@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
# Generated by makepkg 4.1.2
# using fakeroot version 1.20.2
# Sun Dec 14 15:03:54 UTC 2014
pkgname = turses
pkgver = 0.2.23-2
pkgdesc = A Twitter client for the console
url = http://pypi.python.org/pypi/turses/
builddate = 1418569434
packager = Unknown Packager
size = 618496
arch = any
license = GPLv3
depend = ncurses
depend = python2
depend = python2-oauth2
depend = python2-tweepy
depend = python2-urwid
depend = python2-setuptools
makepkgopt = strip
makepkgopt = docs
makepkgopt = !libtool
makepkgopt = !staticlibs
makepkgopt = emptydirs
makepkgopt = zipman
makepkgopt = purge
makepkgopt = !upx
makepkgopt = !debug

10
turses/pkg/turses/usr/bin/turses

@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
#!/bin/python2
# EASY-INSTALL-ENTRY-SCRIPT: 'turses==0.2.23','console_scripts','turses'
__requires__ = 'turses==0.2.23'
import sys
from pkg_resources import load_entry_point
if __name__ == '__main__':
sys.exit(
load_entry_point('turses==0.2.23', 'console_scripts', 'turses')()
)

50
turses/pkg/turses/usr/lib/python2.7/site-packages/turses-0.2.23-py2.7.egg-info/PKG-INFO

@ -0,0 +1,50 @@ @@ -0,0 +1,50 @@
Metadata-Version: 1.1
Name: turses
Version: 0.2.23
Summary: A Twitter client for the console.
Home-page: http://github.com/alejandrogomez/turses
Author: Alejandro Gómez
Author-email: alejandro@dialelo.com
License: UNKNOWN
Description:
turses
======
A Twitter client for the console.
The goal of the project is to build a full-featured, lightweight, and extremely
configurable Twitter client.
Documentation
-------------
The documentation for ``turses`` is `available on ReadTheDocs
<http://turses.readthedocs.org>`_.
License
-------
``turses`` is licensed under a GPLv3 license, see ``LICENSE`` for details.
Authors
-------
``turses`` is based on `Tyrs`_ by `Nicolas Paris`_.
.. _`Tyrs`: http://tyrs.nicosphere.net
.. _`Nicolas Paris`: http://github.com/Nic0
See ``AUTHORS`` for a full list of contributors.
Keywords: twitter client,curses,console,twitter
Platform: UNKNOWN
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console :: Curses
Classifier: Intended Audience :: End Users/Desktop
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
Classifier: Natural Language :: English
Classifier: Operating System :: POSIX :: Linux
Classifier: Operating System :: MacOS
Classifier: Programming Language :: Python :: 2.6
Classifier: Programming Language :: Python :: 2.7
Classifier: Topic :: Communications

33
turses/pkg/turses/usr/lib/python2.7/site-packages/turses-0.2.23-py2.7.egg-info/SOURCES.txt

@ -0,0 +1,33 @@ @@ -0,0 +1,33 @@
MANIFEST.in
README.rst
setup.cfg
setup.py
tests/__init__.py
tests/test_api.py
tests/test_config.py
tests/test_core.py
tests/test_meta.py
tests/test_models.py
tests/test_session.py
tests/test_ui.py
tests/test_utils.py
turses/__init__.py
turses/cli.py
turses/config.py
turses/core.py
turses/meta.py
turses/models.py
turses/session.py
turses/ui.py
turses/utils.py
turses.egg-info/PKG-INFO
turses.egg-info/SOURCES.txt
turses.egg-info/dependency_links.txt
turses.egg-info/entry_points.txt
turses.egg-info/requires.txt
turses.egg-info/top_level.txt
turses/api/__init__.py
turses/api/backends.py
turses/api/base.py
turses/api/debug.py
turses/api/helpers.py

1
turses/pkg/turses/usr/lib/python2.7/site-packages/turses-0.2.23-py2.7.egg-info/dependency_links.txt

@ -0,0 +1 @@ @@ -0,0 +1 @@

3
turses/pkg/turses/usr/lib/python2.7/site-packages/turses-0.2.23-py2.7.egg-info/entry_points.txt

@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
[console_scripts]
turses = turses.cli:main

3
turses/pkg/turses/usr/lib/python2.7/site-packages/turses-0.2.23-py2.7.egg-info/requires.txt

@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
oauth2
urwid
tweepy >2.2,<3

1
turses/pkg/turses/usr/lib/python2.7/site-packages/turses-0.2.23-py2.7.egg-info/top_level.txt

@ -0,0 +1 @@ @@ -0,0 +1 @@
turses

16
turses/pkg/turses/usr/lib/python2.7/site-packages/turses/__init__.py

@ -0,0 +1,16 @@ @@ -0,0 +1,16 @@
# -*- coding: utf-8 -*-
"""
turses
~~~~~~
A Twitter client for the console.
"""
__title__ = "turses"
__author__ = "Alejandro Gómez"
__copyright__ = "Copyright 2012-2013 turses contributors"
__license__ = "GPL3"
__version__ = (0, 2, 23)
version = "%s.%s.%s" % __version__

BIN
turses/pkg/turses/usr/lib/python2.7/site-packages/turses/__init__.pyc

Binary file not shown.

BIN
turses/pkg/turses/usr/lib/python2.7/site-packages/turses/__init__.pyo

Binary file not shown.

5
turses/pkg/turses/usr/lib/python2.7/site-packages/turses/api/__init__.py

@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
"""
This module contains the Twitter API implementations.
"""

BIN
turses/pkg/turses/usr/lib/python2.7/site-packages/turses/api/__init__.pyc

Binary file not shown.

BIN
turses/pkg/turses/usr/lib/python2.7/site-packages/turses/api/__init__.pyo

Binary file not shown.

359
turses/pkg/turses/usr/lib/python2.7/site-packages/turses/api/backends.py

@ -0,0 +1,359 @@ @@ -0,0 +1,359 @@
# -*- coding: utf-8 -*-
"""
This module contains implementations of :class:`turses.api.base.ApiAdapter`
using libraries for accessing the Twitter API.
"""
from functools import wraps, partial
from tweepy import API as BaseTweepyApi
from tweepy import OAuthHandler as TweepyOAuthHandler
from turses.config import configuration
from turses.meta import filter_result
from turses.models import User, Status, DirectMessage, List
from turses.api.base import ApiAdapter
def include_entities(func):
"""
Injects the `include_entities=True` keyword argument into `func`.
"""
@wraps(func)
def wrapper(*args, **kwargs):
kwargs['include_entities'] = True
return func(*args, **kwargs)
return wrapper
# Decorators for converting data to `turses.models`
def _to_status(status, **kwargs):
"""
Convert a `tweepy.Status` to a `turses.models.Status`.
"""
defaults = {
'id': status.id,
'created_at': status.created_at,
'user': None,
'text': status.text,
'is_reply': False,
'is_retweet': False,
'is_favorite': False,
'in_reply_to_user': '',
'in_reply_to_status_id': None,
'retweeted_status': None,
'retweet_count': 0,
'author': '',
'entities': getattr(status, 'entities', None),
}
# When fetching an individual user her last status is included and
# does not include a `user` attribute
if getattr(status, 'user', None):
defaults['user'] = status.user.screen_name
if hasattr(status, 'retweeted_status'):
defaults['is_retweet'] = True
defaults['retweeted_status'] = _to_status(status.retweeted_status)
defaults['retweet_count'] = status.retweet_count
# the `retweeted_status` could not have a `user` attribute
# (e.g. when fetching a user and her last status is a retweet)
if hasattr(status.retweeted_status, 'user'):
defaults['author'] = status.retweeted_status.user.screen_name
if getattr(status, 'in_reply_to_screen_name', False):
defaults['is_reply'] = True
defaults['in_reply_to_user'] = status.in_reply_to_screen_name
if getattr(status, 'in_reply_to_status_id', False):
defaults['in_reply_to_status_id'] = status.in_reply_to_status_id
if hasattr(status, 'favorited'):
defaults['is_favorite'] = status.favorited
defaults.update(**kwargs)
return Status(**defaults)
def _to_direct_message(dm, **kwargs):
"""
Convert a `tweepy.DirectMessage` to a `turses.models.DirectMessage`.
"""
defaults = {
'id': dm.id,
'created_at': dm.created_at,
'sender_screen_name': dm.sender_screen_name,
'recipient_screen_name': dm.recipient_screen_name,
'text': dm.text,
'entities': getattr(dm, 'entities', None),
}
defaults.update(**kwargs)
return DirectMessage(**defaults)
def _to_user(user, **kwargs):
"""
Convert a `tweepy.User` to a `turses.models.User`.
"""
defaults = {
'id': user.id,
'name': user.name,
'screen_name': user.screen_name,
'description': user.description,
'url': user.url,
'created_at': user.created_at,
'friends_count': user.friends_count,
'followers_count': user.followers_count,
'favorites_count': user.favourites_count,
}
if hasattr(user, 'status'):
status = _to_status(user.status, user=user.screen_name)
defaults['status'] = status
defaults.update(**kwargs)
return User(**defaults)
def _to_list(a_list, **kwargs):
"""
Convert a `tweepy.List` to a `turses.models.List`.
"""
defaults = {
'id': a_list.id,
'owner': _to_user(a_list.user),
# TODO: `created_at` should be a datetime object
'created_at': a_list.created_at,
'name': a_list.name,
'slug': a_list.slug,
'description': a_list.description,
'member_count': a_list.member_count,
'subscriber_count': a_list.subscriber_count,
'private': a_list.mode == u'private',
}
defaults.update(**kwargs)
return List(**defaults)
to_status = partial(filter_result,
filter_func=_to_status)
to_direct_message = partial(filter_result,
filter_func=_to_direct_message)
to_user = partial(filter_result,
filter_func=_to_user)
to_list = partial(filter_result,
filter_func=_to_list)
class TweepyApi(BaseTweepyApi, ApiAdapter):
"""
A :class:`turses.api.ApiAdapter` implementation using `tweepy` library.
http://github.com/tweepy/tweepy/
"""
def __init__(self, *args, **kwargs):
ApiAdapter.__init__(self, *args, **kwargs)
# from `turses.api.base.ApiAdapter`
def init_api(self):
oauth_handler = TweepyOAuthHandler(self._consumer_key,
self._consumer_secret,
secure=configuration.twitter['use_https'])
oauth_handler.set_access_token(self._access_token_key,
self._access_token_secret)
self._api = BaseTweepyApi(oauth_handler, secure=configuration.twitter['use_https'])
@to_user
def verify_credentials(self):
return self._api.me()
@to_user
@include_entities
def get_user(self, screen_name, **kwargs):
return self._api.get_user(screen_name=screen_name, **kwargs)
# timelines
@to_status
@include_entities
def get_status(self, status_id, **kwargs):
return self._api.get_status(status_id, **kwargs)
@to_status
@include_entities
def get_home_timeline(self, **kwargs):
tweets = self._api.home_timeline(**kwargs)
return tweets
@to_status
@include_entities
def get_user_timeline(self, screen_name, **kwargs):
return self._api.user_timeline(screen_name, **kwargs)
@to_status
@include_entities
def get_own_timeline(self, **kwargs):
me = self.verify_credentials()
return self._api.user_timeline(screen_name=me.screen_name, **kwargs)
@to_status
@include_entities
def get_mentions(self, **kwargs):
return self._api.mentions_timeline(**kwargs)
@to_status
@include_entities
def get_favorites(self, **kwargs):
return self._api.favorites(**kwargs)
@to_direct_message
@include_entities
def get_direct_messages(self, **kwargs):
dms = self._api.direct_messages(**kwargs)
sent = self._api.sent_direct_messages(**kwargs)
dms.extend(sent)
return dms
@include_entities
def get_thread(self, status, **kwargs):
"""
Get the conversation to which `status` belongs.
"""
users_in_conversation = [status.authors_username]
# Save the users that are mentioned
for user in status.mentioned_usernames:
if user not in users_in_conversation:
users_in_conversation.append(user)
# Fetch the tweets from participants before and after `status`
# was published
tweets_from_participants = []
for user in users_in_conversation:
user_tweets = self._get_older_and_newer_tweets(user, status.id)
tweets_from_participants.extend(user_tweets)
def belongs_to_conversation(tweet):
for user in users_in_conversation:
if user in tweet.text:
return True
return filter(belongs_to_conversation, tweets_from_participants)
def _get_older_and_newer_tweets(self, screen_name, tweet_id, count=20):
"""
Get tweets from the user with `screen_name` username that are older
and newer than `tweet_id`.
By default, 20 tweets are fetched. If provided, `count` controls how
many tweets are requested.
"""
older = self.get_user_timeline(screen_name,
max_id=tweet_id,
count=count/2)
newer = self.get_user_timeline(screen_name,
since_id=tweet_id,
count=count/2)
return older + newer
def get_message_thread(self, dm, **kwargs):
messages = self.get_direct_messages(**kwargs)
me = self.verify_credentials()
if dm.sender_screen_name == me.screen_name:
with_user = dm.recipient_screen_name
else:
with_user = dm.sender_screen_name
def belongs_to_conversation(message):
return (message.sender_screen_name == with_user or
message.recipient_screen_name == with_user)
return filter(belongs_to_conversation, messages)
@to_status
@include_entities
def search(self, text, **kwargs):
return self._api.search(text, **kwargs)
@to_status
@include_entities
def get_retweets_of_me(self, **kwargs):
return self._api.retweets_of_me(**kwargs)
def update(self, text):
self._api.update_status(text)
def reply(self, status, text):
self._api.update_status(text, in_reply_to_status_id=status.id)
def destroy_status(self, status):
self._api.destroy_status(status.id)
def retweet(self, status):
self._api.retweet(status.id)
def direct_message(self, username, text):
self._api.send_direct_message(user=username, text=text)
def destroy_direct_message(self, dm):
self._api.destroy_direct_message(dm.id)
def create_friendship(self, screen_name):
self._api.create_friendship(screen_name=screen_name)
def destroy_friendship(self, screen_name):
self._api.destroy_friendship(screen_name=screen_name)
def create_favorite(self, status):
self._api.create_favorite(status.id)
def destroy_favorite(self, status):
self._api.destroy_favorite(status.id)
# list methods
@to_list
def get_lists(self, screen_name):
return self._api.lists_all(screen_name)
@to_list
def get_own_lists(self):
return self._api.lists_all()
@to_list
def get_list_memberships(self):
return self._api.lists_memberships()
@to_list
def get_list_subscriptions(self):
return self._api.lists_subscriptions()
@to_status
def get_list_timeline(self, a_list):
owner = a_list.owner.screen_name
return self._api.list_timeline(owner=owner, slug=a_list.slug)
@to_user
def get_list_members(self, a_list):
owner = a_list.owner.screen_name
return self._api.list_members(owner=owner, slug=a_list.slug)
@to_list
def subscribe_to_list(self, a_list):
owner = a_list.owner
return self._api.subscribe_list(owner=owner.screen_name,
slug=a_list.slug)
@to_user
def get_list_subscribers(self, a_list):
owner = a_list.owner
return self._api.list_subscribers(owner=owner.screen_name,
slug=a_list.slug,)

BIN
turses/pkg/turses/usr/lib/python2.7/site-packages/turses/api/backends.pyc

Binary file not shown.

BIN
turses/pkg/turses/usr/lib/python2.7/site-packages/turses/api/backends.pyo

Binary file not shown.

469
turses/pkg/turses/usr/lib/python2.7/site-packages/turses/api/base.py

@ -0,0 +1,469 @@ @@ -0,0 +1,469 @@
# -*- coding: utf-8 -*-
"""
This module contains an `ApiAdapter` abstract class that acts as an adapter
for different Twitter API implementations.
It also contains `AsyncApi`, an asynchronous wrapper to `ApiAdapter` and a
function to authorize `turses` to use a Twitter account obtaining the OAuth
tokens.
"""
from ssl import SSLError
from abc import ABCMeta, abstractmethod
import oauth2 as oauth
from urlparse import parse_qsl, urljoin
from gettext import gettext as _
from turses.models import is_DM
from turses.utils import encode
from turses.meta import async, wrap_exceptions
TWITTER_CONSUMER_KEY = 'OEn4hrNGknVz9ozQytoR0A'
TWITTER_CONSUMER_SECRET = 'viud49uVgdVO9dnOGxSQJRo7jphTioIlEn3OdpkZI'
BASE_URL = 'https://api.twitter.com'
HTTP_OK = 200
def get_authorization_tokens():
"""
Authorize `turses` to use a Twitter account.
Return a dictionary with `oauth_token` and `oauth_token_secret` keys
if succesfull, `None` otherwise.
"""
# This function was borrowed from python-twitter developers and experienced
# an important refactoring
#
# Copyright 2007 The Python-Twitter Developers
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
oauth_consumer = oauth.Consumer(key=TWITTER_CONSUMER_KEY,
secret=TWITTER_CONSUMER_SECRET)
oauth_client = oauth.Client(oauth_consumer)
print _('Requesting temporary token from Twitter')
try:
oauth_token, oauth_token_secret = get_temporary_tokens(oauth_client)
except SSLError:
print _("""There was an SSL certificate error, your user may not have
permission to access SSL. Try executing `turses` as a
privileged user.""")
return None
except Exception as e:
print e
return None
authorization_url = urljoin(BASE_URL, '/oauth/authorize')
authorization_url_with_token = urljoin(authorization_url,
'?oauth_token=%s' % oauth_token)
print
print _('Please visit the following page to retrieve the pin code needed '
'to obtain an Authorization Token:')
print
print authorization_url_with_token
print
pin_code = raw_input(_('Pin code? '))
print
print encode(_('Generating and signing request for an access token'))
print
# Generate an OAuth token that verifies the identity of the user
token = oauth.Token(oauth_token, oauth_token_secret)
token.set_verifier(pin_code)
# Re-create the OAuth client with the corresponding token
oauth_client = oauth.Client(oauth_consumer, token)
try:
access_tokens = get_access_tokens(oauth_client, pin_code)
return access_tokens
except Exception as e:
print e
return None
def get_temporary_tokens(oauth_client):
"""
Request temporary OAuth tokens using the provided `oauth_client`; these
tokens require the user to confirm its identity on Twitter's website for
obtaining an access token.
This function will return a tuple with a public and a private OAuth tokens
that can be used to retrieve an access token from Twitter if the request
was successfull.
If there is an error with the HTTP request, it will raise an
:class:`Exception` with a meaningful error message.
"""
request_token_url = urljoin(BASE_URL, '/oauth/request_token')
response, content = oauth_client.request(request_token_url, 'GET')
status_code = int(response['status'])
if status_code == HTTP_OK:
response_content = dict(parse_qsl(content))
oauth_token = response_content['oauth_token']
oauth_token_secret = response_content['oauth_token_secret']
return (oauth_token, oauth_token_secret)
else:
error_message = _('Twitter responded with an HTTP %s code.' % str(status_code))
raise Exception(error_message)
def get_access_tokens(oauth_client, pin_code):
"""
Request access tokens using the provided `oauth_client` and the
`pin_code`that verifies the user's identity.
This function will return a dictionary with `oauth_token` and
`oauth_token_secret` keys if the request was successful.
If there is an error with the HTTP request, it will raise an
:class:`Exception` with a meaningful error message.
"""
access_token_url = urljoin(BASE_URL, '/oauth/access_token')
response, content = oauth_client.request(access_token_url,
method='POST',
body='oauth_verifier=%s' % pin_code)
status_code = int(response['status'])
if status_code == HTTP_OK:
access_token = dict(parse_qsl(content))
return access_token
else:
error_message = _('Twitter responded with an HTTP %s code.' % str(status_code))
raise Exception(error_message)
class ApiAdapter(object):
"""
A simplified version of the API to use as an adapter for a real
implementation.
"""
__metaclass__ = ABCMeta
def __init__(self,
access_token_key,
access_token_secret,
consumer_key=TWITTER_CONSUMER_KEY,
consumer_secret=TWITTER_CONSUMER_SECRET,):
self._consumer_key = consumer_key
self._consumer_secret = consumer_secret
self._access_token_key = access_token_key
self._access_token_secret = access_token_secret
self.is_authenticated = False
@abstractmethod
def init_api(self):
pass
@abstractmethod
def verify_credentials(self):
"""
Return a `turses.models.User` with the authenticating user if the given
credentials are valid.
"""
pass
# users
@abstractmethod
def get_user(self, screen_name):
pass
# timelines
@abstractmethod
def get_status(self, status_id):
pass
@abstractmethod
def get_home_timeline(self):
pass
@abstractmethod
def get_user_timeline(self, screen_name):
pass
@abstractmethod
def get_own_timeline(self):
pass
@abstractmethod
def get_mentions(self):
pass
@abstractmethod
def get_favorites(self):
pass
@abstractmethod
def get_direct_messages(self):
pass
@abstractmethod
def get_thread(self, status):
pass
@abstractmethod
def get_message_thread(self, dm):
pass
@abstractmethod
def search(self, text):
pass
@abstractmethod
def get_retweets_of_me(self):
pass
# statuses
@abstractmethod
def update(self, text):
pass
@abstractmethod
def reply(self, status, text):
pass
@abstractmethod
def retweet(self, status):
pass
@abstractmethod
def destroy_status(self, status):
"""
Destroy the given `status` (must belong to authenticating user).
"""
pass
@abstractmethod
def direct_message(self, screen_name, text):
pass
@abstractmethod
def destroy_direct_message(self, dm):
"""
Destroy the given `dm` (must be written by the authenticating user).
"""
pass
# friendship
@abstractmethod
def create_friendship(self, screen_name):
pass
@abstractmethod
def destroy_friendship(self, screen_name):
pass
# favorite methods
@abstractmethod
def create_favorite(self, status):
pass
@abstractmethod
def destroy_favorite(self, status):
pass
# list methods
@abstractmethod
def get_lists(self, screen_name):
pass
@abstractmethod
def get_own_lists(self):
pass
@abstractmethod
def get_list_memberships(self):
pass
@abstractmethod
def get_list_subscriptions(self):
pass
@abstractmethod
def get_list_timeline(self, list):
pass
@abstractmethod
def get_list_members(self, list):
pass
@abstractmethod
def subscribe_to_list(self, list):
pass
@abstractmethod
def get_list_subscribers(self, list):
pass
class AsyncApi(ApiAdapter):
"""
Wrap an `ApiAdapter` subclass and execute the methods for creating,
updating and deleting Twitter entities in background. Those methods
are decorated with `turses.utils.wrap_exceptions`.
"""
def __init__(self, api_cls, *args, **kwargs):
"""
Args:
api_cls -- the class used to instantiate the Twitter API,
it must implement the methods in `ApiAdapter`.
"""
ApiAdapter.__init__(self, *args, **kwargs)
self._api = api_cls(access_token_key=self._access_token_key,
access_token_secret=self._access_token_secret,)
@wrap_exceptions
def init_api(self):
self._api.init_api()
self.is_authenticated = True
self.user = self.verify_credentials()
def verify_credentials(self):
return self._api.verify_credentials()
def get_status(self, **kwargs):
return self._api.get_status(**kwargs)
def get_home_timeline(self, **kwargs):
return self._api.get_home_timeline(**kwargs)
def get_user_timeline(self, screen_name, **kwargs):
return self._api.get_user_timeline(screen_name=screen_name, **kwargs)
def get_own_timeline(self, **kwargs):
return self._api.get_own_timeline(**kwargs)
def get_mentions(self, **kwargs):
return self._api.get_mentions()
def get_favorites(self, **kwargs):
return self._api.get_favorites()
def get_direct_messages(self, **kwargs):
return self._api.get_direct_messages(**kwargs)
def get_thread(self, status, **kwargs):
return self._api.get_thread(status, **kwargs)
def get_message_thread(self, dm, **kwargs):
return self._api.get_message_thread(dm, **kwargs)
def search(self, text, **kwargs):
return self._api.search(text, **kwargs)
def get_retweets_of_me(self, **kwargs):
return self._api.get_retweets_of_me(**kwargs)
def get_user(self, screen_name):
return self._api.get_user(screen_name)
@async
@wrap_exceptions
def update(self, text):
self._api.update(text)
@async
@wrap_exceptions
def reply(self, status, text):
self._api.reply(status, text)
@async
@wrap_exceptions
def retweet(self, status):
self._api.retweet(status)
@async
@wrap_exceptions
def destroy_status(self, status):
self._api.destroy_status(status)
@async
@wrap_exceptions
def destroy_direct_message(self, status):
self._api.destroy_direct_message(status)
@async
@wrap_exceptions
def direct_message(self, screen_name, text):
self._api.direct_message(screen_name, text)
@async
@wrap_exceptions
def create_friendship(self, screen_name):
self._api.create_friendship(screen_name)
@async
@wrap_exceptions
def destroy_friendship(self, screen_name):
self._api.destroy_friendship(screen_name)
@async
@wrap_exceptions
def create_favorite(self, status):
if is_DM(status) or status.is_favorite:
raise Exception
self._api.create_favorite(status)
@async
@wrap_exceptions
def destroy_favorite(self, status):
self._api.destroy_favorite(status)
def get_list(self, screen_name, slug):
pass
def get_lists(self, screen_name):
pass
def get_own_lists(self):
pass
def get_list_memberships(self):
pass
def get_list_subscriptions(self):
pass
def get_list_timeline(self, list):
pass
def get_list_members(self, list):
pass
def subscribe_to_list(self, list):
pass
def get_list_subscribers(self, list):
pass

BIN
turses/pkg/turses/usr/lib/python2.7/site-packages/turses/api/base.pyc

Binary file not shown.

BIN
turses/pkg/turses/usr/lib/python2.7/site-packages/turses/api/base.pyo

Binary file not shown.

199
turses/pkg/turses/usr/lib/python2.7/site-packages/turses/api/debug.py

@ -0,0 +1,199 @@ @@ -0,0 +1,199 @@
# -*- coding: utf-8 -*-
"""
Contains `MockApi`, a fake `turses.api.ApiAdapter` implementation for debugging
purposes.
"""
import random
from time import sleep
from datetime import datetime
from turses.models import User, Status
from turses.meta import wrap_exceptions
from turses.api.base import ApiAdapter
def random_status(quantity=1, **kwargs):
"""Return `quantity` random statuses.
By default it returns a single `turses.models.Status` instance, but
if `q` is greater than 1 it returns a list of random statuses."""
def create_status():
sleep(0.02)
now = datetime.now()
defaults = {
'id': random.randint(0, 999),
'created_at': now,
'user': 'testbot',
'text': 'Status created at %s' % now,
}
defaults.update(**kwargs)
return Status(**defaults)
if not quantity:
return
if quantity == 1:
return create_status()
return [create_status() for _ in range(0, quantity)]
def random_user(quantity=1, **kwargs):
"""Return `quantity` random users.
By default it returns a single `turses.models.user` instance, but
if `q` is greater than 1 it returns a list of random users."""
def create_user():
sleep(0.02)
now = datetime.now()
defaults = {
'id': random.randint(0, 999),
'name': 'Alejandro',
'screen_name': 'dialelo',
'description': None,
'url': 'http://dialelo.com',
'created_at': now,
'friends_count': 3,
'followers_count': 42,
'favorites_count': 0,
'status': random_status(),
}
defaults.update(**kwargs)
return User(**defaults)
if not quantity:
return
if quantity == 1:
return create_user()
return [create_user() for _ in range(0, quantity)]
class MockApi(ApiAdapter):
"""
"""
def __init__(self, *args, **kwargs):
ApiAdapter.__init__(self, *args, **kwargs)
@wrap_exceptions
def init_api(self):
self.is_authenticated = True
def verify_credentials(self):
return random_user()
# users
def get_user(self, screen_name):
return random_user(screen_name=screen_name)
# timelines
def get_status(self, status_id):
return random_status(id=status_id)
def get_home_timeline(self):
return random_status(quantity=3)
def get_user_timeline(self, screen_name):
return random_status(quantity=10)
def get_own_timeline(self):
return random_status(quantity=10)
def get_mentions(self):
return random_status(quantity=10)
def get_favorites(self):
return random_status(quantity=10)
def get_direct_messages(self):
# TODO: random DM
return random_status(quantity=10)
def get_thread(self, status):
return random_status(quantity=14)
def get_message_thread(self, status):
return random_status(quantity=4)
def search(self, text):
return random_status(quantity=14)
def get_retweets_of_me(self):
return random_status(quantity=14)
# statuses
def update(self, text):
pass
def reply(self, status, text):
pass
def retweet(self, status):
pass
def destroy_status(self, status):
"""
Destroy the given `status` (must belong to authenticating user).
"""
pass
def direct_message(self, screen_name, text):
pass
def destroy_direct_message(self, dm):
"""
Destroy the given `dm` (must be written by the authenticating user).
"""
pass
# friendship
def create_friendship(self, screen_name):
pass
def destroy_friendship(self, screen_name):
pass
# favorite methods
def create_favorite(self, status):
pass
def destroy_favorite(self, status):
pass
# list methods
def get_lists(self, screen_name):
pass
def get_own_lists(self):
pass
def get_list_memberships(self):
pass
def get_list_subscriptions(self):
pass
def get_list_timeline(self, list):
pass
def get_list_members(self, list):
pass
def subscribe_to_list(self, list):
pass
def get_list_subscribers(self, list):
pass

BIN
turses/pkg/turses/usr/lib/python2.7/site-packages/turses/api/debug.pyc

Binary file not shown.

BIN
turses/pkg/turses/usr/lib/python2.7/site-packages/turses/api/debug.pyo

Binary file not shown.

149
turses/pkg/turses/usr/lib/python2.7/site-packages/turses/api/helpers.py

@ -0,0 +1,149 @@ @@ -0,0 +1,149 @@
"""
This module contains various methods for checking the type of timelines and a
class that creates all kinds of timelines.
"""
import re
from functools import partial
from gettext import gettext as _
from turses.models import Timeline, is_DM
HOME_TIMELINE = 'home'
MENTIONS_TIMELINE = 'mentions'
FAVORITES_TIMELINE = 'favorites'
MESSAGES_TIMELINE = 'messages'
OWN_TWEETS_TIMELINE = 'own_tweets'
DEFAULT_TIMELINES = [
HOME_TIMELINE,
MENTIONS_TIMELINE,
FAVORITES_TIMELINE,
MESSAGES_TIMELINE,
OWN_TWEETS_TIMELINE,
]
def check_update_function_name(timeline, update_function_name=None):
if not isinstance(timeline, Timeline):
return False
update_function = timeline.update_function
if update_function is None:
return False
return update_function.__name__ == update_function_name
is_home_timeline = partial(check_update_function_name,
update_function_name='get_home_timeline')
is_mentions_timeline = partial(check_update_function_name,
update_function_name='get_mentions')
is_favorites_timeline = partial(check_update_function_name,
update_function_name='get_favorites')
is_own_timeline = partial(check_update_function_name,
update_function_name='get_own_timeline')
is_messages_timeline = partial(check_update_function_name,
update_function_name='get_direct_messages')
is_search_timeline = partial(check_update_function_name,
update_function_name='search')
is_user_timeline = partial(check_update_function_name,
update_function_name='get_user_timeline')
is_retweets_of_me_timeline = partial(check_update_function_name,
update_function_name='get_retweets_of_me')
is_thread_timeline = partial(check_update_function_name,
update_function_name='get_thread')
search_name_re = re.compile(r'^search:(?P<query>.+)$')
hashtag_name_re = re.compile(r'^hashtag:(?P<query>.+)$')
user_name_re = re.compile(r'^user:(?P<screen_name>[A-Za-z0-9_]+)$')
class TimelineFactory:
def __init__(self, api):
self.api = api
def __call__(self, timeline_string):
timeline = timeline_string.strip()
if timeline == HOME_TIMELINE:
return Timeline(name=_('tweets'),
update_function=self.api.get_home_timeline,)
elif timeline == MENTIONS_TIMELINE:
return Timeline(name=_('mentions'),
update_function=self.api.get_mentions,)
elif timeline == FAVORITES_TIMELINE:
return Timeline(name=_('favorites'),
update_function=self.api.get_favorites,)
elif timeline == MESSAGES_TIMELINE:
return Timeline(name=_('messages'),
update_function=self.api.get_direct_messages,)
elif timeline == OWN_TWEETS_TIMELINE:
return Timeline(name=_('me'),
update_function=self.api.get_own_timeline,)
elif timeline == 'retweets_of_me':
return Timeline(name=_('retweets of me'),
update_function=self.api.get_retweets_of_me,)
is_search = search_name_re.match(timeline)
if is_search:
query = is_search.groupdict()['query']
return Timeline(name=_('Search: %s' % query),
update_function=self.api.search,
update_function_args=query,)
is_hashtag = hashtag_name_re.match(timeline)
if is_hashtag:
query = "#{}".format(is_hashtag.groupdict()['query'])
return Timeline(name=_('hashtag: %s' % query),
update_function=self.api.search,
update_function_args=query,)
is_user = user_name_re.match(timeline)
if is_user:
screen_name = is_user.groupdict()['screen_name']
timeline_name = _('@{screen_name}'.format(screen_name=screen_name))
return Timeline(name=timeline_name,
update_function=self.api.get_user_timeline,
update_function_args=screen_name,)
def valid_timeline_name(self, name):
if name in DEFAULT_TIMELINES:
return True
if name == 'retweets_of_me':
return True
# search
if search_name_re.match(name):
return True
# user
if user_name_re.match(name):
return True
return False
def thread(self, status):
"""
Create a timeline with the conversation to which `status` belongs.
`status` can be a regular status or a direct message.
"""
if is_DM(status):
participants = [status.sender_screen_name,
status.recipient_screen_name]
name = _('DM thread: %s' % ', '.join(participants))
update_function = self.api.get_message_thread
else:
participants = status.mentioned_usernames
author = status.authors_username
if author not in participants:
participants.insert(0, author)
name = _('thread: %s' % ', '.join(participants))
update_function = self.api.get_thread
return Timeline(name=name,
update_function=update_function,
update_function_args=status,)

BIN
turses/pkg/turses/usr/lib/python2.7/site-packages/turses/api/helpers.pyc

Binary file not shown.

BIN
turses/pkg/turses/usr/lib/python2.7/site-packages/turses/api/helpers.pyo

Binary file not shown.

179
turses/pkg/turses/usr/lib/python2.7/site-packages/turses/cli.py

@ -0,0 +1,179 @@ @@ -0,0 +1,179 @@
# -*- coding: utf-8 -*-
"""
Handle the invocation of ``turses`` from the command line.
"""
import logging
from sys import stdout
from argparse import ArgumentParser
from os import getenv
from gettext import gettext as _
from urwid import set_encoding
from turses import __name__
from turses import version as turses_version
from turses.config import configuration, LOG_FILE
from turses.models import TimelineList
from turses.ui import CursesInterface
from turses.api.base import AsyncApi
from turses.api.debug import MockApi
from turses.api.backends import TweepyApi
from turses.core import Controller as Turses
def save_stdout():
"""Save shell screen."""
stdout.write("\033[?1049h\033[H")
def restore_stdout():
"""Restore saved shell screen."""
stdout.write("\033[?1049l")
def set_title(string):
"""Set window title."""
try:
if getenv('TERM').startswith("screen"):
# terminal multiplexors
if getenv('TMUX'):
stdout.write("\033k%s\033\\" % string) # for tmux
else:
stdout.write("\033_%s\033\\" % string) # for GNU screen
else:
# terminal
stdout.write("\x1b]2;%s\x07" % string)
except:
pass
def restore_title():
"""Restore original window title."""
if getenv('TMUX'):
set_title(getenv('SHELL').split('/')[-1])
def create_async_api(api_backend_cls):
"""
Create an asynchronous API given a concrete API class ``api_backend_cls``.
"""
oauth_token = configuration.oauth_token
oauth_token_secret = configuration.oauth_token_secret
return AsyncApi(api_backend_cls,
access_token_key=oauth_token,
access_token_secret=oauth_token_secret,)
def read_arguments():
"""Read arguments from the command line."""
parser_title = "turses: Twitter client featuring a sexy curses interface."
parser = ArgumentParser(parser_title)
# load account
parser.add_argument("-a",
"--account",
help=_("Use account with the specified username."))
# load non-default configuration
parser.add_argument("-c",
"--config",
help=_("Use the specified configuration file."))
# generate configuration
generate_config_help = _("Generate a default configuration file is "
"the specified path.")
parser.add_argument("-g",
"--generate-config",
help=generate_config_help)
# load session
parser.add_argument("-s",
"--session",
help=_("Load the specified session"))
# version
version = "turses %s" % turses_version
parser.add_argument("-v",
"--version",
action="version",
version=version,
help=_("Show the current version of turses"))
# debug mode
parser.add_argument("-d",
"--debug",
action="store_true",
help=_("Start turses in debug mode."))
# offline debug mode
parser.add_argument("-o",
"--offline",
action="store_true",
help=_("Start turses in offline debug mode."))
args = parser.parse_args()
return args
def main():
"""
Launch ``turses``.
"""
set_title(__name__)
set_encoding('utf8')
args = read_arguments()
# check if stdout has to be restored after program exit
if any([args.debug,
args.offline,
getattr(args, 'help', False),
getattr(args, 'version', False)]):