andreped commited on
Commit
05af501
·
1 Parent(s): 2c6e974

Implemented postly client

Browse files
postly/__init__.py ADDED
File without changes
postly/clients/__init__.py ADDED
File without changes
postly/clients/postly_client.py ADDED
@@ -0,0 +1,144 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import re
2
+ from collections import Counter
3
+ from typing import List
4
+
5
+ from ..common.models import Post
6
+
7
+
8
+ class PostlyClient:
9
+ """
10
+ The Postly service interface.
11
+
12
+ This allows adding and deleting users, adding, and retrieving posts
13
+ and getting trending topics.
14
+ """
15
+
16
+ def __init__(self) -> None:
17
+ self.userPosts = {}
18
+ self.post_max_length = 140
19
+ self.timestamp_iter = 0
20
+
21
+ @staticmethod
22
+ def get_topics_from_post(post: str) -> List[str]:
23
+ """
24
+ Get topics from post.
25
+
26
+ Args:
27
+ post: The post to extract topics from.
28
+ Returns:
29
+ A list of topics.
30
+ """
31
+ return re.findall(pattern=r"#(\w+)", string=post)
32
+
33
+ def add_user(self, user_name: str) -> None:
34
+ """
35
+ Add new user to system.
36
+
37
+ Args:
38
+ user_name: The name of the user to add.
39
+ Returns:
40
+ None
41
+ """
42
+ self.userPosts[user_name] = []
43
+
44
+ def add_post(self, user_name: str, post_text: str, timestamp: int) -> None:
45
+ """
46
+ Add new post to the user's post history.
47
+
48
+ Args:
49
+ user_name: The name of the user to add the post to.
50
+ post_text: The text of the post.
51
+ timestamp: The timestamp of the post.
52
+ Returns:
53
+ None
54
+ """
55
+ if user_name not in self.userPosts:
56
+ raise KeyError(f"User {user_name} not found.")
57
+
58
+ if len(post_text) > self.post_max_length:
59
+ raise RuntimeError("Post is too long")
60
+
61
+ if not post_text.strip():
62
+ raise ValueError("Post cannot be empty.")
63
+
64
+ if not isinstance(timestamp, int) or timestamp < 0:
65
+ raise ValueError("Timestamp must be a non-negative integer.")
66
+
67
+ self.timestamp_iter += 1
68
+ curr_topics = self.get_topics_from_post(post_text)
69
+
70
+ self.userPosts[user_name].append(Post(content=post_text, timestamp=self.timestamp_iter, topics=curr_topics))
71
+
72
+ def delete_user(self, user_name: str) -> None:
73
+ """
74
+ Delete user from system.
75
+
76
+ Args:
77
+ user_name: The name of the user to delete.
78
+ Returns:
79
+ None
80
+ """
81
+ if user_name not in self.userPosts:
82
+ raise KeyError(f"User '{user_name}' not found.")
83
+
84
+ self.userPosts.pop(user_name, None)
85
+
86
+ def get_posts_for_user(self, user_name: str) -> List[str]:
87
+ """
88
+ Get all posts for user, sorted by timestamp in descending order.
89
+
90
+ Args:
91
+ user_name: The name of the user to retrieve posts for.
92
+ Returns:
93
+ A list of posts.
94
+ """
95
+ if user_name not in self.userPosts:
96
+ raise KeyError(f"User '{user_name} not found.")
97
+
98
+ return [post_data.content for post_data in self.userPosts[user_name][::-1]]
99
+
100
+ def get_posts_for_topic(self, topic: str) -> List[str]:
101
+ """
102
+ Get all posts for topic.
103
+
104
+ Args:
105
+ topic: The topic to retrieve posts for.
106
+ Returns:
107
+ A list of posts.
108
+ """
109
+ matched_posts = []
110
+ for user in self.userPosts:
111
+ for post_data in self.userPosts[user]:
112
+ if topic in post_data.topics:
113
+ matched_posts.append(post_data.content)
114
+
115
+ return matched_posts
116
+
117
+ def get_trending_topics(self, from_timestamp: int, to_timestamp: int) -> List[str]:
118
+ """
119
+ Get all trending topics within a time interval.
120
+
121
+ Args:
122
+ from_timestamp: The start of the time interval.
123
+ to_timestamp: The end of the time interval.
124
+ Returns:
125
+ A list of topics.
126
+ """
127
+ if not isinstance(from_timestamp, int) or from_timestamp < 0:
128
+ raise ValueError("from_timestamp must be a non-negative integer.")
129
+
130
+ if not isinstance(to_timestamp, int) or to_timestamp < 0:
131
+ raise ValueError("to_timestamp must be a non-negative integer.")
132
+
133
+ if from_timestamp > to_timestamp:
134
+ raise ValueError("from_timestamp cannot be greater than to_timestamp.")
135
+
136
+ # construct topic histogram
137
+ topics_frequency = Counter()
138
+ for user in self.userPosts:
139
+ for post_data in self.userPosts[user]:
140
+ if from_timestamp <= post_data.timestamp <= to_timestamp:
141
+ topics_frequency.update(post_data.topics)
142
+
143
+ # retriev top topics in descending order
144
+ return [topic for topic, _ in topics_frequency.most_common()]