TimeFeatures 1.0.11__tar.gz → 1.0.13__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (18) hide show
  1. {TimeFeatures-1.0.11 → TimeFeatures-1.0.13}/PKG-INFO +1 -1
  2. {TimeFeatures-1.0.11 → TimeFeatures-1.0.13}/TimeFeatures.egg-info/PKG-INFO +1 -1
  3. {TimeFeatures-1.0.11 → TimeFeatures-1.0.13}/setup.py +1 -1
  4. {TimeFeatures-1.0.11 → TimeFeatures-1.0.13}/timefeatures/widgets/owsavetodb.py +107 -18
  5. {TimeFeatures-1.0.11 → TimeFeatures-1.0.13}/timefeatures/widgets/owtimefeaturesconstructor.py +45 -1
  6. {TimeFeatures-1.0.11 → TimeFeatures-1.0.13}/timefeatures/widgets/owvardependencygraph.py +5 -1
  7. {TimeFeatures-1.0.11 → TimeFeatures-1.0.13}/LICENSE +0 -0
  8. {TimeFeatures-1.0.11 → TimeFeatures-1.0.13}/README.md +0 -0
  9. {TimeFeatures-1.0.11 → TimeFeatures-1.0.13}/TimeFeatures.egg-info/SOURCES.txt +0 -0
  10. {TimeFeatures-1.0.11 → TimeFeatures-1.0.13}/TimeFeatures.egg-info/dependency_links.txt +0 -0
  11. {TimeFeatures-1.0.11 → TimeFeatures-1.0.13}/TimeFeatures.egg-info/entry_points.txt +0 -0
  12. {TimeFeatures-1.0.11 → TimeFeatures-1.0.13}/TimeFeatures.egg-info/top_level.txt +0 -0
  13. {TimeFeatures-1.0.11 → TimeFeatures-1.0.13}/setup.cfg +0 -0
  14. {TimeFeatures-1.0.11 → TimeFeatures-1.0.13}/timefeatures/widgets/__init__.py +0 -0
  15. {TimeFeatures-1.0.11 → TimeFeatures-1.0.13}/timefeatures/widgets/icons/graphgenerator.svg +0 -0
  16. {TimeFeatures-1.0.11 → TimeFeatures-1.0.13}/timefeatures/widgets/icons/savedatadb.svg +0 -0
  17. {TimeFeatures-1.0.11 → TimeFeatures-1.0.13}/timefeatures/widgets/icons/timefeature-xs.svg +0 -0
  18. {TimeFeatures-1.0.11 → TimeFeatures-1.0.13}/timefeatures/widgets/icons/timefeature.svg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: TimeFeatures
3
- Version: 1.0.11
3
+ Version: 1.0.13
4
4
  Summary: Timefeatures add-on for Orange 3 data mining software.
5
5
  Home-page: https://github.com/alervgr/Orange-TimeFeatures
6
6
  Author: Alejandro Rivas García
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: TimeFeatures
3
- Version: 1.0.11
3
+ Version: 1.0.13
4
4
  Summary: Timefeatures add-on for Orange 3 data mining software.
5
5
  Home-page: https://github.com/alervgr/Orange-TimeFeatures
6
6
  Author: Alejandro Rivas García
