forked from FlxVctr/RADICES
-
Notifications
You must be signed in to change notification settings - Fork 0
/
setup.py
198 lines (169 loc) · 7.78 KB
/
setup.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
import json
from json import JSONDecodeError
import pandas as pd
from requests import post
import yaml
# General class for necessary file imports
class FileImport():
def read_app_key_file(self, filename: str = "keys.json") -> tuple:
"""Reads file with consumer key and consumer secret (JSON)
Args:
filename (str, optional): Defaults to "keys.json"
Returns:
Tuple with two strings: (1) being the twitter consumer token and (2) being the
twitter consumer secret
"""
# TODO: change return to dictionary
try:
with open(filename, "r") as f:
self.key_file = json.load(f)
except FileNotFoundError:
raise FileNotFoundError('"keys.json" could not be found')
except JSONDecodeError as e:
print("Bad JSON file. Please check that 'keys.json' is formatted\
correctly and that it is not empty")
raise e
if "consumer_token" not in self.key_file or "consumer_secret" not in self.key_file:
raise KeyError('''"keys.json" does not contain the dictionary keys
"consumer_token" and/or "consumer_secret"''')
if type(self.key_file["consumer_secret"]) is not str or type(
self.key_file["consumer_token"]) is not str:
raise TypeError("Consumer secret is type" +
str(type(self.key_file["consumer_secret"])) +
"and consumer token is type " + str(type(
self.key_file["consumer_token"])) + '''. Both
must be of type str. ''')
return (self.key_file["consumer_token"], self.key_file["consumer_secret"])
def read_seed_file(self, filename: str = "seeds.csv") -> pd.DataFrame:
"""Reads file with specified seeds to start from (csv)
Args:
filename (str, optional): Defaults to "seeds.csv"
Returns:
A single column pandas DataFrame with one Twitter ID (seed) each row.
"""
try:
with open("seeds.csv", "r") as f:
self.seeds = pd.read_csv(f, header=None)
except FileNotFoundError:
raise FileNotFoundError('"seeds.csv" could not be found')
except pd.errors.EmptyDataError as e:
print('"seeds.csv" is empty!')
raise e
return self.seeds
def read_token_file(self, filename="tokens.csv"):
"""Reads file with authorized user tokens (csv).
Args:
filename (str, optional): Defaults to "tokens.csv"
Returns:
pandas.DataFrame: With columns `token` and `secret`, one line per user
"""
return pd.read_csv(filename)
# Configuration class. Reads out all information from a given config.yml
class Config():
"""Class that handles the SQL and twitter user details configuration.
Attributes:
config_file (str): Path to configuration file
config_dict (dict): Dictionary containing the config information (in case
the dictionary shall be directly passed instead of read
out of a configuration file).
"""
config_template = "config_template.py"
# Initializes class using config.yml
def __init__(self, config_file="config.yml", config_dict: dict = None):
if config_dict is not None:
self.config = config_dict
else:
self.config_path = config_file
try:
with open(self.config_path, 'r') as f:
self.config = yaml.safe_load(f)
except FileNotFoundError:
raise FileNotFoundError('Could not find "' + self.config_path + '''".\n
Please run "python3 make_config.py" or provide a config.yml''')
# Check if mailgun notifications should be used
if "notifications" not in self.config:
self.use_notifications = False
else:
self.notif_config = self.config["notifications"]
notif_config_items = [value for (key, value) in self.notif_config.items()]
single_items = list(set(notif_config_items))
if len(single_items) == 1 and single_items[0] is None:
self.use_notifications = False
elif None in single_items:
missing = [key for (key, value) in self.notif_config.items() if value is None]
raise ValueError(f"""You have not filled all required fields for the notifications
configuration! Fields missing are {missing}""")
else:
self.use_notifications = True
# Check for necessary database information. If no information is provided,
# stop
if "sql" not in self.config:
print("Config file " + config_file + """ does not contain key 'sql'!
Will use default sqlite configuration.""")
self.config["sql"] = dict(dbtype="sqlite",
dbname="new_database")
self.sql_config = self.config["sql"]
# No db type given in Config
if self.sql_config["dbtype"] is None:
print('''Parameter dbtype not set in the "config.yml". Will create
an sqlite database.''')
self.dbtype = "sqlite"
else:
self.dbtype = self.sql_config["dbtype"].strip()
# DB type is msql - checking for all parameters
if self.dbtype == "mysql":
try:
self.dbhost = str(self.sql_config["host"])
self.dbuser = str(self.sql_config["user"])
self.dbpwd = str(self.sql_config["passwd"])
if self.dbhost == '':
raise ValueError("dbhost parameter is empty")
if self.dbuser == '':
raise ValueError("dbuser parameter is empty")
if self.dbpwd == '':
raise ValueError("passwd parameter is empty")
except KeyError as e:
raise e
elif self.dbtype == "sqlite":
self.dbhost = None
self.dbuser = None
self.dbpwd = None
else:
raise ValueError('''dbtype parameter is neither "sqlite" nor
"mysql". Please adjust the "config.yml" ''')
# Set db name
if self.sql_config["dbname"] is not None:
self.dbname = self.sql_config["dbname"]
else:
print('''Parameter "dbname" is missing. New database will have the name
"new_database".''')
self.dbname = "new_database"
# Function to send mail if notifications are turned on in config.yml
# TODO: finalize this function
def send_mail(self, message_dict):
'''Sends an email via Mailgun.
Args:
message_dict (dict):
{
"subject": "your_subject"
"text": "message"
}
config (dict):
{
"mailgun_api_base_url": "link to mailgun_api_base_url"
"mailgun_api_key": "your mailgun_api_key"
"mailgun_default_smtp_login": "your mailgun_default_smtp_login"
"email_to_notify": "the email_to_notify"
}
Returns:
requests.post to Mailgun API.
'''
api_base_url = self.notif_config["mailgun_api_base_url"] + '/messages'
auth = ('api', self.notif_config["mailgun_api_key"])
data = {
"from": f"SparseTwitter <{self.notif_config['mailgun_default_smtp_login']}>",
"to": self.notif_config["email_to_notify"]
}
data.update(message_dict)
return post(api_base_url, auth=auth, data=data)
# TODO: Add mailgun config