pkscreener 0.46.20250221.728__cp312-cp312-manylinux2014_x86_64.whl → 0.46.20250221.729__cp312-cp312-manylinux2014_x86_64.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 (61) hide show
  1. {pkscreener-0.46.20250221.728.data → pkscreener-0.46.20250221.729.data}/purelib/pkscreener/README.txt +5 -5
  2. pkscreener-0.46.20250221.729.data/purelib/pkscreener/classes/PKAnalytics.py +146 -0
  3. {pkscreener-0.46.20250221.728.data → pkscreener-0.46.20250221.729.data}/purelib/pkscreener/classes/PKUserRegistration.py +2 -0
  4. pkscreener-0.46.20250221.729.data/purelib/pkscreener/classes/__init__.py +1 -0
  5. {pkscreener-0.46.20250221.728.data → pkscreener-0.46.20250221.729.data}/purelib/pkscreener/globals.py +29 -4
  6. {pkscreener-0.46.20250221.728.data → pkscreener-0.46.20250221.729.data}/purelib/pkscreener/requirements.txt +1 -1
  7. {pkscreener-0.46.20250221.728.dist-info → pkscreener-0.46.20250221.729.dist-info}/METADATA +8 -8
  8. pkscreener-0.46.20250221.729.dist-info/RECORD +58 -0
  9. pkscreener-0.46.20250221.728.data/purelib/pkscreener/classes/PKAnalytics.py +0 -122
  10. pkscreener-0.46.20250221.728.data/purelib/pkscreener/classes/__init__.py +0 -1
  11. pkscreener-0.46.20250221.728.dist-info/RECORD +0 -58
  12. {pkscreener-0.46.20250221.728.data → pkscreener-0.46.20250221.729.data}/purelib/pkscreener/Disclaimer.txt +0 -0
  13. {pkscreener-0.46.20250221.728.data → pkscreener-0.46.20250221.729.data}/purelib/pkscreener/LICENSE-Others.txt +0 -0
  14. {pkscreener-0.46.20250221.728.data → pkscreener-0.46.20250221.729.data}/purelib/pkscreener/LICENSE.txt +0 -0
  15. {pkscreener-0.46.20250221.728.data → pkscreener-0.46.20250221.729.data}/purelib/pkscreener/LogoWM.txt +0 -0
  16. {pkscreener-0.46.20250221.728.data → pkscreener-0.46.20250221.729.data}/purelib/pkscreener/__init__.py +0 -0
  17. {pkscreener-0.46.20250221.728.data → pkscreener-0.46.20250221.729.data}/purelib/pkscreener/classes/ArtTexts.py +0 -0
  18. {pkscreener-0.46.20250221.728.data → pkscreener-0.46.20250221.729.data}/purelib/pkscreener/classes/AssetsManager.py +0 -0
  19. {pkscreener-0.46.20250221.728.data → pkscreener-0.46.20250221.729.data}/purelib/pkscreener/classes/Backtest.py +0 -0
  20. {pkscreener-0.46.20250221.728.data → pkscreener-0.46.20250221.729.data}/purelib/pkscreener/classes/Barometer.py +0 -0
  21. {pkscreener-0.46.20250221.728.data → pkscreener-0.46.20250221.729.data}/purelib/pkscreener/classes/BaseScreeningStatistics.py +0 -0
  22. {pkscreener-0.46.20250221.728.data → pkscreener-0.46.20250221.729.data}/purelib/pkscreener/classes/CandlePatterns.py +0 -0
  23. {pkscreener-0.46.20250221.728.data → pkscreener-0.46.20250221.729.data}/purelib/pkscreener/classes/Changelog.py +0 -0
  24. {pkscreener-0.46.20250221.728.data → pkscreener-0.46.20250221.729.data}/purelib/pkscreener/classes/ConfigManager.py +0 -0
  25. {pkscreener-0.46.20250221.728.data → pkscreener-0.46.20250221.729.data}/purelib/pkscreener/classes/ConsoleMenuUtility.py +0 -0
  26. {pkscreener-0.46.20250221.728.data → pkscreener-0.46.20250221.729.data}/purelib/pkscreener/classes/ConsoleUtility.py +0 -0
  27. {pkscreener-0.46.20250221.728.data → pkscreener-0.46.20250221.729.data}/purelib/pkscreener/classes/Fetcher.py +0 -0
  28. {pkscreener-0.46.20250221.728.data → pkscreener-0.46.20250221.729.data}/purelib/pkscreener/classes/GlobalStore.py +0 -0
  29. {pkscreener-0.46.20250221.728.data → pkscreener-0.46.20250221.729.data}/purelib/pkscreener/classes/ImageUtility.py +0 -0
  30. {pkscreener-0.46.20250221.728.data → pkscreener-0.46.20250221.729.data}/purelib/pkscreener/classes/MarketMonitor.py +0 -0
  31. {pkscreener-0.46.20250221.728.data → pkscreener-0.46.20250221.729.data}/purelib/pkscreener/classes/MarketStatus.py +0 -0
  32. {pkscreener-0.46.20250221.728.data → pkscreener-0.46.20250221.729.data}/purelib/pkscreener/classes/MenuOptions.py +0 -0
  33. {pkscreener-0.46.20250221.728.data → pkscreener-0.46.20250221.729.data}/purelib/pkscreener/classes/Messenger.py +0 -0
  34. {pkscreener-0.46.20250221.728.data → pkscreener-0.46.20250221.729.data}/purelib/pkscreener/classes/OtaUpdater.py +0 -0
  35. {pkscreener-0.46.20250221.728.data → pkscreener-0.46.20250221.729.data}/purelib/pkscreener/classes/PKDataService.py +0 -0
  36. {pkscreener-0.46.20250221.728.data → pkscreener-0.46.20250221.729.data}/purelib/pkscreener/classes/PKDemoHandler.py +0 -0
  37. {pkscreener-0.46.20250221.728.data → pkscreener-0.46.20250221.729.data}/purelib/pkscreener/classes/PKMarketOpenCloseAnalyser.py +0 -0
  38. {pkscreener-0.46.20250221.728.data → pkscreener-0.46.20250221.729.data}/purelib/pkscreener/classes/PKPremiumHandler.py +0 -0
  39. {pkscreener-0.46.20250221.728.data → pkscreener-0.46.20250221.729.data}/purelib/pkscreener/classes/PKScanRunner.py +0 -0
  40. {pkscreener-0.46.20250221.728.data → pkscreener-0.46.20250221.729.data}/purelib/pkscreener/classes/PKScheduledTaskProgress.py +0 -0
  41. {pkscreener-0.46.20250221.728.data → pkscreener-0.46.20250221.729.data}/purelib/pkscreener/classes/PKScheduler.py +0 -0
  42. {pkscreener-0.46.20250221.728.data → pkscreener-0.46.20250221.729.data}/purelib/pkscreener/classes/PKSpreadsheets.py +0 -0
  43. {pkscreener-0.46.20250221.728.data → pkscreener-0.46.20250221.729.data}/purelib/pkscreener/classes/PKTask.py +0 -0
  44. {pkscreener-0.46.20250221.728.data → pkscreener-0.46.20250221.729.data}/purelib/pkscreener/classes/Pktalib.py +0 -0
  45. {pkscreener-0.46.20250221.728.data → pkscreener-0.46.20250221.729.data}/purelib/pkscreener/classes/Portfolio.py +0 -0
  46. {pkscreener-0.46.20250221.728.data → pkscreener-0.46.20250221.729.data}/purelib/pkscreener/classes/PortfolioXRay.py +0 -0
  47. {pkscreener-0.46.20250221.728.data → pkscreener-0.46.20250221.729.data}/purelib/pkscreener/classes/ScreeningStatistics.py +0 -0
  48. {pkscreener-0.46.20250221.728.data → pkscreener-0.46.20250221.729.data}/purelib/pkscreener/classes/StockScreener.py +0 -0
  49. {pkscreener-0.46.20250221.728.data → pkscreener-0.46.20250221.729.data}/purelib/pkscreener/classes/StockSentiment.py +0 -0
  50. {pkscreener-0.46.20250221.728.data → pkscreener-0.46.20250221.729.data}/purelib/pkscreener/classes/UserMenuChoicesHandler.py +0 -0
  51. {pkscreener-0.46.20250221.728.data → pkscreener-0.46.20250221.729.data}/purelib/pkscreener/classes/Utility.py +0 -0
  52. {pkscreener-0.46.20250221.728.data → pkscreener-0.46.20250221.729.data}/purelib/pkscreener/classes/WorkflowManager.py +0 -0
  53. {pkscreener-0.46.20250221.728.data → pkscreener-0.46.20250221.729.data}/purelib/pkscreener/classes/keys.py +0 -0
  54. {pkscreener-0.46.20250221.728.data → pkscreener-0.46.20250221.729.data}/purelib/pkscreener/courbd.ttf +0 -0
  55. {pkscreener-0.46.20250221.728.data → pkscreener-0.46.20250221.729.data}/purelib/pkscreener/pkscreener.ini +0 -0
  56. {pkscreener-0.46.20250221.728.data → pkscreener-0.46.20250221.729.data}/purelib/pkscreener/pkscreenerbot.py +0 -0
  57. {pkscreener-0.46.20250221.728.data → pkscreener-0.46.20250221.729.data}/purelib/pkscreener/pkscreenercli.py +0 -0
  58. {pkscreener-0.46.20250221.728.dist-info → pkscreener-0.46.20250221.729.dist-info}/LICENSE +0 -0
  59. {pkscreener-0.46.20250221.728.dist-info → pkscreener-0.46.20250221.729.dist-info}/WHEEL +0 -0
  60. {pkscreener-0.46.20250221.728.dist-info → pkscreener-0.46.20250221.729.dist-info}/entry_points.txt +0 -0
  61. {pkscreener-0.46.20250221.728.dist-info → pkscreener-0.46.20250221.729.dist-info}/top_level.txt +0 -0