@@ -21,7 +21,7 @@ setup(name="TimeFeatures",
21
21
  packages=["timefeatures.widgets"],
22
22
  package_data={"timefeatures.widgets": ["icons/*.svg", "icons/*.png"]},
23
23
  entry_points={"orange.widgets": "Time-Features = timefeatures.widgets"},
24
- version="1.0.11",
24
+ version="1.0.13",
25
25
  author="Alejandro Rivas García",
26
26
  author_email="alejandrorivasgarcia@gmail.com",
27
27
  keywords=[
@@ -19,6 +19,12 @@ from PyQt5.QtGui import QPixmap, QStandardItem
19
19
  from PyQt5.QtWidgets import QGridLayout, QLineEdit, QPushButton, QSizePolicy, QLabel
20
20
  from orangewidget.utils.signals import Input
21
21
 
22
+ import re
23
+
24
+ import smtplib, ssl, time
25
+ from email.mime.text import MIMEText
26
+ from email.mime.multipart import MIMEMultipart
27
+
22
28
  MAX_DL_LIMIT = 1000000
23
29
 
24
30
 
@@ -131,6 +137,9 @@ class owsavetodb(OWBaseSql, OWWidget):
131
137
  self.cols_label = QLabel()
132
138
  self.cols_label.setText("Columns: 0")
133
139
  layoutA.addWidget(self.cols_label, 2, 0)
140
+ self.emailDirection = QLineEdit(
141
+ placeholderText="Email... (Optional)", toolTip="Email direction")
142
+ layoutA.addWidget(self.emailDirection, 4, 0)
134
143
  self.tableName = QLineEdit(
135
144
  placeholderText="Table name...", toolTip="Table name")
136
145
  layoutA.addWidget(self.tableName, 3, 0)
@@ -140,7 +149,7 @@ class owsavetodb(OWBaseSql, OWWidget):
140
149
  )
141
150
  self.btn_savedata.clicked.connect(self.saveData)
142
151
  self.btn_savedata.setEnabled(False)
143
- layoutA.addWidget(self.btn_savedata, 3, 2)
152
+ layoutA.addWidget(self.btn_savedata, 4, 2)
144
153
  self._add_backend_controls()
145
154
 
146
155
  def _add_backend_controls(self):
@@ -180,7 +189,7 @@ class owsavetodb(OWBaseSql, OWWidget):
180
189
  self.Error.connection(str(ex))
181
190
 
182
191
  def create_table(self, table_name):
183
-
192
+ start_time = time.time()
184
193
  self.progressBarInit()
185
194
  contBar = 0
186
195
  contMetasOriginales = 0
@@ -246,35 +255,115 @@ class owsavetodb(OWBaseSql, OWWidget):
246
255
  pass
247
256
  except BackendError as ex:
248
257
  self.Error.connection(str(ex))
249
- self.progressBarFinished()
258
+
259
+ self.progressBarFinished()
260
+ if str(self.emailDirection.text()) != "":
261
+ end_time = time.time()
262
+ time_elapsed = end_time - start_time
263
+ time_elapsed = round(time_elapsed, 3)
264
+ self.send_mail(str(self.emailDirection.text()), time_elapsed)
265
+
266
+ def send_mail(self, mail, time_elapsed):
267
+
268
+ # Configuración de la connexión
269
+ sender = 'savetodbodm@gmail.com'
270
+ password = 'arnj lakd lyol rakg'
271
+ server = 'smtp.gmail.com'
272
+ port = 587
273
+
274
+ # Configuración del destinatario
275
+ to = mail
276
+
277
+ # configuración de las cabeceras y del mensaje
278
+ message = MIMEMultipart("alternative")
279
+
280
+ current_datetime = datetime.now()
281
+ formatted_datetime = current_datetime.strftime('%d-%m-%Y %H:%M:%S')
282
+
283
+ message["Subject"] = "Upload completed - Save To DB - " + str(formatted_datetime)
284
+ message["From"] = sender
285
+ message["To"] = to
286
+
287
+ if self.data.domain.class_var:
288
+ class_name = self.data.domain.class_var.name
289
+ else:
290
+ class_name = None
291
+
292
+ body = f"""\
293
+ <html>
294
+ <head>
295
+ </head>
296
+ <body>
297
+ <h1>Save to DB - Widget</h1>
298
+ <p>Your data upload has been completed!</p>
299
+ <p>-Table information:</p>
300
+ <ul>
301
+ <li>Table name: {str(self.tableName.text())}.</li>
302
+ <li>{str(self.rows_label.text())}.</li>
303
+ <li>{str(self.cols_label.text())}.</li>
304
+ <li>Class name: {str(class_name)}</li>
305
+ <li>{str(self.target_label.text())}.</li>
306
+ </ul>
307
+ <p>-Connection information:</p>
308
+ <ul>
309
+ <li>Server name: {str(self.servertext.text())}</li>
310
+ <li>Database name: {str(self.databasetext.text())}</li>
311
+ <li>Time Elapsed: {str(time_elapsed)}s.</li>
312
+ </ul>
313
+ </body>
314
+ </html>
315
+ """
316
+
317
+ part = MIMEText(body, "html")
318
+ message.attach(part)
319
+
320
+ # Envío del mensaje
321
+ try:
322
+ context = ssl.create_default_context()
323
+ with smtplib.SMTP(server, port=port) as smtp:
324
+ smtp.starttls(context=context)
325
+ smtp.login(sender, password)
326
+ smtp.send_message(message)
327
+ except Exception as ex:
328
+ self.Error.connection(str(ex))
250
329
 
251
330
  def saveData(self):
252
331
 
253
332
  self.clear()
254
333
 
334
+ email_regex = r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b'
335
+
255
336
  if self.tableName.text() == "":
256
337
  self.Error.connection("Table name must be filled.")
257
338
  elif self.servertext.text() == "" or self.databasetext.text() == "":
258
339
  self.Error.connection("Host and database fields must be filled.")
340
+ elif self.emailDirection.text() != "":
341
+ if not re.match(email_regex, self.emailDirection.text()):
342
+ self.Error.connection("The field email must be an email.")
343
+ else:
344
+ self.insert_data()
259
345
  else:
260
- self.create_master_table()
346
+ self.insert_data()
261
347
 
262
- if self.data.domain.class_var:
263
- class_name = self.data.domain.class_var.name
264
- else:
265
- class_name = None
348
+ def insert_data(self):
349
+ self.create_master_table()
266
350
 
267
- query = "INSERT INTO public.datasets (name, datetime, rows, cols, class, class_name) VALUES ('" + self.tableName.text().lower() + "','" + datetime.now().strftime(
268
- '%Y-%m-%d %H:%M:%S') + "','" + str(self.rows) + "','" + str(self.cols) + "','" + str(
269
- self.target) + "','" + str(class_name) + "');"
351
+ if self.data.domain.class_var:
352
+ class_name = self.data.domain.class_var.name
353
+ else:
354
+ class_name = None
355
+
356
+ query = "INSERT INTO public.datasets (name, datetime, rows, cols, class, class_name) VALUES ('" + self.tableName.text().lower() + "','" + datetime.now().strftime(
357
+ '%Y-%m-%d %H:%M:%S') + "','" + str(self.rows) + "','" + str(self.cols) + "','" + str(
358
+ self.target) + "','" + str(class_name) + "');"
359
+
360
+ try:
361
+ with self.backend.execute_sql_query(query):
362
+ pass
363
+ self.create_table(self.tableName.text().lower())
364
+ except BackendError as ex:
365
+ self.Error.connection(str(ex))
270
366
 
271
- try:
272
- with self.backend.execute_sql_query(query):
273
- pass
274
- self.create_table(self.tableName.text().lower())
275
- except BackendError as ex:
276
- self.Error.connection(str(ex))
277
-
278
367
  def highlight_error(self, text=""):
279
368
  err = ['', 'QLineEdit {border: 2px solid red;}']
280
369
  self.servertext.setStyleSheet(err['server' in text or 'host' in text])
@@ -819,6 +819,7 @@ class owtimefeaturesconstructor(OWWidget, ConcurrentWidgetMixin):
819
819
 
820
820
  class Inputs:
821
821
  data = Input("Data", Orange.data.Table)
822
+ expressions = Input("Variable Definitions", Orange.data.Table)
822
823
 
823
824
  class Outputs:
824
825
  data = Output("Data", Orange.data.Table)
@@ -1103,6 +1104,35 @@ class owtimefeaturesconstructor(OWWidget, ConcurrentWidgetMixin):
1103
1104
  self.fix_button.setHidden(not self.expressions_with_values)
1104
1105
  self.editorstack.setEnabled(self.currentIndex >= 0)
1105
1106
 
1107
+ @Inputs.expressions
1108
+ @check_sql_input
1109
+ def setExpressions(self, expressions=None):
1110
+
1111
+ self.expressions = expressions
1112
+
1113
+ if self.expressions is None:
1114
+ self.Warning.clear()
1115
+ self.Error.transform_error.clear()
1116
+
1117
+ if self.data is not None and self.expressions is not None:
1118
+ if self.expressions is not None:
1119
+ if len(self.expressions.domain) >= 2 and (
1120
+ self.expressions.domain[0].name != "Variable" or self.expressions.domain[1].name != "Expression"):
1121
+ self.Warning.table_warning()
1122
+ else:
1123
+ self.Error.transform_error.clear()
1124
+ for datos in reversed(self.expressions):
1125
+ if not math.isnan(datos[1]) and str(datos[1]) != "NaN":
1126
+ desc = ContinuousDescriptor(
1127
+ name=str(datos[0]),
1128
+ expression=str(datos[1]),
1129
+ meta=False,
1130
+ number_of_decimals=3,
1131
+ )
1132
+ self.addFeature(desc)
1133
+ else:
1134
+ self.Error.transform_error("There is not data input.")
1135
+
1106
1136
  def handleNewSignals(self):
1107
1137
  if self.data is not None:
1108
1138
  self.apply()
@@ -1188,6 +1218,14 @@ class owtimefeaturesconstructor(OWWidget, ConcurrentWidgetMixin):
1188
1218
  desc = self._validate_descriptors(desc)
1189
1219
  self.start(run, self.data, desc, self.expressions_with_values)
1190
1220
 
1221
+ '''
1222
+ INTENTO DE PODER USAR VARIABLES NO CONTENIDAS EN EL DATASET ORIGINAL.
1223
+
1224
+ desc = list(self.featuremodel)
1225
+ for d in desc:
1226
+ self.start(run, self.data, self._validate_descriptors(d), self.expressions_with_values)'''
1227
+
1228
+
1191
1229
  def on_done(self, result: "Result") -> None:
1192
1230
  data, attrs, desc = result.data, result.attributes, result.desc
1193
1231
  disc_attrs_not_ok = self.check_attrs_values(
@@ -1361,6 +1399,7 @@ class Result:
1361
1399
  def run(data: Table, desc, use_values, task: TaskState) -> Result:
1362
1400
  if task.is_interruption_requested():
1363
1401
  raise CancelledError # pragma: no cover
1402
+
1364
1403
  new_variables, new_metas = construct_variables(desc, data, use_values)
1365
1404
  # Explicit cancellation point after `construct_variables` which can
1366
1405
  # already run `compute_value`.
@@ -1374,10 +1413,14 @@ def run(data: Table, desc, use_values, task: TaskState) -> Result:
1374
1413
  try:
1375
1414
  for variable in new_variables:
1376
1415
  variable.compute_value.mask_exceptions = False
1377
- data = data.transform(new_domain)
1416
+ try:
1417
+ data = data.transform(new_domain)
1418
+ except:
1419
+ raise TypeError("One or more variables were not found.")
1378
1420
  finally:
1379
1421
  for variable in new_variables:
1380
1422
  variable.compute_value.mask_exceptions = True
1423
+
1381
1424
  return Result(data, new_variables, new_metas, desc)
1382
1425
 
1383
1426
 
@@ -1456,6 +1499,7 @@ def validate_exp(exp):
1456
1499
 
1457
1500
  def construct_variables(descriptions, data, use_values=False):
1458
1501
  # subs
1502
+
1459
1503
  variables = []
1460
1504
  metas = []
1461
1505
  source_vars = data.domain.variables + data.domain.metas
@@ -17,7 +17,11 @@ from PyQt5.QtWidgets import QPushButton, QVBoxLayout, QHBoxLayout
17
17
  from orangecontrib.network import Network
18
18
  from orangewidget.utils.signals import Input
19
19
 
20
- '''def calculate_weight(expression):
20
+ '''
21
+
22
+ CALCULO DE PONDERACIONES PARA LOS PESOS DE LAS ARISTAS.
23
+
24
+ def calculate_weight(expression):
21
25
  # Encontrar todas las coincidencias con las funciones temporales y almacenarlas
22
26
  matches_shift = list(re.finditer(r'shift\(([^,]+),([-+]?\d+)\)', expression))
23
27
  matches_sum = list(re.finditer(r'sum\(([^,]+),([-+]?\d+),([-+]?\d+)\)', expression))
File without changes
File without changes
File without changes