customeranalytics 0.1__py3-none-any.whl

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 (254) hide show
  1. customeranalytics/__init__.py +319 -0
  2. customeranalytics/configs.py +480 -0
  3. customeranalytics/data_storage_configurations/__init__.py +245 -0
  4. customeranalytics/data_storage_configurations/data_access.py +165 -0
  5. customeranalytics/data_storage_configurations/data_works_pipeline.py +207 -0
  6. customeranalytics/data_storage_configurations/es_create_index.py +544 -0
  7. customeranalytics/data_storage_configurations/logger.py +36 -0
  8. customeranalytics/data_storage_configurations/query_es.py +157 -0
  9. customeranalytics/data_storage_configurations/reports.py +684 -0
  10. customeranalytics/data_storage_configurations/schedule_data_integration.py +355 -0
  11. customeranalytics/docs/queries.yaml +245 -0
  12. customeranalytics/docs/web_configs.yaml +2 -0
  13. customeranalytics/exploratory_analysis/__init__.py +109 -0
  14. customeranalytics/exploratory_analysis/churn.py +232 -0
  15. customeranalytics/exploratory_analysis/cohorts.py +535 -0
  16. customeranalytics/exploratory_analysis/descriptive_statistics.py +470 -0
  17. customeranalytics/exploratory_analysis/funnels.py +407 -0
  18. customeranalytics/exploratory_analysis/product_analytics.py +340 -0
  19. customeranalytics/exploratory_analysis/promotion_analytics.py +299 -0
  20. customeranalytics/exploratory_analysis/rfm.py +202 -0
  21. customeranalytics/exploratory_analysis/sample_data/sample_data_avg_order_count_per_promo_per_cust.csv +99 -0
  22. customeranalytics/exploratory_analysis/sample_data/sample_data_chart_1_search.csv +2 -0
  23. customeranalytics/exploratory_analysis/sample_data/sample_data_chart_2_search.csv +46 -0
  24. customeranalytics/exploratory_analysis/sample_data/sample_data_chart_3_search.csv +2 -0
  25. customeranalytics/exploratory_analysis/sample_data/sample_data_chart_4_search.csv +2 -0
  26. customeranalytics/exploratory_analysis/sample_data/sample_data_churn.csv +2 -0
  27. customeranalytics/exploratory_analysis/sample_data/sample_data_churn_weekly.csv +10 -0
  28. customeranalytics/exploratory_analysis/sample_data/sample_data_client_feature_predicted.csv +1590 -0
  29. customeranalytics/exploratory_analysis/sample_data/sample_data_client_kpis.csv +7060 -0
  30. customeranalytics/exploratory_analysis/sample_data/sample_data_clvrfm_anomaly.csv +561 -0
  31. customeranalytics/exploratory_analysis/sample_data/sample_data_clvsegments_amount.csv +8 -0
  32. customeranalytics/exploratory_analysis/sample_data/sample_data_customer_journey.csv +18 -0
  33. customeranalytics/exploratory_analysis/sample_data/sample_data_daily_clv.csv +103 -0
  34. customeranalytics/exploratory_analysis/sample_data/sample_data_daily_cohort_downloads.csv +68 -0
  35. customeranalytics/exploratory_analysis/sample_data/sample_data_daily_cohort_from_1_to_2.csv +66 -0
  36. customeranalytics/exploratory_analysis/sample_data/sample_data_daily_cohort_from_2_to_3.csv +64 -0
  37. customeranalytics/exploratory_analysis/sample_data/sample_data_daily_cohort_from_3_to_4.csv +55 -0
  38. customeranalytics/exploratory_analysis/sample_data/sample_data_daily_dimension_values.csv +199 -0
  39. customeranalytics/exploratory_analysis/sample_data/sample_data_daily_funnel.csv +36 -0
  40. customeranalytics/exploratory_analysis/sample_data/sample_data_daily_funnel_downloads.csv +68 -0
  41. customeranalytics/exploratory_analysis/sample_data/sample_data_daily_inorganic_ratio.csv +6070 -0
  42. customeranalytics/exploratory_analysis/sample_data/sample_data_daily_orders.csv +57 -0
  43. customeranalytics/exploratory_analysis/sample_data/sample_data_daily_organic_orders.csv +64 -0
  44. customeranalytics/exploratory_analysis/sample_data/sample_data_daily_products_of_sales.csv +12574 -0
  45. customeranalytics/exploratory_analysis/sample_data/sample_data_daily_promotion_discount.csv +64 -0
  46. customeranalytics/exploratory_analysis/sample_data/sample_data_daily_promotion_revenue.csv +6070 -0
  47. customeranalytics/exploratory_analysis/sample_data/sample_data_dcohort_anomaly.csv +6 -0
  48. customeranalytics/exploratory_analysis/sample_data/sample_data_dcohort_anomaly_2.csv +118 -0
  49. customeranalytics/exploratory_analysis/sample_data/sample_data_deliver.csv +47 -0
  50. customeranalytics/exploratory_analysis/sample_data/sample_data_deliver_kpis.csv +2 -0
  51. customeranalytics/exploratory_analysis/sample_data/sample_data_deliver_weekday_hour.csv +25 -0
  52. customeranalytics/exploratory_analysis/sample_data/sample_data_dfunnel_anomaly.csv +118 -0
  53. customeranalytics/exploratory_analysis/sample_data/sample_data_dimension_kpis.csv +199 -0
  54. customeranalytics/exploratory_analysis/sample_data/sample_data_dorders_anomaly.csv +85 -0
  55. customeranalytics/exploratory_analysis/sample_data/sample_data_frequency_clusters.csv +6 -0
  56. customeranalytics/exploratory_analysis/sample_data/sample_data_frequency_recency.csv +3740 -0
  57. customeranalytics/exploratory_analysis/sample_data/sample_data_hourly_funnel.csv +25 -0
  58. customeranalytics/exploratory_analysis/sample_data/sample_data_hourly_funnel_downloads.csv +25 -0
  59. customeranalytics/exploratory_analysis/sample_data/sample_data_hourly_inorganic_ratio.csv +2353 -0
  60. customeranalytics/exploratory_analysis/sample_data/sample_data_hourly_orders.csv +25 -0
  61. customeranalytics/exploratory_analysis/sample_data/sample_data_hourly_organic_orders.csv +2353 -0
  62. customeranalytics/exploratory_analysis/sample_data/sample_data_inorganic_orders_per_promotion_per_day.csv +6070 -0
  63. customeranalytics/exploratory_analysis/sample_data/sample_data_kpis.csv +2 -0
  64. customeranalytics/exploratory_analysis/sample_data/sample_data_monetary_clusters.csv +6 -0
  65. customeranalytics/exploratory_analysis/sample_data/sample_data_monetary_frequency.csv +3740 -0
  66. customeranalytics/exploratory_analysis/sample_data/sample_data_monthly_funnel.csv +5 -0
  67. customeranalytics/exploratory_analysis/sample_data/sample_data_monthly_funnel_downloads.csv +5 -0
  68. customeranalytics/exploratory_analysis/sample_data/sample_data_monthly_orders.csv +4 -0
  69. customeranalytics/exploratory_analysis/sample_data/sample_data_most_combined_products.csv +11 -0
  70. customeranalytics/exploratory_analysis/sample_data/sample_data_most_ordered_categories.csv +11 -0
  71. customeranalytics/exploratory_analysis/sample_data/sample_data_most_ordered_products.csv +11 -0
  72. customeranalytics/exploratory_analysis/sample_data/sample_data_order_and_payment_amount_differences.csv +91 -0
  73. customeranalytics/exploratory_analysis/sample_data/sample_data_prepare.csv +101 -0
  74. customeranalytics/exploratory_analysis/sample_data/sample_data_prepare_weekday_hour.csv +25 -0
  75. customeranalytics/exploratory_analysis/sample_data/sample_data_product_kpis.csv +201 -0
  76. customeranalytics/exploratory_analysis/sample_data/sample_data_product_usage_before_after_amount_accept.csv +11 -0
  77. customeranalytics/exploratory_analysis/sample_data/sample_data_product_usage_before_after_amount_reject.csv +7 -0
  78. customeranalytics/exploratory_analysis/sample_data/sample_data_product_usage_before_after_orders_accept.csv +11 -0
  79. customeranalytics/exploratory_analysis/sample_data/sample_data_product_usage_before_after_orders_reject.csv +11 -0
  80. customeranalytics/exploratory_analysis/sample_data/sample_data_promotion_comparison.csv +91 -0
  81. customeranalytics/exploratory_analysis/sample_data/sample_data_promotion_kpis.csv +99 -0
  82. customeranalytics/exploratory_analysis/sample_data/sample_data_promotion_number_of_customer.csv +99 -0
  83. customeranalytics/exploratory_analysis/sample_data/sample_data_promotion_usage_before_after_amount_accept.csv +81 -0
  84. customeranalytics/exploratory_analysis/sample_data/sample_data_promotion_usage_before_after_amount_reject.csv +11 -0
  85. customeranalytics/exploratory_analysis/sample_data/sample_data_promotion_usage_before_after_orders_accept.csv +55 -0
  86. customeranalytics/exploratory_analysis/sample_data/sample_data_promotion_usage_before_after_orders_reject.csv +37 -0
  87. customeranalytics/exploratory_analysis/sample_data/sample_data_purchase_amount_distribution.csv +22 -0
  88. customeranalytics/exploratory_analysis/sample_data/sample_data_recency_clusters.csv +6 -0
  89. customeranalytics/exploratory_analysis/sample_data/sample_data_recency_monetary.csv +3740 -0
  90. customeranalytics/exploratory_analysis/sample_data/sample_data_rfm.csv +2001 -0
  91. customeranalytics/exploratory_analysis/sample_data/sample_data_ride.csv +101 -0
  92. customeranalytics/exploratory_analysis/sample_data/sample_data_ride_weekday_hour.csv +25 -0
  93. customeranalytics/exploratory_analysis/sample_data/sample_data_segmentation.csv +11 -0
  94. customeranalytics/exploratory_analysis/sample_data/sample_data_segments_change_daily_before_after_amount.csv +10 -0
  95. customeranalytics/exploratory_analysis/sample_data/sample_data_segments_change_daily_before_after_orders.csv +9 -0
  96. customeranalytics/exploratory_analysis/sample_data/sample_data_segments_change_monthly_before_after_amount.csv +10 -0
  97. customeranalytics/exploratory_analysis/sample_data/sample_data_segments_change_monthly_before_after_orders.csv +11 -0
  98. customeranalytics/exploratory_analysis/sample_data/sample_data_segments_change_weekly_before_after_amount.csv +10 -0
  99. customeranalytics/exploratory_analysis/sample_data/sample_data_segments_change_weekly_before_after_orders.csv +10 -0
  100. customeranalytics/exploratory_analysis/sample_data/sample_data_user_counts_per_order_seq.csv +47 -0
  101. customeranalytics/exploratory_analysis/sample_data/sample_data_weekly_average_order_per_user.csv +13 -0
  102. customeranalytics/exploratory_analysis/sample_data/sample_data_weekly_average_payment_amount.csv +13 -0
  103. customeranalytics/exploratory_analysis/sample_data/sample_data_weekly_average_session_per_user.csv +13 -0
  104. customeranalytics/exploratory_analysis/sample_data/sample_data_weekly_cohort_downloads.csv +13 -0
  105. customeranalytics/exploratory_analysis/sample_data/sample_data_weekly_cohort_from_1_to_2.csv +13 -0
  106. customeranalytics/exploratory_analysis/sample_data/sample_data_weekly_cohort_from_2_to_3.csv +13 -0
  107. customeranalytics/exploratory_analysis/sample_data/sample_data_weekly_cohort_from_3_to_4.csv +12 -0
  108. customeranalytics/exploratory_analysis/sample_data/sample_data_weekly_funnel.csv +25 -0
  109. customeranalytics/exploratory_analysis/sample_data/sample_data_weekly_funnel_downloads.csv +25 -0
  110. customeranalytics/exploratory_analysis/sample_data/sample_data_weekly_orders.csv +10 -0
  111. customeranalytics/ml_process/__init__.py +64 -0
  112. customeranalytics/ml_process/ab_test.py +615 -0
  113. customeranalytics/ml_process/anomaly_detection.py +456 -0
  114. customeranalytics/ml_process/clv_prediction.py +301 -0
  115. customeranalytics/ml_process/customer_segmentation.py +354 -0
  116. customeranalytics/ml_process/delivery_analytics.py +754 -0
  117. customeranalytics/utils.py +186 -0
  118. customeranalytics/web/app/__init__.py +37 -0
  119. customeranalytics/web/app/base/__init__.py +9 -0
  120. customeranalytics/web/app/base/forms.py +16 -0
  121. customeranalytics/web/app/base/models.py +43 -0
  122. customeranalytics/web/app/base/routes.py +126 -0
  123. customeranalytics/web/app/base/static/assets/css/app.css +20 -0
  124. customeranalytics/web/app/base/static/assets/fonts/Inter-Black.woff +0 -0
  125. customeranalytics/web/app/base/static/assets/fonts/Inter-Black.woff2 +0 -0
  126. customeranalytics/web/app/base/static/assets/fonts/Inter-BlackItalic.woff +0 -0
  127. customeranalytics/web/app/base/static/assets/fonts/Inter-BlackItalic.woff2 +0 -0
  128. customeranalytics/web/app/base/static/assets/fonts/Inter-Bold.woff +0 -0
  129. customeranalytics/web/app/base/static/assets/fonts/Inter-Bold.woff2 +0 -0
  130. customeranalytics/web/app/base/static/assets/fonts/Inter-BoldItalic.woff +0 -0
  131. customeranalytics/web/app/base/static/assets/fonts/Inter-BoldItalic.woff2 +0 -0
  132. customeranalytics/web/app/base/static/assets/fonts/Inter-ExtraBold.woff +0 -0
  133. customeranalytics/web/app/base/static/assets/fonts/Inter-ExtraBold.woff2 +0 -0
  134. customeranalytics/web/app/base/static/assets/fonts/Inter-ExtraBoldItalic.woff +0 -0
  135. customeranalytics/web/app/base/static/assets/fonts/Inter-ExtraBoldItalic.woff2 +0 -0
  136. customeranalytics/web/app/base/static/assets/fonts/Inter-ExtraLight-BETA.woff +0 -0
  137. customeranalytics/web/app/base/static/assets/fonts/Inter-ExtraLight-BETA.woff2 +0 -0
  138. customeranalytics/web/app/base/static/assets/fonts/Inter-ExtraLightItalic-BETA.woff +0 -0
  139. customeranalytics/web/app/base/static/assets/fonts/Inter-ExtraLightItalic-BETA.woff2 +0 -0
  140. customeranalytics/web/app/base/static/assets/fonts/Inter-Italic.woff +0 -0
  141. customeranalytics/web/app/base/static/assets/fonts/Inter-Italic.woff2 +0 -0
  142. customeranalytics/web/app/base/static/assets/fonts/Inter-Light-BETA.woff +0 -0
  143. customeranalytics/web/app/base/static/assets/fonts/Inter-Light-BETA.woff2 +0 -0
  144. customeranalytics/web/app/base/static/assets/fonts/Inter-LightItalic-BETA.woff +0 -0
  145. customeranalytics/web/app/base/static/assets/fonts/Inter-LightItalic-BETA.woff2 +0 -0
  146. customeranalytics/web/app/base/static/assets/fonts/Inter-Medium.woff +0 -0
  147. customeranalytics/web/app/base/static/assets/fonts/Inter-Medium.woff2 +0 -0
  148. customeranalytics/web/app/base/static/assets/fonts/Inter-MediumItalic.woff +0 -0
  149. customeranalytics/web/app/base/static/assets/fonts/Inter-MediumItalic.woff2 +0 -0
  150. customeranalytics/web/app/base/static/assets/fonts/Inter-Regular.woff +0 -0
  151. customeranalytics/web/app/base/static/assets/fonts/Inter-Regular.woff2 +0 -0
  152. customeranalytics/web/app/base/static/assets/fonts/Inter-SemiBold.woff +0 -0
  153. customeranalytics/web/app/base/static/assets/fonts/Inter-SemiBold.woff2 +0 -0
  154. customeranalytics/web/app/base/static/assets/fonts/Inter-SemiBoldItalic.woff +0 -0
  155. customeranalytics/web/app/base/static/assets/fonts/Inter-SemiBoldItalic.woff2 +0 -0
  156. customeranalytics/web/app/base/static/assets/fonts/Inter-Thin-BETA.woff +0 -0
  157. customeranalytics/web/app/base/static/assets/fonts/Inter-Thin-BETA.woff2 +0 -0
  158. customeranalytics/web/app/base/static/assets/fonts/Inter-ThinItalic-BETA.woff +0 -0
  159. customeranalytics/web/app/base/static/assets/fonts/Inter-ThinItalic-BETA.woff2 +0 -0
  160. customeranalytics/web/app/base/static/assets/fonts/Inter-italic.var.woff2 +0 -0
  161. customeranalytics/web/app/base/static/assets/fonts/Inter-upright.var.woff2 +0 -0
  162. customeranalytics/web/app/base/static/assets/fonts/Inter.var.woff2 +0 -0
  163. customeranalytics/web/app/base/static/assets/fonts/fa-brands-400.eot +0 -0
  164. customeranalytics/web/app/base/static/assets/fonts/fa-brands-400.svg +3570 -0
  165. customeranalytics/web/app/base/static/assets/fonts/fa-brands-400.ttf +0 -0
  166. customeranalytics/web/app/base/static/assets/fonts/fa-brands-400.woff +0 -0
  167. customeranalytics/web/app/base/static/assets/fonts/fa-brands-400.woff2 +0 -0
  168. customeranalytics/web/app/base/static/assets/fonts/fa-regular-400.eot +0 -0
  169. customeranalytics/web/app/base/static/assets/fonts/fa-regular-400.svg +801 -0
  170. customeranalytics/web/app/base/static/assets/fonts/fa-regular-400.ttf +0 -0
  171. customeranalytics/web/app/base/static/assets/fonts/fa-regular-400.woff +0 -0
  172. customeranalytics/web/app/base/static/assets/fonts/fa-regular-400.woff2 +0 -0
  173. customeranalytics/web/app/base/static/assets/fonts/fa-solid-900.eot +0 -0
  174. customeranalytics/web/app/base/static/assets/fonts/fa-solid-900.svg +5028 -0
  175. customeranalytics/web/app/base/static/assets/fonts/fa-solid-900.ttf +0 -0
  176. customeranalytics/web/app/base/static/assets/fonts/fa-solid-900.woff +0 -0
  177. customeranalytics/web/app/base/static/assets/fonts/fa-solid-900.woff2 +0 -0
  178. customeranalytics/web/app/base/static/assets/img/avatars/avatar-1.png +0 -0
  179. customeranalytics/web/app/base/static/assets/img/avatars/avatar-2.png +0 -0
  180. customeranalytics/web/app/base/static/assets/img/avatars/avatar-3.png +0 -0
  181. customeranalytics/web/app/base/static/assets/img/avatars/avatar-4.png +0 -0
  182. customeranalytics/web/app/base/static/assets/img/avatars/avatar-5.png +0 -0
  183. customeranalytics/web/app/base/static/assets/img/avatars/info.jpeg +0 -0
  184. customeranalytics/web/app/base/static/assets/img/icons/customanality.png +0 -0
  185. customeranalytics/web/app/base/static/assets/img/icons/icon-48x48.png +0 -0
  186. customeranalytics/web/app/base/static/assets/js/app.js +2 -0
  187. customeranalytics/web/app/base/static/assets/js/app.js.LICENSE +566 -0
  188. customeranalytics/web/app/base/static/assets/js/app.js.LICENSE.txt +556 -0
  189. customeranalytics/web/app/base/static/assets/js/modules/bootstrap.js +15 -0
  190. customeranalytics/web/app/base/static/assets/js/modules/chartjs.js +4 -0
  191. customeranalytics/web/app/base/static/assets/js/modules/feather.js +8 -0
  192. customeranalytics/web/app/base/static/assets/js/modules/flatpickr.js +4 -0
  193. customeranalytics/web/app/base/static/assets/js/modules/moment.js +4 -0
  194. customeranalytics/web/app/base/static/assets/js/modules/sidebar.js +23 -0
  195. customeranalytics/web/app/base/static/assets/js/modules/theme.js +16 -0
  196. customeranalytics/web/app/base/templates/accounts/login.html +81 -0
  197. customeranalytics/web/app/base/templates/accounts/register.html +80 -0
  198. customeranalytics/web/app/base/templates/includes/footer.html +28 -0
  199. customeranalytics/web/app/base/templates/includes/navigation.html +51 -0
  200. customeranalytics/web/app/base/templates/includes/scripts.html +3 -0
  201. customeranalytics/web/app/base/templates/includes/sidebar.html +146 -0
  202. customeranalytics/web/app/base/templates/layouts/base-fullscreen.html +36 -0
  203. customeranalytics/web/app/base/templates/layouts/base.html +84 -0
  204. customeranalytics/web/app/base/util.py +30 -0
  205. customeranalytics/web/app/home/__init__.py +9 -0
  206. customeranalytics/web/app/home/forms.py +1039 -0
  207. customeranalytics/web/app/home/models.py +438 -0
  208. customeranalytics/web/app/home/profiles.py +310 -0
  209. customeranalytics/web/app/home/routes.py +386 -0
  210. customeranalytics/web/app/home/search.py +288 -0
  211. customeranalytics/web/app/home/static/assets/img/avatars/avatar-1.png +0 -0
  212. customeranalytics/web/app/home/static/assets/img/avatars/avatar-2.png +0 -0
  213. customeranalytics/web/app/home/static/assets/img/avatars/avatar-3.png +0 -0
  214. customeranalytics/web/app/home/static/assets/img/avatars/avatar-4.png +0 -0
  215. customeranalytics/web/app/home/static/assets/img/avatars/avatar-5.png +0 -0
  216. customeranalytics/web/app/home/static/assets/img/icons/customanality.png +0 -0
  217. customeranalytics/web/app/home/static/assets/img/icons/icon-48x48.png +0 -0
  218. customeranalytics/web/app/home/templates/abtest-product.html +280 -0
  219. customeranalytics/web/app/home/templates/abtest-promotion.html +362 -0
  220. customeranalytics/web/app/home/templates/abtest-segments.html +298 -0
  221. customeranalytics/web/app/home/templates/add-data-delivery.html +184 -0
  222. customeranalytics/web/app/home/templates/add-data-product.html +177 -0
  223. customeranalytics/web/app/home/templates/add-data-purchase.html +392 -0
  224. customeranalytics/web/app/home/templates/anomaly.html +261 -0
  225. customeranalytics/web/app/home/templates/clv.html +211 -0
  226. customeranalytics/web/app/home/templates/cohorts.html +308 -0
  227. customeranalytics/web/app/home/templates/customer-segmentation.html +308 -0
  228. customeranalytics/web/app/home/templates/data-es.html +152 -0
  229. customeranalytics/web/app/home/templates/data-execute.html +397 -0
  230. customeranalytics/web/app/home/templates/delivery.html +404 -0
  231. customeranalytics/web/app/home/templates/funnel-customer.html +240 -0
  232. customeranalytics/web/app/home/templates/funnel-session.html +236 -0
  233. customeranalytics/web/app/home/templates/index.html +524 -0
  234. customeranalytics/web/app/home/templates/index2.html +515 -0
  235. customeranalytics/web/app/home/templates/page-403.html +46 -0
  236. customeranalytics/web/app/home/templates/page-404.html +45 -0
  237. customeranalytics/web/app/home/templates/page-500.html +45 -0
  238. customeranalytics/web/app/home/templates/pages-blank.html +33 -0
  239. customeranalytics/web/app/home/templates/pages-sign-in.html +67 -0
  240. customeranalytics/web/app/home/templates/pages-sign-up.html +61 -0
  241. customeranalytics/web/app/home/templates/product.html +203 -0
  242. customeranalytics/web/app/home/templates/profile.html +1009 -0
  243. customeranalytics/web/app/home/templates/rfm.html +254 -0
  244. customeranalytics/web/app/home/templates/search.html +167 -0
  245. customeranalytics/web/app/home/templates/settings.html +205 -0
  246. customeranalytics/web/app/home/templates/stats-desc.html +230 -0
  247. customeranalytics/web/app/home/templates/stats-purchase.html +221 -0
  248. customeranalytics/web/config.py +30 -0
  249. customeranalytics/web/db.sqlite3 +0 -0
  250. customeranalytics/web/run.py +30 -0
  251. customeranalytics-0.1.dist-info/METADATA +1102 -0
  252. customeranalytics-0.1.dist-info/RECORD +254 -0
  253. customeranalytics-0.1.dist-info/WHEEL +4 -0
  254. customeranalytics-0.1.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,544 @@