@@ -328,15 +328,15 @@ After you have finished the run, go to that copied path, zip the contents of the
328
328
  [MADE-IN-INDIA-badge]: https://img.shields.io/badge/MADE%20WITH%20%E2%9D%A4%20IN-INDIA-orange
329
329
  [MADE-IN-INDIA]: https://en.wikipedia.org/wiki/India
330
330
  [Windows-badge]: https://img.shields.io/badge/Windows-0078D6?logo=windows&logoColor=white
331
- [Windows]: https://github.com/pkjmesra/PKScreener/releases/download/0.46.20250220.727/pkscreenercli.exe
331
+ [Windows]: https://github.com/pkjmesra/PKScreener/releases/download/0.46.20250221.728/pkscreenercli.exe
332
332
  [Linux-badge_x64]: https://img.shields.io/badge/Linux(x64)-FCC624?logo=linux&logoColor=black
333
- [Linux_x64]: https://github.com/pkjmesra/PKScreener/releases/download/0.46.20250220.727/pkscreenercli_x64.bin
333
+ [Linux_x64]: https://github.com/pkjmesra/PKScreener/releases/download/0.46.20250221.728/pkscreenercli_x64.bin
334
334
  [Linux-badge_arm64]: https://img.shields.io/badge/Linux(arm64)-FCC624?logo=linux&logoColor=black
335
- [Linux_arm64]: https://github.com/pkjmesra/PKScreener/releases/download/0.46.20250220.727/pkscreenercli_arm64.bin
335
+ [Linux_arm64]: https://github.com/pkjmesra/PKScreener/releases/download/0.46.20250221.728/pkscreenercli_arm64.bin
336
336
  [Mac OS-badge_x64]: https://img.shields.io/badge/mac%20os(x64)-D3D3D3?logo=apple&logoColor=000000
337
- [Mac OS_x64]: https://github.com/pkjmesra/PKScreener/releases/download/0.46.20250220.727/pkscreenercli_x64.run
337
+ [Mac OS_x64]: https://github.com/pkjmesra/PKScreener/releases/download/0.46.20250221.728/pkscreenercli_x64.run
338
338
  [Mac OS-badge_arm64]: https://img.shields.io/badge/mac%20os(arm64)-D3D3D3?logo=apple&logoColor=000000
339
- [Mac OS_arm64]: https://github.com/pkjmesra/PKScreener/releases/download/0.46.20250220.727/pkscreenercli_arm64.run
339
+ [Mac OS_arm64]: https://github.com/pkjmesra/PKScreener/releases/download/0.46.20250221.728/pkscreenercli_arm64.run
340
340
  [GitHub release (latest by date)-badge]: https://img.shields.io/github/v/release/pkjmesra/PKScreener
341
341
  [GitHub release (latest by date)]: https://github.com/pkjmesra/PKScreener/releases/latest
342
342
  [pypi-badge]: https://img.shields.io/pypi/v/pkscreener.svg?style=flat-square
@@ -0,0 +1,146 @@
1
+ #!/usr/bin/python3
2
+ """
3
+ The MIT License (MIT)
4
+
5
+ Copyright (c) 2023 pkjmesra
6
+
7
+ Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ of this software and associated documentation files (the "Software"), to deal
9
+ in the Software without restriction, including without limitation the rights
10
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ copies of the Software, and to permit persons to whom the Software is
12
+ furnished to do so, subject to the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be included in all
15
+ copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ SOFTWARE.
24
+
25
+ """
26
+
27
+ import os
28
+ # import base64
29
+ from sys import platform
30
+ import platform
31
+ import getpass
32
+ # import git
33
+ import json
34
+ # import io
35
+ import time
36
+ from PKDevTools.classes.Fetcher import fetcher
37
+ from PKDevTools.classes.Utils import random_user_agent
38
+ from PKDevTools.classes.PKDateUtilities import PKDateUtilities
39
+ from PKDevTools.classes import Archiver
40
+ from PKDevTools.classes.Singleton import SingletonType, SingletonMixin
41
+ from PKDevTools.classes.pubsub.publisher import PKUserService
42
+ from PKDevTools.classes.pubsub.subscriber import notification_service
43
+ from pkscreener.classes import VERSION
44
+
45
+ class PKAnalyticsService(SingletonMixin, metaclass=SingletonType):
46
+ def __init__(self):
47
+ super(PKAnalyticsService, self).__init__()
48
+ self.username = ""
49
+ self.locationInfo = ""
50
+ self.os = platform.system()
51
+ self.os_version = platform.release()
52
+ self.app_version = VERSION
53
+ self.start_time = time.time()
54
+ self.isRunner = "RUNNER" in os.environ.keys()
55
+
56
+ def collectMetrics(self,user=None):
57
+ try:
58
+ self.userName = self.getUserName()
59
+ metrics = self.getApproxLocationInfo()
60
+ self.locationInfo = metrics
61
+ self.send_event("app_start")
62
+ except KeyboardInterrupt: # pragma: no cover
63
+ raise KeyboardInterrupt
64
+ except Exception as e: # pragma: no cover
65
+ pass
66
+
67
+ def getUserName(self):
68
+ try:
69
+ username = os.getlogin()
70
+ if username is None or len(username) == 0:
71
+ username = os.environ.get('username') if platform.startswith("win") else os.environ.get("USER")
72
+ if username is None or len(username) == 0:
73
+ username = os.environ.get('USERPROFILE')
74
+ if username is None or len(username) == 0:
75
+ username = os.path.expandvars("%userprofile%") if platform.startswith("win") else getpass.getuser()
76
+ except KeyboardInterrupt: # pragma: no cover
77
+ raise KeyboardInterrupt
78
+ except: # pragma: no cover
79
+ username = f"Unidentified-{self.os}"
80
+ pass
81
+ return username
82
+
83
+ def getApproxLocationInfo(self):
84
+ try:
85
+ url = 'http://ipinfo.io/json'
86
+ f = fetcher()
87
+ response = f.fetchURL(url=url,timeout=5,headers={'user-agent': f'{random_user_agent()}'})
88
+ data = json.loads(response.text)
89
+ except: # pragma: no cover
90
+ data = {"locationInfo":f"Unidentified-{self.os}"}
91
+ pass
92
+ return data
93
+
94
+ def send_event(self,event_name):
95
+ event_params = {
96
+ "user_id": self.userName,
97
+ "os": self.os,
98
+ "os_version": self.os_version,
99
+ "app_version": self.app_version,
100
+ "elapsed_time": str(time.time() - self.start_time),
101
+ "is_Runner": self.isRunner
102
+ }
103
+ for key in self.locationInfo.keys():
104
+ if key not in ["readme"]:
105
+ event_params[key] = self.locationInfo[key]
106
+ PKUserService().send_event(event_name, event_params)
107
+
108
+ # def tryCommitAnalytics(self, userDict={},username="Unidentified"):
109
+ # import git.repo
110
+ # repo_clone_url = "https://github.com/pkjmesra/PKUserAnalytics.git"
111
+ # local_repo = os.path.join(Archiver.get_user_data_dir(),"PKUserAnalytics")
112
+ # try:
113
+ # test_branch = "main"
114
+ # repo = git.Repo.clone_from(repo_clone_url, local_repo)
115
+ # repo.git.checkout(test_branch)
116
+ # except Exception as e: # pragma: no cover
117
+ # repo = git.Repo(local_repo)
118
+ # repo.git.checkout(test_branch)
119
+ # pass
120
+ # remote = git.remote.Remote(repo=repo,name="origin")
121
+ # repo.git.reset('--hard','origin/main')
122
+ # remote.pull()
123
+ # # write to file in working directory
124
+ # scanResultFilesPath = os.path.join(local_repo, f"users-{PKDateUtilities.currentDateTime().strftime('%Y-%m-%d')}.txt")
125
+ # records = {}
126
+ # existingUserRecords = [userDict]
127
+ # mode = "rb+" if os.path.exists(scanResultFilesPath) else "wb+"
128
+ # with open(scanResultFilesPath, mode) as f:
129
+ # allUsers = f.read()
130
+ # if allUsers is not None and len(allUsers) > 0:
131
+ # allUsers = base64.b64decode(allUsers).decode("utf-8").replace("'","\"")
132
+ # records = json.loads(allUsers)
133
+ # if records is None:
134
+ # records = {}
135
+ # existingUserRecords = records.get(username)
136
+ # if existingUserRecords is not None:
137
+ # existingUserRecords.append(userDict)
138
+ # else:
139
+ # existingUserRecords = [userDict]
140
+ # records[username] = existingUserRecords
141
+ # encoded = base64.b64encode(bytes(str(records).replace("'","\""), "utf-8"))
142
+ # f.writelines(io.BytesIO(encoded))
143
+ # repo.index.add([scanResultFilesPath])
144
+ # repo.index.commit("[User-Analytics]")
145
+ # remote = git.remote.Remote(repo=repo,name="origin")
146
+ # remote.push()
@@ -94,6 +94,8 @@ class PKUserRegistration(SingletonMixin, metaclass=SingletonType):
94
94
  @classmethod
