This repository has been archived by the owner on Dec 21, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
447 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,139 @@ | ||
# relationships | ||
relationships | ||
--- | ||
redis backed user relationships on it's simplest form. | ||
|
||
####installation | ||
|
||
```bash | ||
$ [sudo] pip install relationships | ||
``` | ||
or if you like 90s: | ||
```bash | ||
$ [sudo] easy_install relationships | ||
``` | ||
|
||
####usage | ||
|
||
**getting the Relationship class** | ||
|
||
```python | ||
from relationships import Relationship | ||
r = Relationship() | ||
``` | ||
|
||
**follow** | ||
|
||
```python | ||
|
||
r('Guido').follow('Rasmus') | ||
r('Guido').follow('Larry') | ||
r('Larry').follow('Guido') | ||
r('Rasmus').follow('Guido') | ||
r('Dave').follow('Guido') | ||
r('Larry').follow('Guido') | ||
|
||
``` | ||
|
||
**unfollow** | ||
|
||
```python | ||
r('Guido').unfollow("Rasmus") | ||
``` | ||
|
||
**block** | ||
```python | ||
r('Guido').block("Guido") | ||
r('Rasmus').block("Guido") | ||
``` | ||
|
||
**unblock** | ||
```python | ||
r('Rasmus').unblock('Guido') | ||
``` | ||
|
||
**getting friends** | ||
```python | ||
r('Guido').friends() | ||
``` | ||
|
||
```bash | ||
>>> {'Larry', 'Rasmus'} | ||
``` | ||
|
||
**getting followers** | ||
|
||
```python | ||
r("Guido").followers() | ||
``` | ||
|
||
```bash | ||
>>> {'Dave', 'Larry', 'Rasmus'} | ||
``` | ||
**getting followings** | ||
|
||
```python | ||
r("Guido").following() | ||
``` | ||
|
||
```bash | ||
>>> {'Larry', 'Rasmus'} | ||
``` | ||
**getting a simple graph of spesific user** | ||
```python | ||
|
||
r('Zlatan Ibrahimovic').follow("Galatasaray") | ||
r('Galatasaray').follow("Zlatan Ibrahimovic") | ||
r('Galatasaray').follow("Podolski") | ||
r('Galatasaray').follow("Drogba") | ||
r('Galatasaray').follow("Sneijder") | ||
r('Galatasaray').follow("Zlatan Ibrahimovic") | ||
r('Sneijder').follow("Galatasaray") | ||
r('Podolski').follow("Galatasaray") | ||
|
||
r("Galatasaray").get_network("/tmp/galatasaray_network.png") | ||
``` | ||
|
||
<img src="http://i.imgur.com/HakrxvJ.png"> | ||
|
||
|
||
**getting block list by user** | ||
|
||
```python | ||
# people blocked by guido | ||
r('Guido').blocks() | ||
``` | ||
|
||
```bash | ||
>>> {'Rasmus'} | ||
``` | ||
|
||
**getting blocked list by user** | ||
|
||
```python | ||
# people who blocked Guido | ||
r('Guido').blocked() | ||
``` | ||
|
||
```bash | ||
>>> {'Rasmus'} | ||
``` | ||
|
||
**counts** | ||
```python | ||
r('Guido').block_count() # count of people blocked by Guido | ||
r('Guido').blocked_count() # count of people who blocked Guido | ||
|
||
r('Guido').follower_count() # count of people who follows Guido | ||
r('Guido').following_count() # count of people following by Guido | ||
``` | ||
|
||
**checks** | ||
|
||
```python | ||
r('Guido').is_following('Rasmus') # does Guido follows Rasmus? | ||
r('Rasmus').is_follower('Guido') # is Rasmus a follower of Guido? | ||
|
||
r('Guido').is_blocked('Rasmus') # did Guido blocked Rasmus? | ||
r('Rasmus').is_blocked_by('Guido') # is Rasmus blocked by Guido? | ||
``` | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
from relationship import Relationship | ||
|
||
__version__ = '0.0.1' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
|
||
# list of keys will be used on redis. can be | ||
|
||
key_list = { | ||
"following": "following", | ||
"followers": "followers", | ||
"blocked": "blocked", | ||
"blocked_by": "blocked_by", | ||
"prefix": "relationships", | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
|
||
import redis | ||
|
||
from keys import key_list as default_key_list | ||
|
||
|
||
class Relationship(object): | ||
|
||
def __init__(self, redis_connection=None, key_list=None, actor=None): | ||
|
||
if key_list: | ||
default_key_list.update(key_list) | ||
|
||
self.key_list = default_key_list | ||
|
||
if redis_connection: | ||
self.redis_connection = redis_connection | ||
else: | ||
self.redis_connection = redis.StrictRedis( | ||
host='localhost', | ||
port=6379, | ||
db=0 | ||
) | ||
|
||
self.actor = actor | ||
|
||
def __call__(self, *args, **kwargs): | ||
|
||
self.actor = args[0] | ||
|
||
return self | ||
|
||
def _action_call(self, command, from_id, to_id, operation_key): | ||
command_values = ':'.join(('user', str(from_id), operation_key)), to_id | ||
return getattr(self.redis_connection, command)(*command_values) | ||
|
||
def _list_call(self, operation_key): | ||
return self.redis_connection.smembers( | ||
'user:{}:{}'.format(self._get_actor(), operation_key) | ||
) | ||
|
||
def _count_call(self, operation_key): | ||
return self.redis_connection.scard( | ||
'user:{}:{}'.format( | ||
self._get_actor(), | ||
operation_key | ||
) | ||
) | ||
|
||
def _get_actor(self): | ||
if hasattr(self, 'actor'): | ||
return self.actor | ||
|
||
raise ValueError("actor is not defined") | ||
|
||
def block(self, to_id): | ||
|
||
self._action_call('sadd', self._get_actor(), to_id, self.key_list["blocked"]) | ||
self._action_call('sadd', to_id, self._get_actor(), self.key_list["blocked_by"]) | ||
|
||
def unblock(self, to_id): | ||
|
||
self._action_call('srem', self._get_actor(), to_id, self.key_list["blocked"]) | ||
self._action_call('srem', to_id, self._get_actor(), self.key_list["blocked_by"]) | ||
|
||
def follow(self, to_id): | ||
|
||
self._action_call('sadd', self._get_actor(), to_id, self.key_list["following"]) | ||
self._action_call('sadd', to_id, self._get_actor(), self.key_list["followers"]) | ||
|
||
def unfollow(self, to_id): | ||
|
||
self._action_call('srem', self._get_actor(), to_id, self.key_list["following"]) | ||
self._action_call('srem', to_id, self._get_actor(), self.key_list["followers"]) | ||
|
||
def friends(self): | ||
|
||
return self.redis_connection.sinter( | ||
"user:{}:{}".format(self._get_actor(), self.key_list["following"]), | ||
"user:{}:{}".format(self._get_actor(), self.key_list["followers"]), | ||
) | ||
|
||
def followers(self): | ||
return self._list_call(self.key_list["followers"]) | ||
|
||
def following(self): | ||
return self._list_call(self.key_list["following"]) | ||
|
||
def blocks(self): | ||
return self._list_call(self.key_list["blocked"]) | ||
|
||
def blocked(self): | ||
return self._list_call(self.key_list["blocked_by"]) | ||
|
||
def follower_count(self): | ||
return self._count_call(self.key_list["followers"]) | ||
|
||
def following_count(self): | ||
return self._count_call(self.key_list["following"]) | ||
|
||
def block_count(self): | ||
return self._count_call(self.key_list["blocked"]) | ||
|
||
def blocked_count(self): | ||
return self._count_call(self.key_list["blocked_by"]) | ||
|
||
def is_follower(self, follower_id): | ||
return self._action_call('sismember', self._get_actor(), follower_id, self.key_list["followers"]) | ||
|
||
def is_following(self, following_id): | ||
return self._action_call('sismember', self._get_actor(), following_id, self.key_list["following"]) | ||
|
||
def is_blocked(self, blocked_id): | ||
return self._action_call('sismember', self._get_actor(), blocked_id, self.key_list["blocked"]) | ||
|
||
def is_blocked_by(self, blocked_by_id): | ||
return self._action_call('sismember', self._get_actor(), blocked_by_id,self.key_list["blocked_by"]) | ||
|
||
def get_network(self, output): | ||
|
||
user_id = self._get_actor() | ||
|
||
try: | ||
import pydot | ||
except ImportError: | ||
raise ImportError("You need pydot library to get network functionality.") | ||
|
||
graph = pydot.Dot('network_of_user_{}'.format(user_id), graph_type='digraph') | ||
target_node = pydot.Node(user_id) | ||
|
||
for _id in self(user_id).following(): | ||
user_node = pydot.Node(_id) | ||
graph.add_edge(pydot.Edge(target_node, user_node)) | ||
|
||
for _id in self(user_id).followers(): | ||
user_node = pydot.Node(_id) | ||
graph.add_edge(pydot.Edge(user_node, target_node)) | ||
|
||
graph.write_png(output) | ||
|
Oops, something went wrong.