1
+ import sys, os, inspect
2
+ currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
3
+ parentdir = os.path.dirname(currentdir)
4
+ sys.path.insert(0, parentdir)
5
+ import numpy as np
6
+ import pandas as pd
7
+ import datetime
8
+ import random
9
+ from time import gmtime, strftime
10
+ import pytz
11
+ from elasticsearch import Elasticsearch
12
+ from elasticsearch import helpers
13
+ import argparse
14
+ from dateutil.parser import parse
15
+ from sqlalchemy import create_engine, MetaData
16
+ from flask_login import current_user
17
+ from os.path import abspath, join
18
+ import time
19
+
20
+ from customeranalytics.utils import read_yaml, current_date_to_day, convert_to_date, convert_to_iso_format, formating_numbers
21
+ from customeranalytics.configs import query_path, default_es_port, default_es_host, none_types, delivery_metrics
22
+ from customeranalytics.configs import orders_index_columns, downloads_index_columns, not_required_columns, not_required_default_values
23
+ from customeranalytics.data_storage_configurations.query_es import QueryES
24
+ from customeranalytics.data_storage_configurations.data_access import GetData
25
+
26
+ try:
27
+ engine = create_engine('sqlite://///' + join(abspath(""), "web", 'db.sqlite3'), connect_args={'check_same_thread': False})
28
+ metadata = MetaData()
29
+ con = engine.connect()
30
+ except Exception as e:
31
+ engine = create_engine('sqlite://///' + join(parentdir, "web", 'db.sqlite3'), connect_args={'check_same_thread': False})
32
+ metadata = MetaData()
33
+ con = engine.connect()
34
+
35
+
36
+ class CreateIndex:
37
+ """
38
+ This class is converting input data to elasticsearch index.
39
+ This allow us to query data from elasticsearch.
40
+ Each business has on its own way to store data.
41
+ This is a generic way to store the data into the elasticsearch indexes
42
+ """
43
+ def __init__(self, data_connection_structure, data_columns, actions):
44
+ """
45
+ data_sets:
46
+ * orders:
47
+ each purchased orders row by row
48
+ columns: order_id, client, start_date, purchase_date, purchase_amount, discount_amount
49
+ optional columns: purchase_date, discount_amount
50
+ * products:
51
+ ****** OPTIONAL DATA *******
52
+ each purchased orders of products row by row.
53
+ columns: order_id, product_id, product_category, product_price, rank
54
+ optional columns: product_category, product_price, rank
55
+ * promos:
56
+ ****** OPTIONAL DATA *******
57
+ each order of promotion status
58
+ please assign only if there is discount at order
59
+ columns: order_id, promotion_id
60
+ * sessions:
61
+ columns: session_id, client_id
62
+ * actions:
63
+ ****** OPTIONAL DATA *******
64
+ columns: session_id, client_id, action_1 (boolean: True/False), .. action_10 (boolean: True/False)
65
+ * action_details:
66
+ ****** OPTIONAL DATA *******
67
+ detail of action
68
+ columns: session_id, action_name (action_1, action_2, ..., action_10), detail_1, detail_2, detail_3
69
+
70
+
71
+ indicator columns:
72
+ These are type of indicator columns;
73
+ e.g.
74
+ :param data_connection_structure: data connections
75
+ :param data_columns: matched columns
76
+ """
77
+ self.data_connection_structure = data_connection_structure
78
+ self.data_columns = data_columns
79
+ self.actions = actions
80
+ self.sqlite_queries = read_yaml(query_path, "queries.yaml")
81
+ self.tables = pd.read_sql(self.sqlite_queries['tables'], con)
82
+ self.query_es = QueryES()
83
+ self.es_cons = pd.DataFrame()
84
+ self.schedule = pd.DataFrame()
85
+ self.start_date, self.end_date = None, None
86
+ self.ebd_date = current_date_to_day()
87
+ self.port = default_es_port
88
+ self.host = default_es_host
89
+ self.latest_session_transaction_date = None
90
+ self.result_data = pd.DataFrame()
91
+ self.job_start_date = None
92
+ self.info_logs_for_chat = lambda info: {'user': 'info',
93
+ 'date': str(current_date_to_day())[0:19],
94
+ 'user_logo': 'info.jpeg',
95
+ 'chat_type': 'info', 'chart': '',
96
+ 'general_message': info, 'message': ''}
97
+
98
+ def insert_query(self, table, columns, values):
99
+ values = [values[col] for col in columns]
100
+ _query = "INSERT INTO " + table + " "
101
+ _query += " (" + ", ".join(columns) + ") "
102
+ _query += " VALUES (" + ", ".join([" '{}' ".format(v) for v in values]) + ") "
103
+ _query = _query.replace("\\", "")
104
+ return _query
105
+
106
+ def update_query(self, table, condition, columns, values):
107
+ values = [(col, values[col]) for col in columns if values.get(col, None) is not None]
108
+ _query = "UPDATE " + table
109
+ _query += " SET " + ", ".join([i[0] + " = '" + i[1] + "'" for i in values])
110
+ _query +=" WHERE " + condition
111
+ _query = _query.replace("\\", "")
112
+ return _query
113
+
114
+ def check_for_table_exits(self, table, query=None):
115
+ try:
116
+ if table not in list(self.tables['name']):
117
+ if query is None:
118
+ con.execute(self.sqlite_queries[table])
119
+ else:
120
+ con.execute(query)
121
+ except Exception as e:
122
+ print(e)
123
+
124
+ def logs_update(self, logs):
125
+ """
126
+ logs table in sqlite table is updated.
127
+ chats table in sqlite table is updated.
128
+ """
129
+ try: self.check_for_table_exits(table='logs')
130
+ except Exception as e: print(e)
131
+
132
+ try: self.check_for_table_exits(table='chat')
133
+ except Exception as e: print(e)
134
+
135
+ try:
136
+ logs['login_user'] = current_user
137
+ logs['log_time'] = str(current_date_to_day())[0:19]
138
+ logs['general_message'] = logs['info']
139
+ con.execute(self.insert_query(table='logs',
140
+ columns=self.sqlite_queries['columns']['logs'][1:],
141
+ values=logs
142
+ ))
143
+ except Exception as e:
144
+ print(e)
145
+
146
+ try: con.execute(self.insert_query(table='chat', columns=self.sqlite_queries['columns']['chat'][1:],
147
+ values=self.info_logs_for_chat(logs['info'])))
148
+ except Exception as e: print(e)
149
+
150
+ def update_schedule(self, date):
151
+ self.check_for_table_exits(table='schedule_data')
152
+ try:
153
+ con.execute(self.update_query(table='schedule_data',
154
+ condition=" id = 1",
155
+ columns=['max_date_of_order_data'],
156
+ values= {'max_date_of_order_data': date}
157
+ ))
158
+ except Exception as e:
159
+ print(e)
160
+
161
+ def collect_es_connection_infos(self):
162
+ self.es_cons = pd.read_sql("SELECT * FROM es_connection", con)
163
+ self.port = list(self.es_cons['port'])[0]
164
+ self.host = list(self.es_cons['host'])[0]
165
+
166
+ def create_index_connection(self):
167
+ self.collect_es_connection_infos()
168
+ self.query_es = QueryES(port=self.port, host=self.host)
169
+
170
+ def index_count(self, index):
171
+ _count = int(self.query_es.es.cat.count(index, params={"format": "json"})[0]['count'])
172
+ return _count
173
+
174
+ def check_and_create_index(self, index):
175
+ self.create_index_connection()
176
+ accept = False if self.query_es.check_index_exists(index=index) is None else True
177
+ if accept:
178
+ if self.index_count(index) != 0:
179
+ accept = True
180
+ return accept
181
+
182
+ def get_schedule_data(self):
183
+ self.schedule = pd.read_sql("SELECT * FROM schedule_data", con)
184
+
185
+ def get_start_date(self):
186
+ if list(self.schedule['time_period'])[0] != 'once':
187
+ self.start_date = convert_to_date(list(self.schedule['max_date_of_order_data'])[0])
188
+
189
+ def get_end_date(self):
190
+ if list(self.schedule['time_period'])[0] != 'once':
191
+ self.end_date = current_date_to_day()
192
+
193
+ def design_order_basket(self, x):
194
+ try:
195
+ result = {}
196
+ for i in x:
197
+ for p in list(i.keys()):
198
+ result[p] = i[p]
199
+ return result
200
+ except Exception as e:
201
+ print(e)
202
+ return None
203
+
204
+ def change_columns_format(self, data, data_source_type):
205
+ columns = list(data.columns)
206
+ if data_source_type in ['orders', 'products', 'deliveries']:
207
+ data['order_id'] = data['order_id'].apply(lambda x: str(x))
208
+ if data_source_type in ['orders', 'downloads']:
209
+ data['client'] = data['client'].apply(lambda x: str(x))
210
+ if data_source_type == 'orders':
211
+ data['session_start_date'] = data['session_start_date'].apply(lambda x: parse(x))
212
+ data['payment_amount'] = data['payment_amount'].apply(
213
+ lambda x: float(x) if x == x and x not in ['None', None, 'nan'] else None)
214
+ if 'discount_amount' in columns:
215
+ data['discount_amount'] = data['discount_amount'].apply(
216
+ lambda x: float(x) if x == x and x not in ['None', None, 'nan'] else None)
217
+ if 'date' in columns:
218
+ data['date'] = data['date'].apply(
219
+ lambda x: parse(x) if x == x and x not in ['None', None, 'nan'] else None)
220
+ if 'promotion_id' in columns:
221
+ data['promotion_id'] = data['promotion_id'].apply(
222
+ lambda x: x if x == x and x not in ['None', None, 'nan'] else None)
223
+ if data_source_type == 'deliveries':
224
+ for col in delivery_metrics:
225
+ if col in columns:
226
+ data[col] = data[col].apply(
227
+ lambda x: parse(x) if col in ['return_date', 'prepare_date', 'delivery_date'] else float(x))
228
+ if data_source_type == 'downloads':
229
+ data['download_date'] = data['download_date'].apply(
230
+ lambda x: parse(x) if x == x and x not in ['None', None, 'nan'] else None)
231
+ if 'signup_date' in columns:
232
+ data['signup_date'] = data['signup_date'].apply(
233
+ lambda x: parse(x) if x == x and x not in ['None', None, 'nan'] else None)
234
+ if data_source_type == 'products':
235
+ if 'price' in columns:
236
+ data['price'] = data['price'].apply(
237
+ lambda x: float(x) if x == x and x not in ['None', None, 'nan'] else None)
238
+ return data
239
+
240
+ def get_index_of_last_date(self, date_column, index):
241
+ try:
242
+ match = {"size": 1, "from": 0, "_source": True, "sort": {date_column: "desc"}, }
243
+ res = self.query_es.es.search(index=index, body=match)['hits']['hits']
244
+ return convert_to_date([r['_source'][date_column] for r in res][0])
245
+ except Exception as e:
246
+ print("session_start_date/download_date is not inserted into the indexes.")
247
+ return None
248
+
249
+ def collect_prev_downloads(self):
250
+ try:
251
+ match = {"size": 100000, "from": 0, "_source": True}
252
+ res = self.query_es.es.search(index='downloads', body=match)['hits']['hits']
253
+ return [r['_source']['client'] for r in res]
254
+ except Exception as e:
255
+ print(e)
256
+ return []
257
+
258
+ def filter_dates(self, data, data_source_type):
259
+ """
260
+
261
+ """
262
+ try:
263
+ if data_source_type in ['orders', 'downloads']:
264
+ date_column = "session_start_date" if data_source_type == 'orders' else "download_date"
265
+ max_index_date = self.get_index_of_last_date(date_column, data_source_type)
266
+ if self.start_date is not None:
267
+ data = data[data[date_column] >= self.start_date]
268
+ if self.end_date is not None:
269
+ data = data[data[date_column] < self.end_date]
270
+ if max_index_date is not None:
271
+ data = data[data[date_column] >= max_index_date]
272
+ if data_source_type == 'downloads':
273
+ data[~data['client'].isin(self.collect_prev_downloads())]
274
+ except Exception as e:
275
+ print(e)
276
+ return data
277
+
278
+ def check_columns(self, col):
279
+ _col = col
280
+ if col == 'client_2':
281
+ _col = 'client'
282
+ if col == 'order_id_2':
283
+ _col = 'order_id'
284
+ return _col
285
+
286
+ def match_data_columns(self, data):
287
+ cols = list(data.columns)
288
+ renaming = {}
289
+ for col in self.data_columns:
290
+ if self.data_columns[col] in cols:
291
+ renaming[self.data_columns[col]] = self.check_columns(col)
292
+ return data.rename(columns=renaming)
293
+
294
+ def check_for_not_required_columns(self, data, data_source_type):
295
+ _columns = list(data.columns)
296
+ for col in not_required_columns[data_source_type]:
297
+ if col not in _columns:
298
+ data[col] = not_required_default_values[col]
299
+ return data
300
+
301
+ def get_data(self, conf, data_source_type):
302
+ """
303
+ {'data_source': connection[index + '_data_source_type'],
304
+ 'date': date,
305
+ 'data_query_path': connection[index + '_data_query_path'],
306
+ 'test': test,
307
+ 'config': {'host': connection[index + '_host'],
308
+ 'port': connection[index + '_port'],
309
+ 'password': connection[index + '_password'],
310
+ 'user': connection[index + '_user'], 'db': connection[index + '_db']}
311
+ }
312
+ """
313
+ gd = GetData(data_source=conf['data_source'],
314
+ data_query_path=conf['data_query_path'], config=conf['config'], test=1000)
315
+ gd.query_data_source()
316
+ gd = GetData(data_source=conf['data_source'],
317
+ data_query_path=conf['data_query_path'], config=conf['config'])
318
+ gd.query_data_source()
319
+ data = self.match_data_columns(data=gd.data)
320
+ data = self.change_columns_format(data, data_source_type)
321
+ data = self.filter_dates(data, data_source_type)
322
+ data = self.check_for_not_required_columns(data, data_source_type)
323
+ return data
324
+
325
+ def merge_orders(self, order_source, product_source, delivery_source):
326
+ orders = pd.DataFrame()
327
+ try:
328
+ orders = self.get_data(conf=order_source, data_source_type='orders')
329
+ except Exception as e:
330
+ print(e)
331
+
332
+ if len(orders) != 0:
333
+ try:
334
+ if product_source.get('data_query_path', None) is not None:
335
+ products = self.get_data(conf=product_source, data_source_type='products')
336
+ products['basket'] = products.apply(
337
+ lambda row: {row['product']: {'price': row['price'],
338
+ 'category': row['category']}}, axis=1)
339
+ products = products.groupby("order_id").agg({"basket":
340
+ lambda x: self.design_order_basket(x)}).reset_index()
341
+ products['total_products'] = products['basket'].apply(lambda x: len(x.keys()))
342
+ orders = pd.merge(orders, products, on='order_id', how='left')
343
+ orders['basket'] = orders['basket'].fillna({})
344
+ del products
345
+ else: orders['basket'] = None
346
+ except Exception as e:
347
+ print(e)
348
+ orders['basket'] = None
349
+
350
+ try:
351
+ if delivery_source.get('data_query_path', None) is not None:
352
+ deliveries = self.get_data(conf=delivery_source, data_source_type='deliveries')
353
+ deliveries = deliveries.groupby("order_id").agg({m: 'first' for m in delivery_metrics}).reset_index()
354
+ deliveries['delivery'] = deliveries.apply(lambda row: {m: row[m] for m in delivery_metrics}, axis=1)
355
+ orders = pd.merge(orders, deliveries[['order_id', 'delivery']], on='order_id', how='left')
356
+ else: orders['delivery'] = None
357
+ except Exception as e:
358
+ print(e)
359
+ orders['delivery'] = None
360
+
361
+ return orders
362
+
363
+ def partial_insert(self, _insert, index):
364
+ counter = 0
365
+ while counter < 10:
366
+ try:
367
+ self.query_es.insert_data_to_index(_insert, index)
368
+ counter = 10
369
+ except Exception as e:
370
+ print(e)
371
+ counter += 1
372
+
373
+ def insert_to_index(self, data, index):
374
+ """
375
+ Sessions (Orders) Index Document;
376
+ {'_index': 'orders',
377
+ '_type': '_doc',
378
+ '_id': 'VgxgE3cBdDDj70WtOuFJ',
379
+ '_score': 1.0,
380
+ '_source': {'id': 74915741,
381
+ 'date': '2020-12-16T09:47:00',
382
+ 'actions': {'has_sessions': True,
383
+ 'has_basket': True,
384
+ 'order_screen': True,
385
+ 'purchased': False},
386
+ 'client': 'u_382139',
387
+ 'dimension': 'location_1',
388
+ 'promotion_id': None,
389
+ 'payment_amount': 52.75500000000001,
390
+ 'discount_amount': 0,
391
+ 'basket': {'p_10': {'price': 6.12, 'category': 'p_c_8', 'rank': 109},....},
392
+ 'delivery': {'delivery_date': '2020-12-16T09:39:11',
393
+ 'return_date': '2020-12-16T09:39:11',
394
+ 'prepare_date': '2020-12-16T09:39:11',
395
+ 'latitude':43,2342131232, 'longitude': 34,2342131232}
396
+ 'total_products': 7,
397
+ 'session_start_date': '2020-12-16T09:39:11'}}
398
+
399
+ Customers (Downloads) Index Document;
400
+ {'id': 3840375,
401
+ 'download_date': '2020-12-31T14:56:32',
402
+ 'signup_date': '2021-01-02T13:55:32', 'client': 'u_344313'}
403
+ """
404
+ try:
405
+ _insert = []
406
+ data = data.to_dict('records')
407
+ if index == 'orders':
408
+ for i in data:
409
+ _obj = {i: None for i in orders_index_columns}
410
+ _keys = list(i.keys())
411
+ _has_purchased = True if i['has_purchased'] in ['True', True] else False
412
+ if len(self.actions[index]) != 0:
413
+ _obj['actions'] = {_a: False for _a in self.actions[index]}
414
+ _obj['actions']['purchased'] = _has_purchased
415
+ _obj['actions']['has_sessions'] = True
416
+ else:
417
+ _obj['actions'] = {'purchased': _has_purchased, 'has_sessions': True}
418
+
419
+ if i['delivery'] is not None:
420
+ _delivery = {}
421
+ if i['delivery'] == i['delivery']:
422
+ _delivery = i['delivery']
423
+ try:
424
+ for k in ['return_date', 'prepare_date', 'delivery_date']:
425
+ if _delivery[k] not in ['None', None, 'nan']:
426
+ _delivery[k] = convert_to_iso_format(i['delivery'][k])
427
+ else:
428
+ _delivery[k] = convert_to_iso_format(i['session_start_date'])
429
+ except Exception as e:
430
+ print(e)
431
+ i['delivery'] = _delivery
432
+
433
+ for k in _obj:
434
+ if k in _keys:
435
+ if k in ['date', 'session_start_date']:
436
+ _obj[k] = convert_to_iso_format(i[k])
437
+ else:
438
+ _obj[k] = i[k] if i[k] == i[k] and i[k] not in ['None', None, 'nan'] else None
439
+ else:
440
+ if k == 'id':
441
+ _obj['id'] = i['order_id']
442
+ if k == 'basket':
443
+ _obj['basket'] = i['basket'] if i['basket'] == i['basket'] else {}
444
+ if k == 'actions':
445
+ for a in self.actions[index]:
446
+ if a in _keys:
447
+ if i[a]:
448
+ _obj['actions'][a] = True
449
+ _insert.append(_obj)
450
+ del _obj
451
+ if len(_insert) >= 10:
452
+ self.partial_insert(_insert, index)
453
+ _insert = []
454
+
455
+ if len(_insert) != 0:
456
+ self.partial_insert(_insert, index)
457
+ # insert logs into the sqlite logs table for sessions data insert process
458
+ self.logs_update(logs={"page": "data-execute",
459
+ "info": " SESSIONS index Done! - Number of documents :" + formating_numbers(len(data)),
460
+ "color": "green"})
461
+ _insert = []
462
+ if index == 'downloads':
463
+ for i in data:
464
+ _keys = list(i.keys())
465
+ _obj = {i: None for i in downloads_index_columns}
466
+ # TODO : id must be the counter not randomly selected
467
+ _obj['id'] = np.random.randint(200000000)
468
+ _obj['client'] = i['client']
469
+ _obj['download_date'] = convert_to_iso_format(i['download_date'])
470
+ if i.get('signup_date', None) is not None:
471
+ if i['signup_date'] not in ['nan', None, '', '-', 'Null']:
472
+ try:
473
+ _obj['signup_date'] = convert_to_iso_format(i['signup_date'])
474
+ except Exception as e_signup:
475
+ _obj['signup_date'] = None
476
+
477
+ for _a in self.actions[index]:
478
+ if i[_a] == i[_a]:
479
+ _obj[_a] = convert_to_iso_format(i[_a])
480
+
481
+ _insert.append(_obj)
482
+ if len(_insert) >= 10:
483
+ self.partial_insert(_insert, index)
484
+ _insert = []
485
+
486
+ if len(_insert) != 0:
487
+ self.partial_insert(_insert, index)
488
+ # insert logs into the sqlite logs table for customers data insert process
489
+ self.logs_update(logs={"page": "data-execute",
490
+ "info": " CUSTOMERS index Done! - Number of documents :" + formating_numbers(len(data)),
491
+ "color": "green"})
492
+
493
+ except Exception as e:
494
+ try:
495
+ err_str = " - " + str(e).replace("'", " ")
496
+ err_str = err_str[0:100] if len(err_str) >= 100 else err_str
497
+ except: err_str = " "
498
+ self.logs_update(logs={"page": "data-execute",
499
+ "info": "indexes Creation is failed! While " + index + " is creating. " + err_str,
500
+ "color": "red"})
501
+
502
+ def execute_index(self):
503
+ """
504
+
505
+ """
506
+ self.job_start_date = current_date_to_day()
507
+ self.get_schedule_data()
508
+ self.get_end_date()
509
+
510
+ try:
511
+ for _data_type in ['orders', 'downloads']:
512
+ if _data_type == 'orders':
513
+ _result_data = self.merge_orders(self.data_connection_structure['orders'],
514
+ self.data_connection_structure['products'],
515
+ self.data_connection_structure['deliveries'])
516
+ else:
517
+ _result_data = self.get_data(conf=self.data_connection_structure['downloads'],
518
+ data_source_type='downloads')
519
+ if self.check_and_create_index(_data_type):
520
+ self.get_start_date()
521
+ if len(_result_data) != 0:
522
+ self.insert_to_index(data=_result_data, index=_data_type)
523
+ del _result_data
524
+
525
+ last_schedule_triggered_date = str(current_date_to_day())
526
+ self.update_schedule(date=last_schedule_triggered_date)
527
+
528
+ self.end_date = current_date_to_day()
529
+
530
+ spent_hour = round(abs(self.job_start_date - self.end_date).total_seconds() / 60 / 60, 2)
531
+ total_time_str = str(round(spent_hour, 2)) + " hr. " if spent_hour >= 1 else str(round(spent_hour * 60, 2)) + " min. "
532
+ comment = "indexes are created safely. Total spent time : " + total_time_str
533
+ self.logs_update(logs={"page": "data-execute",
534
+ "info": comment,
535
+ "color": "green"})
536
+
537
+ except Exception as e:
538
+ try: err_str = " - " + str(e).replace("'", " ")
539
+ except: err_str = " "
540
+ self.logs_update(logs={"page": "data-execute",
541
+ "info": "indexes Creation is failed! " + err_str,
542
+ "color": "red"})
543
+
544
+
@@ -0,0 +1,36 @@
1
+ import logging
2
+
3
+
4
+ import sys, os, inspect
5
+ currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
6
+ parentdir = os.path.dirname(currentdir)
7
+ sys.path.insert(0, parentdir)
8
+
9
+ from sqlalchemy import create_engine, MetaData
10
+ from os.path import abspath, join
11
+ import pandas as pd
12
+ from flask_login import current_user
13
+
14
+
15
+ from customeranalytics.utils import read_yaml, current_date_to_day, abspath_for_sample_data
16
+
17
+ engine = create_engine('sqlite://///' + join(abspath_for_sample_data(), "web", 'db.sqlite3'),
18
+ connect_args={'check_same_thread': False})
19
+ metadata = MetaData()
20
+ con = engine.connect()
21
+
22
+
23
+ class LogsBasicConfeger:
24
+ try: directory = pd.read_sql("select * from es_connection", con).to_dict('records')[-1]['directory']
25
+ except: directory = currentdir
26
+
27
+ try: user = current_user['email']
28
+ except: user = 'logs'
29
+
30
+ file_path = join(currentdir, "logs.log")
31
+ logging.basicConfig(filename=file_path,
32
+ level=logging.INFO,
33
+ format='%(asctime)s:%(levelname)s:%(message)s')
34
+
35
+
36
+