95
95
  def login(self, trialCount=0):
96
96
  try:
97
+ from pkscreener.classes.PKAnalytics import PKAnalyticsService
98
+ PKAnalyticsService().collectMetrics()
97
99
  if "RUNNER" in os.environ.keys():
98
100
  return ValidationResult.Success
99
101
  except: # pragma: no cover
@@ -0,0 +1 @@
1
+ VERSION='0.46.20250221.729'
@@ -110,6 +110,7 @@ from pkscreener.classes.PKScanRunner import PKScanRunner
110
110
  from pkscreener.classes.PKMarketOpenCloseAnalyser import PKMarketOpenCloseAnalyser
111
111
  from pkscreener.classes.PKPremiumHandler import PKPremiumHandler
112
112
  from pkscreener.classes.AssetsManager import PKAssetsManager
113
+ from pkscreener.classes.PKAnalytics import PKAnalyticsService
113
114
 
114
115
  if __name__ == '__main__':
115
116
  multiprocessing.freeze_support()
@@ -214,6 +215,7 @@ def getDownloadChoices(defaultAnswer=None):
214
215
  + colorText.END
215
216
  + " already exists. Exiting as user chose not to replace it!"
216
217
  )
218
+ PKAnalyticsService().send_event("app_exit")
217
219
  sys.exit(0)
218
220
  else:
219
221
  pattern = f"{'intraday_' if intraday else ''}stock_data_*.pkl"
@@ -268,6 +270,7 @@ def getScannerMenuChoices(
268
270
  + " [+] Press <Enter> to Exit!"
269
271
  + colorText.END
270
272
  )
273
+ PKAnalyticsService().send_event("app_exit")
271
274
  sys.exit(0)
272
275
  except Exception as e: # pragma: no cover
273
276
  default_logger().debug(e, exc_info=True)
@@ -573,6 +576,7 @@ def initExecution(menuOption=None):
573
576
  + " [+] Press <Enter> to Exit!"
574
577
  + colorText.END
575
578
  )
579
+ PKAnalyticsService().send_event("app_exit")
576
580
  sys.exit(0)
577
581
  elif selectedMenu.menuKey in ["B", "C", "G", "H", "U", "T", "S", "E", "X", "Y", "M", "D", "I", "L","F"]:
578
582
  ConsoleUtility.PKConsoleTools.clearScreen(forceTop=True)
@@ -679,6 +683,7 @@ def initPostLevel1Execution(indexOption, executeOption=None, skip=[], retrial=Fa
679
683
  if indexOption == "S":
680
684
  ensureMenusLoaded("X",indexOption,executeOption)
681
685
  if not PKPremiumHandler.hasPremium(selectedMenu):
686
+ PKAnalyticsService().send_event("app_exit")
682
687
  sys.exit(0)
683
688
  indexKeys = level1_index_options_sectoral.keys()
684
689
  stockIndexCode = input(
@@ -917,6 +922,7 @@ def main(userArgs=None,optionalFinalOutcome_df=None):
917
922
  mkt_monitor_dict = mp_manager.dict()
918
923
  # Let's start monitoring the market monitor
919
924
  startMarketMonitor(mkt_monitor_dict,keyboardInterruptEvent)
925
+ PKAnalyticsService().send_event("market_monitor_started")
920
926
 
921
927
  keyboardInterruptEventFired = False
922
928
  if stockDictPrimary is None:
@@ -947,12 +953,15 @@ def main(userArgs=None,optionalFinalOutcome_df=None):
947
953
  if menuOption in ["F", "M", "S", "B", "G", "C", "P", "D"] or selectedMenu.isPremium:
948
954
  ensureMenusLoaded(menuOption,indexOption,executeOption)
949
955
  if not PKPremiumHandler.hasPremium(selectedMenu):
956
+ PKAnalyticsService().send_event(f"non_premium_user_{menuOption}")
957
+ PKAnalyticsService().send_event("app_exit")
950
958
  sys.exit(0)
951
959
  if menuOption in ["M", "D", "I", "L", "F"]:
952
960
  launcher = f'"{sys.argv[0]}"' if " " in sys.argv[0] else sys.argv[0]
953
961
  launcher = f"python3.12 {launcher}" if (launcher.endswith(".py\"") or launcher.endswith(".py")) else launcher
954
962
  if menuOption in ["M"]:
955
963
  OutputControls().printOutput(f"{colorText.GREEN}Launching PKScreener in monitoring mode. If it does not launch, please try with the following:{colorText.END}\n{colorText.FAIL}{launcher} --systemlaunched -a Y -m 'X'{colorText.END}\n{colorText.WARN}Press Ctrl + C to exit monitoring mode.{colorText.END}")
964
+ PKAnalyticsService().send_event(f"monitor_{menuOption}")
956
965
  sleep(2)
957
966
  os.system(f"{launcher} --systemlaunched -a Y -m 'X'")
958
967
  elif menuOption in ["D"]:
@@ -963,11 +972,13 @@ def main(userArgs=None,optionalFinalOutcome_df=None):
963
972
  OutputControls().printOutput(colorText.END, end="")
964
973
  if selDownloadOption.upper() == "D":
965
974
  OutputControls().printOutput(f"{colorText.GREEN}Launching PKScreener to Download daily OHLC data. If it does not launch, please try with the following:{colorText.END}\n{colorText.FAIL}{launcher} -a Y -e -d{colorText.END}\n{colorText.WARN}Press Ctrl + C to exit at any time.{colorText.END}")
975
+ PKAnalyticsService().send_event(f"{menuOption}_{selDownloadOption.upper()}")
966
976
  sleep(2)
967
977
  os.system(f"{launcher} -a Y -e -d")
968
978
  return None, None
969
979
  elif selDownloadOption.upper() == "I":
970
980
  OutputControls().printOutput(f"{colorText.GREEN}Launching PKScreener to Download intraday OHLC data. If it does not launch, please try with the following:{colorText.END}\n{colorText.FAIL}{launcher} -a Y -e -d -i 1m{colorText.END}\n{colorText.WARN}Press Ctrl + C to exit at any time.{colorText.END}")
981
+ PKAnalyticsService().send_event(f"{menuOption}_{selDownloadOption.upper()}")
971
982
  sleep(2)
972
983
  os.system(f"{launcher} -a Y -e -d -i 1m")
973
984
  return None, None
@@ -975,6 +986,7 @@ def main(userArgs=None,optionalFinalOutcome_df=None):
975
986
  selectedMenu = m1.find(selDownloadOption.upper())
976
987
  ConsoleUtility.PKConsoleTools.clearScreen(forceTop=True)
977
988
  m2.renderForMenu(selectedMenu)
989
+ PKAnalyticsService().send_event(f"{menuOption}_{selDownloadOption.upper()}")
978
990
  selDownloadOption = input(colorText.FAIL + " [+] Select option: ") or "12"
979
991
  OutputControls().printOutput(colorText.END, end="")
980
992
  filePrefix = "Download"
@@ -986,6 +998,7 @@ def main(userArgs=None,optionalFinalOutcome_df=None):
986
998
  + ".csv"
987
999
  )
988
1000
  filePath = os.path.join(Archiver.get_user_indices_dir(), filename)
1001
+ PKAnalyticsService().send_event(f"{menuOption}_{selDownloadOption.upper()}")
989
1002
  if selDownloadOption.upper() == "15":
990
1003
  nasdaq = PKNasdaqIndexFetcher(configManager)
991
1004
  _,nasdaq_df = nasdaq.fetchNasdaqIndexConstituents()
@@ -998,6 +1011,7 @@ def main(userArgs=None,optionalFinalOutcome_df=None):
998
1011
  input(f"{colorText.GREEN}Press any key to continue...{colorText.END}")
999
1012
  return None, None
1000
1013
  elif selDownloadOption.upper() == "M":
1014
+ PKAnalyticsService().send_event(f"{menuOption}_{selDownloadOption.upper()}")
1001
1015
  return None, None
1002
1016
  else:
1003
1017
  fileContents = fetcher.fetchFileFromHostServer(filePath=filePath,tickerOption=int(selDownloadOption),fileContents="")
@@ -1022,12 +1036,14 @@ def main(userArgs=None,optionalFinalOutcome_df=None):
1022
1036
  + PKDateUtilities.currentDateTime().strftime("%d-%m-%y_%H.%M.%S")
1023
1037
  + ".csv"
1024
1038
  )
1039
+ PKAnalyticsService().send_event(f"{menuOption}_{selDownloadOption.upper()}")
1025
1040
  filePath = os.path.join(Archiver.get_user_reports_dir(), filename)
1026
1041
  if selDownloadOption.upper() == "M":
1027
1042
  return None, None
1028
1043
  else:
1029
1044
  indexOption = int(selDownloadOption)
1030
1045
  if indexOption > 0 and indexOption <= 14:
1046
+ PKAnalyticsService().send_event(f"{menuOption}_{selDownloadOption.upper()}")
1031
1047
  shouldSuppress = not OutputControls().enableMultipleLineOutput
1032
1048
  with SuppressOutput(suppress_stderr=shouldSuppress, suppress_stdout=shouldSuppress):
1033
1049
  listStockCodes = fetcher.fetchStockCodes(indexOption, stockCode=None)
@@ -1043,12 +1059,15 @@ def main(userArgs=None,optionalFinalOutcome_df=None):
1043
1059
  OutputControls().printOutput(f"{colorText.FAIL}We encountered an error. Please try again!{colorText.END}")
1044
1060
  input(f"{colorText.GREEN}Press any key to continue...{colorText.END}")
1045
1061
  elif selDownloadOption.upper() == "M":
1062
+ PKAnalyticsService().send_event(f"{menuOption}_{selDownloadOption.upper()}")
1046
1063
  return None, None
1047
1064
  elif menuOption in ["L"]:
1065
+ PKAnalyticsService().send_event(f"{menuOption}")
1048
1066
  OutputControls().printOutput(f"{colorText.GREEN}Launching PKScreener to collect logs. If it does not launch, please try with the following:{colorText.END}\n{colorText.FAIL}{launcher} -a Y -l{colorText.END}\n{colorText.WARN}Press Ctrl + C to exit at any time.{colorText.END}")
1049
1067
  sleep(2)
1050
1068
  os.system(f"{launcher} -a Y -l")
1051
1069
  if menuOption in ["F"]:
1070
+ PKAnalyticsService().send_event(f"{menuOption}")
1052
1071
  indexOption = 0
1053
1072
  selectedChoice["0"] = "F"
1054
1073
  selectedChoice["1"] = "0"
@@ -1754,7 +1773,7 @@ def main(userArgs=None,optionalFinalOutcome_df=None):
1754
1773
  maLength = float(maLength)
1755
1774
  if maLength > 0:
1756
1775
  maLength = 0 - maLength
1757
-
1776
+
1758
1777
  if executeOption == MAX_MENU_OPTION:
1759
1778
  ConsoleUtility.PKConsoleTools.getLastScreenedResults(defaultAnswer)
1760
1779
  return None, None
@@ -1770,6 +1789,7 @@ def main(userArgs=None,optionalFinalOutcome_df=None):
1770
1789
  if str(indexOption).isnumeric() and int(indexOption) > 1 and executeOption <= MAX_SUPPORTED_MENU_OPTION:
1771
1790
  ensureMenusLoaded(menuOption,indexOption,executeOption)
1772
1791
  if not PKPremiumHandler.hasPremium(m2.find(str(executeOption).upper())):
1792
+ PKAnalyticsService().send_event("app_exit")
1773
1793
  sys.exit(0)
1774
1794
  if (
1775
1795
  not str(indexOption).isnumeric() and str(indexOption).upper() in ["W", "E", "M", "N", "Z", "S"]
@@ -1781,6 +1801,7 @@ def main(userArgs=None,optionalFinalOutcome_df=None):
1781
1801
  try:
1782
1802
  if str(indexOption).upper() in ["W", "E", "S"]:
1783
1803
  if not PKPremiumHandler.hasPremium(m1.find(str(indexOption).upper())):
1804
+ PKAnalyticsService().send_event("app_exit")
1784
1805
  sys.exit(0)
1785
1806
  if indexOption == "W":
1786
1807
  listStockCodes = fetcher.fetchWatchlist()
@@ -1790,6 +1811,7 @@ def main(userArgs=None,optionalFinalOutcome_df=None):
1790
1811
  + f" [+] Please create the watchlist.xlsx file in {os.getcwd()} and Restart the Program!"
1791
1812
  + colorText.END
1792
1813
  )
1814
+ PKAnalyticsService().send_event("app_exit")
1793
1815
  sys.exit(0)
1794
1816
  elif indexOption == "N":
1795
1817
  os.environ["TF_CPP_MIN_LOG_LEVEL"] = "3"
@@ -1824,6 +1846,7 @@ def main(userArgs=None,optionalFinalOutcome_df=None):
1824
1846
  + " [+] Press <Enter> to Exit!"
1825
1847
  + colorText.END
1826
1848
  )
1849
+ PKAnalyticsService().send_event("app_exit")
1827
1850
  sys.exit(0)
1828
1851
  elif indexOption == "E":
1829
1852
  return handleMonitorFiveEMA()
@@ -1885,7 +1908,6 @@ def main(userArgs=None,optionalFinalOutcome_df=None):
1885
1908
  except: # pragma: no cover
1886
1909
  stockDictPrimary,stockDictSecondary = loadDatabaseOrFetch(downloadOnly, listStockCodes, menuOption, indexOption)
1887
1910
  pass
1888
-
1889
1911
  loadCount = len(stockDictPrimary) if stockDictPrimary is not None else 0
1890
1912
  # Let's use screening only for the stocks for which we could get the data.
1891
1913
  savedOrDownloadedKeys = list(stockDictPrimary.keys())
@@ -2179,6 +2201,7 @@ def main(userArgs=None,optionalFinalOutcome_df=None):
2179
2201
  OutputControls().printOutput(colorText.END, end="")
2180
2202
  ensureMenusLoaded(menuOption,indexOption,executeOption)
2181
2203
  if not PKPremiumHandler.hasPremium(m0.find(str(pinOption).upper())):
2204
+ PKAnalyticsService().send_event("app_exit")
2182
2205
  sys.exit(0)
2183
2206
  if pinOption in ["1","2"]:
2184
2207
  if pinOption in ["2"]:
@@ -2508,7 +2531,6 @@ def addOrRunPipedMenus():
2508
2531
  def describeUser():
2509
2532
  if not configManager.enableUsageAnalytics:
2510
2533
  return
2511
- from pkscreener.classes.PKAnalytics import PKAnalyticsService
2512
2534
  service = PKAnalyticsService()
2513
2535
  func_args = None
2514
2536
  task = PKTask("Usage Analytics",
@@ -2736,6 +2758,7 @@ def handleExitRequest(executeOption):
2736
2758
  + " [+] Press <Enter> to Exit!"
2737
2759
  + colorText.END
2738
2760
  )
2761
+ PKAnalyticsService().send_event("app_exit")
2739
2762
  sys.exit(0)
2740
2763
 
2741
2764
  def handleMenu_XBG(menuOption, indexOption, executeOption):
@@ -2845,7 +2868,7 @@ def updateMenuChoiceHierarchy():
2845
2868
  if ((":0:" in runOptionName or "_0_" in runOptionName) and userPassedArgs.progressstatus is not None) or userPassedArgs.progressstatus is not None:
2846
2869
  runOptionName = userPassedArgs.progressstatus.split("=>")[0].split(" [+] ")[1].strip()
2847
2870
  reportTitle = f"{runOptionName} | {reportTitle}" if runOptionName is not None else reportTitle
2848
-
2871
+ PKAnalyticsService().send_event(runOptionName)
2849
2872
  OutputControls().printOutput(
2850
2873
  colorText.FAIL
2851
2874
  + f" [+] You chose: {reportTitle} "
@@ -3840,6 +3863,7 @@ def saveDownloadedData(downloadOnly, testing, stockDictPrimary, configManager, l
3840
3863
  os.system(f"{launcher} -a Y -e -l -d {'-i 1m' if configManager.isIntradayConfig() else ''}")
3841
3864
  else:
3842
3865
  del os.environ['PKDevTools_Default_Log_Level']
3866
+ PKAnalyticsService().send_event("app_exit")
3843
3867
  sys.exit(0)
3844
3868
  else:
3845
3869
  OutputControls().printOutput(colorText.GREEN + " [+] Skipped Saving!" + colorText.END)
@@ -3915,6 +3939,7 @@ def sendGlobalMarketBarometer(userArgs=None):
3915
3939
  )
3916
3940
  os.remove(gmbPath)
3917
3941
  else:
3942
+ PKAnalyticsService().send_event("app_exit")
3918
3943
  sys.exit(0)
3919
3944
  except Exception as e: # pragma: no cover
3920
3945
  default_logger().debug(e,exc_info=True)
@@ -19,7 +19,7 @@ pandas_ta #>=0.3.14b0
19
19
  # and https://github.com/pyinstaller/pyinstaller/issues/7269
20
20
  pefile>=2023.2.7,<2024.8.26
21
21
  Pillow #>=9.5.0,<=9.5.0 # Keep at this version because getsize_multiline is deprecated/removed in higher versions
22
- PKDevTools>=0.13.20250126.236
22
+ PKDevTools>=0.13.20250126.238
23
23
  PKNSETools>=0.1.20250122.138
24
24
  Pyarrow #>=17.0.0
25
25
  pyppeteer #>=2.0.0
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: pkscreener
3
- Version: 0.46.20250221.728
3
+ Version: 0.46.20250221.729
4
4
  Summary: A Python-based stock screener for NSE, India with alerts to Telegram Channel (pkscreener)
5
5
  Home-page: https://github.com/pkjmesra/pkscreener
6
- Download-URL: https://github.com/pkjmesra/pkscreener/archive/v0.46.20250221.728.zip
6
+ Download-URL: https://github.com/pkjmesra/pkscreener/archive/v0.46.20250221.729.zip
7
7
  Author: pkjmesra
8
8
  Author-email: pkjmesra@gmail.com
9
9
  License: OSI Approved (MIT)
@@ -33,7 +33,7 @@ Requires-Dist: pandas
33
33
  Requires-Dist: pandas_ta
34
34
  Requires-Dist: pefile<2024.8.26,>=2023.2.7
35
35
  Requires-Dist: Pillow
36
- Requires-Dist: PKDevTools>=0.13.20250126.236
36
+ Requires-Dist: PKDevTools>=0.13.20250126.238
37
37
  Requires-Dist: PKNSETools>=0.1.20250122.138
38
38
  Requires-Dist: Pyarrow
39
39
  Requires-Dist: pyppeteer
@@ -392,15 +392,15 @@ After you have finished the run, go to that copied path, zip the contents of the
392
392
  [MADE-IN-INDIA-badge]: https://img.shields.io/badge/MADE%20WITH%20%E2%9D%A4%20IN-INDIA-orange
393
393
  [MADE-IN-INDIA]: https://en.wikipedia.org/wiki/India
394
394
  [Windows-badge]: https://img.shields.io/badge/Windows-0078D6?logo=windows&logoColor=white
395
- [Windows]: https://github.com/pkjmesra/PKScreener/releases/download/0.46.20250220.727/pkscreenercli.exe
395
+ [Windows]: https://github.com/pkjmesra/PKScreener/releases/download/0.46.20250221.728/pkscreenercli.exe
396
396
  [Linux-badge_x64]: https://img.shields.io/badge/Linux(x64)-FCC624?logo=linux&logoColor=black
397
- [Linux_x64]: https://github.com/pkjmesra/PKScreener/releases/download/0.46.20250220.727/pkscreenercli_x64.bin
397
+ [Linux_x64]: https://github.com/pkjmesra/PKScreener/releases/download/0.46.20250221.728/pkscreenercli_x64.bin
398
398
  [Linux-badge_arm64]: https://img.shields.io/badge/Linux(arm64)-FCC624?logo=linux&logoColor=black
399
- [Linux_arm64]: https://github.com/pkjmesra/PKScreener/releases/download/0.46.20250220.727/pkscreenercli_arm64.bin
399
+ [Linux_arm64]: https://github.com/pkjmesra/PKScreener/releases/download/0.46.20250221.728/pkscreenercli_arm64.bin
400
400
  [Mac OS-badge_x64]: https://img.shields.io/badge/mac%20os(x64)-D3D3D3?logo=apple&logoColor=000000
401
- [Mac OS_x64]: https://github.com/pkjmesra/PKScreener/releases/download/0.46.20250220.727/pkscreenercli_x64.run
401
+ [Mac OS_x64]: https://github.com/pkjmesra/PKScreener/releases/download/0.46.20250221.728/pkscreenercli_x64.run
402
402
  [Mac OS-badge_arm64]: https://img.shields.io/badge/mac%20os(arm64)-D3D3D3?logo=apple&logoColor=000000
403
- [Mac OS_arm64]: https://github.com/pkjmesra/PKScreener/releases/download/0.46.20250220.727/pkscreenercli_arm64.run
403
+ [Mac OS_arm64]: https://github.com/pkjmesra/PKScreener/releases/download/0.46.20250221.728/pkscreenercli_arm64.run
404
404
  [GitHub release (latest by date)-badge]: https://img.shields.io/github/v/release/pkjmesra/PKScreener
405
405
  [GitHub release (latest by date)]: https://github.com/pkjmesra/PKScreener/releases/latest
406
406
  [pypi-badge]: https://img.shields.io/pypi/v/pkscreener.svg?style=flat-square
@@ -0,0 +1,58 @@
1
+ pkscreener-0.46.20250221.729.data/purelib/pkscreener/Disclaimer.txt,sha256=kBZQSQCFfL2kc1bijXWndZzkjMTtnpH_B7XtDPPMcuw,1396
2
+ pkscreener-0.46.20250221.729.data/purelib/pkscreener/LICENSE-Others.txt,sha256=WBslRYLBoqYg-vr25sS1c_UI7cuUnsGk0nIQLBzTWEE,271830
3
+ pkscreener-0.46.20250221.729.data/purelib/pkscreener/LICENSE.txt,sha256=CdnyGrl-xRYX67ZkdERZWHr6BlTxOyg8Z8sK1XQ5Xsg,1078
4
+ pkscreener-0.46.20250221.729.data/purelib/pkscreener/LogoWM.txt,sha256=7Njnavpy_FKY4Iwbzv1JqsYMcOdkDSKAKXP3SAItKV0,14868
5
+ pkscreener-0.46.20250221.729.data/purelib/pkscreener/README.txt,sha256=rGhkIJt42bA8r1vbEPrmye8p9_TgbA6MaWe5bM3FFjI,32802
6
+ pkscreener-0.46.20250221.729.data/purelib/pkscreener/__init__.py,sha256=aZ62qYACxsU8m8_5JkzNzos1lVFNcMGPRMgeddnUUiQ,1633
7
+ pkscreener-0.46.20250221.729.data/purelib/pkscreener/courbd.ttf,sha256=SKpnp-BRs7AZcdI83nencS3Q7xe0anbbP1YMOxLlEhU,791436
8
+ pkscreener-0.46.20250221.729.data/purelib/pkscreener/globals.py,sha256=N0beEkoGuveA2QAlrtmSTDdWlAJsLyX8jBohccaSIHQ,243495
9
+ pkscreener-0.46.20250221.729.data/purelib/pkscreener/pkscreener.ini,sha256=QKs6j4qhyH37L_MdG3ztAIwgqs4c3qihuqDIoex-V2g,2391
10
+ pkscreener-0.46.20250221.729.data/purelib/pkscreener/pkscreenerbot.py,sha256=hi1qvI2yb9aNkTP4BAZyuVzpLf-_gR0JBaozGUIm32o,117163
11
+ pkscreener-0.46.20250221.729.data/purelib/pkscreener/pkscreenercli.py,sha256=-2cgfdCUJhp4xeZfcbj2ntUp_MvsrVJvz1dnsOBQMZA,57826
12
+ pkscreener-0.46.20250221.729.data/purelib/pkscreener/requirements.txt,sha256=WAgAA0Jnagag0KWNFcM9wspRO23SRkb9F5Fo3ceW3Os,1457
13
+ pkscreener-0.46.20250221.729.data/purelib/pkscreener/classes/ArtTexts.py,sha256=LZ8ynyS8woliv8bM9Nq4aU0VCoJDJU0FgZk8V5zYPmg,19504
14
+ pkscreener-0.46.20250221.729.data/purelib/pkscreener/classes/AssetsManager.py,sha256=5pyXH-9KZszQP5uI4_6XR8QMny1sEHBhpRzsmP0Rhe0,35465
15
+ pkscreener-0.46.20250221.729.data/purelib/pkscreener/classes/Backtest.py,sha256=wobBQgqVQhFNZlyJ2hgMXQqofrICc_3F0I5D66DUvGI,10530
16
+ pkscreener-0.46.20250221.729.data/purelib/pkscreener/classes/Barometer.py,sha256=WPrgtIXb1nIbb-FnuRs-yvOQ5baNQRBgUR_zWg1moxk,9464
17
+ pkscreener-0.46.20250221.729.data/purelib/pkscreener/classes/BaseScreeningStatistics.py,sha256=u5t1wf-HsZ8xEtprON55ehIR3F2LNNq8LvwgIrhYRmU,3000
18
+ pkscreener-0.46.20250221.729.data/purelib/pkscreener/classes/CandlePatterns.py,sha256=gaswU2OeDa3JXjEafR2clUpKW5v8_1_tJuNPuTWsAss,17066
19
+ pkscreener-0.46.20250221.729.data/purelib/pkscreener/classes/Changelog.py,sha256=vUOpca28OACNhavAmjBm4xco3u6fcHqWlnlmCJqO5Lk,1469
20
+ pkscreener-0.46.20250221.729.data/purelib/pkscreener/classes/ConfigManager.py,sha256=THcfBgua5hr1Pv7AwEDBu2yurCNteGM04jY3Fr_MeBg,53565
21
+ pkscreener-0.46.20250221.729.data/purelib/pkscreener/classes/ConsoleMenuUtility.py,sha256=fyR7dEsAaEWEe5SyaVgwLPdU4h4pI8SozUhsPZXShpg,10037
22
+ pkscreener-0.46.20250221.729.data/purelib/pkscreener/classes/ConsoleUtility.py,sha256=TrEnTT4pmsBpEYdwD2oAtNqNG_drPe1LVkhthP2540I,12096
23
+ pkscreener-0.46.20250221.729.data/purelib/pkscreener/classes/Fetcher.py,sha256=3-6x_XoHDzMk5HV40oMS-8hYXRSJ-BaDdfB0KIDnb4c,14766
24
+ pkscreener-0.46.20250221.729.data/purelib/pkscreener/classes/GlobalStore.py,sha256=IzoYMybXpVVf6YwZi7j34rP-hNd7sMened8TAMu_-A8,3709
25
+ pkscreener-0.46.20250221.729.data/purelib/pkscreener/classes/ImageUtility.py,sha256=mgJUzjrOKQ1mYV5P_ylhBnaF7ZgOO6ogjy22Rt49TNI,37032
26
+ pkscreener-0.46.20250221.729.data/purelib/pkscreener/classes/MarketMonitor.py,sha256=GQOPLuUhgcrnVa0mI8ZvXqQ4vPFW00FHW_vMfICnko8,22079
27
+ pkscreener-0.46.20250221.729.data/purelib/pkscreener/classes/MarketStatus.py,sha256=dNg8znbRpt7ID3U_1nmclD4zSLtveJeYeRbS0l6HLtE,3737
28
+ pkscreener-0.46.20250221.729.data/purelib/pkscreener/classes/MenuOptions.py,sha256=iZb0zBs7lcP60cmuP7Z5xmXfNtTFcFH6ZWOuoileErE,64552
29
+ pkscreener-0.46.20250221.729.data/purelib/pkscreener/classes/Messenger.py,sha256=peyY-YiqdC1bp-3DlJXILRa9HGYbqGVzf1wil0fYv98,8396
30
+ pkscreener-0.46.20250221.729.data/purelib/pkscreener/classes/OtaUpdater.py,sha256=_7-nFAC-vAcmZ1Nwi5g5tfp7hKQQPuLUnBCOzrwC39g,13491
31
+ pkscreener-0.46.20250221.729.data/purelib/pkscreener/classes/PKAnalytics.py,sha256=zxbzGOBU8dquofXRRQwJS5nHxV6e2avfVN6CsimqAwk,6277
32
+ pkscreener-0.46.20250221.729.data/purelib/pkscreener/classes/PKDataService.py,sha256=BipM8Z4rS6h12cF6VWv_u4Z8ee7psMFd1yUojejW1Ag,3393
33
+ pkscreener-0.46.20250221.729.data/purelib/pkscreener/classes/PKDemoHandler.py,sha256=r4KrZF8TaOu1J0nu8sUsgWEvnbndboWQQvz69GOy1Fk,2207
34
+ pkscreener-0.46.20250221.729.data/purelib/pkscreener/classes/PKMarketOpenCloseAnalyser.py,sha256=T7S0DRv4Tqg77S5CyTWQUgpIAtx0NEtSVAplkynS2YM,33833
35
+ pkscreener-0.46.20250221.729.data/purelib/pkscreener/classes/PKPremiumHandler.py,sha256=r16-u9fyc0ftgnSnZnz-JusTfEzyQIyKkvgbPuSd7W4,5611
36
+ pkscreener-0.46.20250221.729.data/purelib/pkscreener/classes/PKScanRunner.py,sha256=EPLo2euBMfA9omnqrr5pXv2h9KzTcPZM-PXRFI26LSo,26791
37
+ pkscreener-0.46.20250221.729.data/purelib/pkscreener/classes/PKScheduledTaskProgress.py,sha256=h19ZuxoalB50pnZjntFh12b9mBozvMqhKYq6TL18vo4,1657
38
+ pkscreener-0.46.20250221.729.data/purelib/pkscreener/classes/PKScheduler.py,sha256=qThoz0yXLmHEWAiD_TdkIrzJb37b_m830JJFrkN1Tio,8814
39
+ pkscreener-0.46.20250221.729.data/purelib/pkscreener/classes/PKSpreadsheets.py,sha256=1I7YGGPPY879K5JeTZ_d1FNCpjloh6TZrx91JlwT20o,8298
40
+ pkscreener-0.46.20250221.729.data/purelib/pkscreener/classes/PKTask.py,sha256=4q87uD2cXvp0AbP6I73xPP39F0mfnpHQutsxxqpnxJM,1867
41
+ pkscreener-0.46.20250221.729.data/purelib/pkscreener/classes/PKUserRegistration.py,sha256=SIEpkMscmUav7dXDcRUDZmlb5LeRo6b-Tx-h15ED_88,11589
42
+ pkscreener-0.46.20250221.729.data/purelib/pkscreener/classes/Pktalib.py,sha256=xketnpMVDGHOFg47LFavaU-agWy370VanYWyzzuLY8c,33386
43
+ pkscreener-0.46.20250221.729.data/purelib/pkscreener/classes/Portfolio.py,sha256=JZ93n3Zk9nkSFaX-lHyQiFnavHVmHPFoy-L_4gugj54,13895
44
+ pkscreener-0.46.20250221.729.data/purelib/pkscreener/classes/PortfolioXRay.py,sha256=4MjXqBAVUlfN4w5tTmgEnQGMoy0hFu_uaVgrmai1fN4,48339
45
+ pkscreener-0.46.20250221.729.data/purelib/pkscreener/classes/ScreeningStatistics.py,sha256=YSg4cynnDcn7cUK6VUBRpMmcNsKG3_CCzTSyobiCk2k,221479
46
+ pkscreener-0.46.20250221.729.data/purelib/pkscreener/classes/StockScreener.py,sha256=F0SWa1DSTgYdSWnkPTR9kmOKgHLtaqNMCtJP8yZkDnE,67252
47
+ pkscreener-0.46.20250221.729.data/purelib/pkscreener/classes/StockSentiment.py,sha256=WL7TBAHDSIN5cgZ9uTbbEFnUPo4G-YIzEv16RpPGaro,3546
48
+ pkscreener-0.46.20250221.729.data/purelib/pkscreener/classes/UserMenuChoicesHandler.py,sha256=_fTCscTLEjoU-n12V9237uDN6Jf8nGCvGdBVkpD3Ap4,4947
49
+ pkscreener-0.46.20250221.729.data/purelib/pkscreener/classes/Utility.py,sha256=Cn_QrVH40rQWkHW2e2NolE0b18qszvGXfVLdwAqD7sM,13562
50
+ pkscreener-0.46.20250221.729.data/purelib/pkscreener/classes/WorkflowManager.py,sha256=YRUiZSq83SEx2qB0wTBDE4KFaYqEz1Qu4FSCAzl6xzU,5663
51
+ pkscreener-0.46.20250221.729.data/purelib/pkscreener/classes/__init__.py,sha256=UfAhNrgpaJWf-DVai3i-8xAW837vrWPSDTHtmZoniK8,28
52
+ pkscreener-0.46.20250221.729.data/purelib/pkscreener/classes/keys.py,sha256=LQq_t1lSh0x4TbRCIDhoCil3xctgLLeVk5f2vgrl1tk,6789
53
+ pkscreener-0.46.20250221.729.dist-info/LICENSE,sha256=CdnyGrl-xRYX67ZkdERZWHr6BlTxOyg8Z8sK1XQ5Xsg,1078
54
+ pkscreener-0.46.20250221.729.dist-info/METADATA,sha256=msnC0UhuW26TidYCIlWsAI2S4nXHMe6gvHyvjZl8Qdw,34740
55
+ pkscreener-0.46.20250221.729.dist-info/WHEEL,sha256=aDUArjEbIuDQzblE24IvdIsBzRhJEjiXmuNUYQ-gpaA,104
56
+ pkscreener-0.46.20250221.729.dist-info/entry_points.txt,sha256=Pm30xm4sU7YFtFJUC-Te8VlqOvYAvWKFFA5AfQE0xGY,120
57
+ pkscreener-0.46.20250221.729.dist-info/top_level.txt,sha256=oIfcPPw58Q4KU-GDqp25dXbrtvxYXJBCo_em6i5aVvY,11
58
+ pkscreener-0.46.20250221.729.dist-info/RECORD,,
@@ -1,122 +0,0 @@
1
- #!/usr/bin/python3
2
- """
3
- The MIT License (MIT)
4
-
5
- Copyright (c) 2023 pkjmesra
6
-
7
- Permission is hereby granted, free of charge, to any person obtaining a copy
8
- of this software and associated documentation files (the "Software"), to deal
9
- in the Software without restriction, including without limitation the rights
10
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
- copies of the Software, and to permit persons to whom the Software is
12
- furnished to do so, subject to the following conditions:
13
-
14
- The above copyright notice and this permission notice shall be included in all
15
- copies or substantial portions of the Software.
16
-
17
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
- SOFTWARE.
24
-
25
- """
26
-
27
- import os
28
- import base64
29
- from sys import platform
30
- import platform
31
- import getpass
32
- import git
33
- import json
34
- import io
35
-
36
- from PKDevTools.classes.Fetcher import fetcher
37
- from PKDevTools.classes.Utils import random_user_agent
38
- from PKDevTools.classes.PKDateUtilities import PKDateUtilities
39
- from PKDevTools.classes import Archiver
40
- import git.repo
41
-
42
- class PKAnalyticsService():
43
- def collectMetrics(self,user=None):
44
- try:
45
- userName = self.getUserName()
46
- metrics = self.getApproxLocationInfo()
47
- dateTime = str(PKDateUtilities.currentDateTime())
48
- metrics["dateTime"] = dateTime
49
- metrics["userName"] = userName
50
- if "readme" in metrics.keys():
51
- del metrics['readme']
52
- self.tryCommitAnalytics(userDict=metrics,username=userName)
53
- except KeyboardInterrupt: # pragma: no cover
54
- raise KeyboardInterrupt
55
- except Exception as e: # pragma: no cover
56
- pass
57
-
58
- def getUserName(self):
59
- try:
60
- username = os.getlogin()
61
- if username is None or len(username) == 0:
62
- username = os.environ.get('username') if platform.startswith("win") else os.environ.get("USER")
63
- if username is None or len(username) == 0:
64
- username = os.environ.get('USERPROFILE')
65
- if username is None or len(username) == 0:
66
- username = os.path.expandvars("%userprofile%") if platform.startswith("win") else getpass.getuser()
67
- except KeyboardInterrupt: # pragma: no cover
68
- raise KeyboardInterrupt
69
- except: # pragma: no cover
70
- username = f"Unidentified-{platform.system()}"
71
- pass
72
- return username
73
-
74
- def getApproxLocationInfo(self):
75
- try:
76
- url = 'http://ipinfo.io/json'
77
- f = fetcher()
78
- response = f.fetchURL(url=url,timeout=5,headers={'user-agent': f'{random_user_agent()}'})
79
- data = json.loads(response.text)
80
- except: # pragma: no cover
81
- data = {"locationInfo":f"Unidentified-{platform.system()}"}
82
- pass
83
- return data
84
-
85
- def tryCommitAnalytics(self, userDict={},username="Unidentified"):
86
- repo_clone_url = "https://github.com/pkjmesra/PKUserAnalytics.git"
87
- local_repo = os.path.join(Archiver.get_user_data_dir(),"PKUserAnalytics")
88
- try:
89
- test_branch = "main"
90
- repo = git.Repo.clone_from(repo_clone_url, local_repo)
91
- repo.git.checkout(test_branch)
92
- except Exception as e: # pragma: no cover
93
- repo = git.Repo(local_repo)
94
- repo.git.checkout(test_branch)
95
- pass
96
- remote = git.remote.Remote(repo=repo,name="origin")
97
- repo.git.reset('--hard','origin/main')
98
- remote.pull()
99
- # write to file in working directory
100
- scanResultFilesPath = os.path.join(local_repo, f"users-{PKDateUtilities.currentDateTime().strftime('%Y-%m-%d')}.txt")
101
- records = {}
102
- existingUserRecords = [userDict]
103
- mode = "rb+" if os.path.exists(scanResultFilesPath) else "wb+"
104
- with open(scanResultFilesPath, mode) as f:
105
- allUsers = f.read()
106
- if allUsers is not None and len(allUsers) > 0:
107
- allUsers = base64.b64decode(allUsers).decode("utf-8").replace("'","\"")
108
- records = json.loads(allUsers)
109
- if records is None:
110
- records = {}
111
- existingUserRecords = records.get(username)
112
- if existingUserRecords is not None:
113
- existingUserRecords.append(userDict)
114
- else:
115
- existingUserRecords = [userDict]
116
- records[username] = existingUserRecords
117
- encoded = base64.b64encode(bytes(str(records).replace("'","\""), "utf-8"))
118
- f.writelines(io.BytesIO(encoded))
119
- repo.index.add([scanResultFilesPath])
120
- repo.index.commit("[User-Analytics]")
121
- remote = git.remote.Remote(repo=repo,name="origin")
122
- remote.push()
@@ -1 +0,0 @@
1
- VERSION='0.46.20250221.728'
@@ -1,58 +0,0 @@
1
- pkscreener-0.46.20250221.728.data/purelib/pkscreener/Disclaimer.txt,sha256=kBZQSQCFfL2kc1bijXWndZzkjMTtnpH_B7XtDPPMcuw,1396
2
- pkscreener-0.46.20250221.728.data/purelib/pkscreener/LICENSE-Others.txt,sha256=WBslRYLBoqYg-vr25sS1c_UI7cuUnsGk0nIQLBzTWEE,271830
3
- pkscreener-0.46.20250221.728.data/purelib/pkscreener/LICENSE.txt,sha256=CdnyGrl-xRYX67ZkdERZWHr6BlTxOyg8Z8sK1XQ5Xsg,1078
4
- pkscreener-0.46.20250221.728.data/purelib/pkscreener/LogoWM.txt,sha256=7Njnavpy_FKY4Iwbzv1JqsYMcOdkDSKAKXP3SAItKV0,14868
5
- pkscreener-0.46.20250221.728.data/purelib/pkscreener/README.txt,sha256=M1dCxk7Nipgj7p_foLkSprWXESBFRlEFHOZfV71Y5Lc,32802
6
- pkscreener-0.46.20250221.728.data/purelib/pkscreener/__init__.py,sha256=aZ62qYACxsU8m8_5JkzNzos1lVFNcMGPRMgeddnUUiQ,1633
7
- pkscreener-0.46.20250221.728.data/purelib/pkscreener/courbd.ttf,sha256=SKpnp-BRs7AZcdI83nencS3Q7xe0anbbP1YMOxLlEhU,791436
8
- pkscreener-0.46.20250221.728.data/purelib/pkscreener/globals.py,sha256=vp7-GUGw5VkBU7HsG-3EtE-GRup0POyPH98SZyJi1mM,241603
9
- pkscreener-0.46.20250221.728.data/purelib/pkscreener/pkscreener.ini,sha256=QKs6j4qhyH37L_MdG3ztAIwgqs4c3qihuqDIoex-V2g,2391
10
- pkscreener-0.46.20250221.728.data/purelib/pkscreener/pkscreenerbot.py,sha256=hi1qvI2yb9aNkTP4BAZyuVzpLf-_gR0JBaozGUIm32o,117163
11
- pkscreener-0.46.20250221.728.data/purelib/pkscreener/pkscreenercli.py,sha256=-2cgfdCUJhp4xeZfcbj2ntUp_MvsrVJvz1dnsOBQMZA,57826
12
- pkscreener-0.46.20250221.728.data/purelib/pkscreener/requirements.txt,sha256=M7ZEXe8o9-6N67lHzel4HsEFYma_JfRUP93y3OavkDs,1457
13
- pkscreener-0.46.20250221.728.data/purelib/pkscreener/classes/ArtTexts.py,sha256=LZ8ynyS8woliv8bM9Nq4aU0VCoJDJU0FgZk8V5zYPmg,19504
14
- pkscreener-0.46.20250221.728.data/purelib/pkscreener/classes/AssetsManager.py,sha256=5pyXH-9KZszQP5uI4_6XR8QMny1sEHBhpRzsmP0Rhe0,35465
15
- pkscreener-0.46.20250221.728.data/purelib/pkscreener/classes/Backtest.py,sha256=wobBQgqVQhFNZlyJ2hgMXQqofrICc_3F0I5D66DUvGI,10530
16
- pkscreener-0.46.20250221.728.data/purelib/pkscreener/classes/Barometer.py,sha256=WPrgtIXb1nIbb-FnuRs-yvOQ5baNQRBgUR_zWg1moxk,9464
17
- pkscreener-0.46.20250221.728.data/purelib/pkscreener/classes/BaseScreeningStatistics.py,sha256=u5t1wf-HsZ8xEtprON55ehIR3F2LNNq8LvwgIrhYRmU,3000
18
- pkscreener-0.46.20250221.728.data/purelib/pkscreener/classes/CandlePatterns.py,sha256=gaswU2OeDa3JXjEafR2clUpKW5v8_1_tJuNPuTWsAss,17066
19
- pkscreener-0.46.20250221.728.data/purelib/pkscreener/classes/Changelog.py,sha256=vUOpca28OACNhavAmjBm4xco3u6fcHqWlnlmCJqO5Lk,1469
20
- pkscreener-0.46.20250221.728.data/purelib/pkscreener/classes/ConfigManager.py,sha256=THcfBgua5hr1Pv7AwEDBu2yurCNteGM04jY3Fr_MeBg,53565
21
- pkscreener-0.46.20250221.728.data/purelib/pkscreener/classes/ConsoleMenuUtility.py,sha256=fyR7dEsAaEWEe5SyaVgwLPdU4h4pI8SozUhsPZXShpg,10037
22
- pkscreener-0.46.20250221.728.data/purelib/pkscreener/classes/ConsoleUtility.py,sha256=TrEnTT4pmsBpEYdwD2oAtNqNG_drPe1LVkhthP2540I,12096
23
- pkscreener-0.46.20250221.728.data/purelib/pkscreener/classes/Fetcher.py,sha256=3-6x_XoHDzMk5HV40oMS-8hYXRSJ-BaDdfB0KIDnb4c,14766
24
- pkscreener-0.46.20250221.728.data/purelib/pkscreener/classes/GlobalStore.py,sha256=IzoYMybXpVVf6YwZi7j34rP-hNd7sMened8TAMu_-A8,3709
25
- pkscreener-0.46.20250221.728.data/purelib/pkscreener/classes/ImageUtility.py,sha256=mgJUzjrOKQ1mYV5P_ylhBnaF7ZgOO6ogjy22Rt49TNI,37032
26
- pkscreener-0.46.20250221.728.data/purelib/pkscreener/classes/MarketMonitor.py,sha256=GQOPLuUhgcrnVa0mI8ZvXqQ4vPFW00FHW_vMfICnko8,22079
27
- pkscreener-0.46.20250221.728.data/purelib/pkscreener/classes/MarketStatus.py,sha256=dNg8znbRpt7ID3U_1nmclD4zSLtveJeYeRbS0l6HLtE,3737
28
- pkscreener-0.46.20250221.728.data/purelib/pkscreener/classes/MenuOptions.py,sha256=iZb0zBs7lcP60cmuP7Z5xmXfNtTFcFH6ZWOuoileErE,64552
29
- pkscreener-0.46.20250221.728.data/purelib/pkscreener/classes/Messenger.py,sha256=peyY-YiqdC1bp-3DlJXILRa9HGYbqGVzf1wil0fYv98,8396
30
- pkscreener-0.46.20250221.728.data/purelib/pkscreener/classes/OtaUpdater.py,sha256=_7-nFAC-vAcmZ1Nwi5g5tfp7hKQQPuLUnBCOzrwC39g,13491
31
- pkscreener-0.46.20250221.728.data/purelib/pkscreener/classes/PKAnalytics.py,sha256=_X-2OFw2yQVmXlEIRsnBVNy9fhYyxqt0BOqADD4v08U,5246
32
- pkscreener-0.46.20250221.728.data/purelib/pkscreener/classes/PKDataService.py,sha256=BipM8Z4rS6h12cF6VWv_u4Z8ee7psMFd1yUojejW1Ag,3393
33
- pkscreener-0.46.20250221.728.data/purelib/pkscreener/classes/PKDemoHandler.py,sha256=r4KrZF8TaOu1J0nu8sUsgWEvnbndboWQQvz69GOy1Fk,2207
34
- pkscreener-0.46.20250221.728.data/purelib/pkscreener/classes/PKMarketOpenCloseAnalyser.py,sha256=T7S0DRv4Tqg77S5CyTWQUgpIAtx0NEtSVAplkynS2YM,33833
35
- pkscreener-0.46.20250221.728.data/purelib/pkscreener/classes/PKPremiumHandler.py,sha256=r16-u9fyc0ftgnSnZnz-JusTfEzyQIyKkvgbPuSd7W4,5611
36
- pkscreener-0.46.20250221.728.data/purelib/pkscreener/classes/PKScanRunner.py,sha256=EPLo2euBMfA9omnqrr5pXv2h9KzTcPZM-PXRFI26LSo,26791
37
- pkscreener-0.46.20250221.728.data/purelib/pkscreener/classes/PKScheduledTaskProgress.py,sha256=h19ZuxoalB50pnZjntFh12b9mBozvMqhKYq6TL18vo4,1657
38
- pkscreener-0.46.20250221.728.data/purelib/pkscreener/classes/PKScheduler.py,sha256=qThoz0yXLmHEWAiD_TdkIrzJb37b_m830JJFrkN1Tio,8814
39
- pkscreener-0.46.20250221.728.data/purelib/pkscreener/classes/PKSpreadsheets.py,sha256=1I7YGGPPY879K5JeTZ_d1FNCpjloh6TZrx91JlwT20o,8298
40
- pkscreener-0.46.20250221.728.data/purelib/pkscreener/classes/PKTask.py,sha256=4q87uD2cXvp0AbP6I73xPP39F0mfnpHQutsxxqpnxJM,1867
41
- pkscreener-0.46.20250221.728.data/purelib/pkscreener/classes/PKUserRegistration.py,sha256=ZbnPzgvT5Je9X0Dm6bewSp8u7Fj_szNucaYnit_AtCg,11465
42
- pkscreener-0.46.20250221.728.data/purelib/pkscreener/classes/Pktalib.py,sha256=xketnpMVDGHOFg47LFavaU-agWy370VanYWyzzuLY8c,33386
43
- pkscreener-0.46.20250221.728.data/purelib/pkscreener/classes/Portfolio.py,sha256=JZ93n3Zk9nkSFaX-lHyQiFnavHVmHPFoy-L_4gugj54,13895
44
- pkscreener-0.46.20250221.728.data/purelib/pkscreener/classes/PortfolioXRay.py,sha256=4MjXqBAVUlfN4w5tTmgEnQGMoy0hFu_uaVgrmai1fN4,48339
45
- pkscreener-0.46.20250221.728.data/purelib/pkscreener/classes/ScreeningStatistics.py,sha256=YSg4cynnDcn7cUK6VUBRpMmcNsKG3_CCzTSyobiCk2k,221479
46
- pkscreener-0.46.20250221.728.data/purelib/pkscreener/classes/StockScreener.py,sha256=F0SWa1DSTgYdSWnkPTR9kmOKgHLtaqNMCtJP8yZkDnE,67252
47
- pkscreener-0.46.20250221.728.data/purelib/pkscreener/classes/StockSentiment.py,sha256=WL7TBAHDSIN5cgZ9uTbbEFnUPo4G-YIzEv16RpPGaro,3546
48
- pkscreener-0.46.20250221.728.data/purelib/pkscreener/classes/UserMenuChoicesHandler.py,sha256=_fTCscTLEjoU-n12V9237uDN6Jf8nGCvGdBVkpD3Ap4,4947
49
- pkscreener-0.46.20250221.728.data/purelib/pkscreener/classes/Utility.py,sha256=Cn_QrVH40rQWkHW2e2NolE0b18qszvGXfVLdwAqD7sM,13562
50
- pkscreener-0.46.20250221.728.data/purelib/pkscreener/classes/WorkflowManager.py,sha256=YRUiZSq83SEx2qB0wTBDE4KFaYqEz1Qu4FSCAzl6xzU,5663
51
- pkscreener-0.46.20250221.728.data/purelib/pkscreener/classes/__init__.py,sha256=PQF7M6bcXPYzDrWZq_GCtWxjAkV3FixUXKTCB4HsQSI,28
52
- pkscreener-0.46.20250221.728.data/purelib/pkscreener/classes/keys.py,sha256=LQq_t1lSh0x4TbRCIDhoCil3xctgLLeVk5f2vgrl1tk,6789
53
- pkscreener-0.46.20250221.728.dist-info/LICENSE,sha256=CdnyGrl-xRYX67ZkdERZWHr6BlTxOyg8Z8sK1XQ5Xsg,1078
54
- pkscreener-0.46.20250221.728.dist-info/METADATA,sha256=Rcxp5LJx9cVqT4-eiNatkiu9-JHBUPR7h_lMAAgjccg,34740
55
- pkscreener-0.46.20250221.728.dist-info/WHEEL,sha256=aDUArjEbIuDQzblE24IvdIsBzRhJEjiXmuNUYQ-gpaA,104
56
- pkscreener-0.46.20250221.728.dist-info/entry_points.txt,sha256=Pm30xm4sU7YFtFJUC-Te8VlqOvYAvWKFFA5AfQE0xGY,120
57
- pkscreener-0.46.20250221.728.dist-info/top_level.txt,sha256=oIfcPPw58Q4KU-GDqp25dXbrtvxYXJBCo_em6i5aVvY,11
58
- pkscreener-0.46.20250221.728.dist-info/RECORD,,