radnn 0.0.7.3__py3-none-any.whl → 0.0.9__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 (35) hide show
  1. radnn/__init__.py +3 -1
  2. radnn/data/__init__.py +2 -0
  3. radnn/data/data_feed.py +5 -0
  4. radnn/data/dataset_base.py +17 -5
  5. radnn/data/dataset_folder.py +55 -0
  6. radnn/data/image_dataset_files.py +175 -0
  7. radnn/data/subset_type.py +8 -2
  8. radnn/data/tf_classification_data_feed.py +22 -6
  9. radnn/experiment/ml_experiment_config.py +54 -29
  10. radnn/images/__init__.py +2 -0
  11. radnn/images/colors.py +28 -0
  12. radnn/images/image_processor.py +513 -0
  13. radnn/ml_system.py +1 -0
  14. radnn/plots/plot_auto_multi_image.py +6 -5
  15. radnn/stats/__init__.py +1 -0
  16. radnn/stats/descriptive_stats.py +45 -0
  17. radnn/system/files/__init__.py +1 -0
  18. radnn/system/files/filelist.py +40 -0
  19. radnn/system/files/jsonfile.py +3 -0
  20. radnn/system/files/textfile.py +29 -6
  21. radnn/system/filestore.py +26 -10
  22. radnn/system/filesystem.py +1 -1
  23. radnn/system/hosts/windows_host.py +10 -0
  24. radnn/system/threads/__init__.py +5 -0
  25. radnn/system/threads/semaphore_lock.py +58 -0
  26. radnn/system/threads/thread_context.py +175 -0
  27. radnn/system/threads/thread_safe_queue.py +163 -0
  28. radnn/system/threads/thread_safe_string_collection.py +66 -0
  29. radnn/system/threads/thread_worker.py +68 -0
  30. radnn/utils.py +43 -0
  31. {radnn-0.0.7.3.dist-info → radnn-0.0.9.dist-info}/METADATA +4 -25
  32. {radnn-0.0.7.3.dist-info → radnn-0.0.9.dist-info}/RECORD +35 -21
  33. {radnn-0.0.7.3.dist-info → radnn-0.0.9.dist-info}/WHEEL +1 -1
  34. {radnn-0.0.7.3.dist-info → radnn-0.0.9.dist-info/licenses}/LICENSE.txt +0 -0
  35. {radnn-0.0.7.3.dist-info → radnn-0.0.9.dist-info}/top_level.txt +0 -0
@@ -29,6 +29,7 @@
29
29
  # .......................................................................................
30
30
  import os
31
31
  import numpy as np
32
+ import locale
32
33
  from .fileobject import FileObject
33
34
 
34
35
 
@@ -37,8 +38,33 @@ class TextFile(FileObject):
37
38
  def __init__(self, filename, parent_folder=None, error_template=None, is_verbose=False):
38
39
  super(TextFile, self).__init__(filename, parent_folder, error_template)
39
40
  self.is_verbose = is_verbose
41
+
42
+ # ----------------------------------------------------------------------------------
43
+ def load(self, filename=None, encoding=None):
44
+ filename = self._useFileName(filename)
45
+
46
+ sText = None
47
+ if os.path.isfile(filename):
48
+ oEncodingToTry = ["utf-8", "utf-16", "latin1", "ascii"] # Add more if needed
49
+ if encoding is None:
50
+ bIsLoaded = False
51
+ for sEnc in oEncodingToTry:
52
+ try:
53
+ with open(filename, "r", encoding=sEnc) as oFile:
54
+ sText = oFile.read()
55
+ bIsLoaded = True
56
+ break
57
+ except (UnicodeDecodeError, UnicodeError):
58
+ continue
59
+ if not bIsLoaded:
60
+ raise ValueError("Unsupported encoding")
61
+ else:
62
+ with open(filename, "r", encoding=encoding) as oFile:
63
+ sText = oFile.read()
64
+
65
+ return sText
40
66
  # --------------------------------------------------------------------------------------------------------------------
41
- def save(self, text_obj, filename=None):
67
+ def save(self, text_obj, filename=None, encoding="utf-8"):
42
68
  sFilename = self._useFileName(filename)
43
69
 
44
70
  """
@@ -48,9 +74,6 @@ class TextFile(FileObject):
48
74
  p_sFileName : Full path to the text file
49
75
  p_sText : Text to write
50
76
  """
51
- if (self.parent_folder is not None):
52
- sFilename = os.path.join(self.parent_folder, sFilename)
53
-
54
77
  if self.is_verbose:
55
78
  print(" {.} Saving text to %s" % sFilename)
56
79
 
@@ -61,12 +84,12 @@ class TextFile(FileObject):
61
84
  bIsIterable = text_obj.dtype = str
62
85
 
63
86
  if bIsIterable:
64
- with open(sFilename, "w") as oFile:
87
+ with open(sFilename, "w", encoding=encoding) as oFile:
65
88
  for sLine in text_obj:
66
89
  print(sLine, file=oFile)
67
90
  oFile.close()
68
91
  else:
69
- with open(sFilename, "w") as oFile:
92
+ with open(sFilename, "w", encoding=encoding) as oFile:
70
93
  print(text_obj, file=oFile)
71
94
  oFile.close()
72
95
  return True
radnn/system/filestore.py CHANGED
@@ -35,7 +35,7 @@ if (sys.version_info.major == 3) and (sys.version_info.minor <= 7):
35
35
  import pickle5 as pickle
36
36
  else:
37
37
  import pickle
38
-
38
+ from radnn.system.files import FileList
39
39
  from radnn.system.files import JSONFile
40
40
  from radnn.system.files import PickleFile
41
41
  from radnn.system.files import TextFile
@@ -53,6 +53,7 @@ class FileStore(object):
53
53
  def __init__(self, base_folder, is_verbose=False, must_exist=False):
54
54
  #.......................... | Instance Attributes | ............................
55
55
  self.base_folder = base_folder
56
+ self.absolute_path = os.path.abspath(base_folder)
56
57
  if not os.path.exists(self.base_folder):
57
58
  if must_exist:
58
59
  raise Exception(f"File store folder {self.base_folder} does not exist.")
@@ -98,7 +99,7 @@ class FileStore(object):
98
99
  return self.folder(subfolder_name)
99
100
  # --------------------------------------------------------------------------------------------------------
100
101
  def folder(self, folder_name):
101
- sFolder = os.path.join(self.base_folder, folder_name)
102
+ sFolder = os.path.join(self.absolute_path, folder_name)
102
103
  if not os.path.exists(sFolder):
103
104
  os.makedirs(sFolder)
104
105
 
@@ -110,13 +111,19 @@ class FileStore(object):
110
111
  file_name += "." + file_ext
111
112
  else:
112
113
  file_name += file_ext
113
- return os.path.join(self.base_folder, file_name)
114
+ return os.path.join(self.absolute_path, file_name)
114
115
  # --------------------------------------------------------------------------------------------------------
115
116
  def entries(self):
116
117
  return os.listdir(self.base_folder)
117
118
  # --------------------------------------------------------------------------------------------------------
118
- def list_files(self, file_matching_pattern, is_full_path=True, is_removing_extension=False, sort_filename_key=None):
119
- sEntries = glob.glob1(self.base_folder, file_matching_pattern)
119
+ def _ls(self, file_matching_pattern, is_removing_extension, sort_filename_key):
120
+ if ";" in file_matching_pattern:
121
+ sEntries = []
122
+ for sExt in file_matching_pattern.split(";"):
123
+ sEntries += glob.glob1(self.base_folder, sExt.strip())
124
+ else:
125
+ sEntries = glob.glob1(self.base_folder, file_matching_pattern)
126
+
120
127
  if is_removing_extension:
121
128
  oFileNamesOnly = []
122
129
  for sEntry in sEntries:
@@ -124,15 +131,24 @@ class FileStore(object):
124
131
  oFileNamesOnly.append(sFileNameOnly)
125
132
  sEntries = sorted(oFileNamesOnly, key=sort_filename_key)
126
133
 
134
+ return sEntries
135
+ # --------------------------------------------------------------------------------------------------------
136
+ def list_files(self, file_matching_pattern, is_full_path=True, is_removing_extension=False, sort_filename_key=None):
137
+ sEntries = self._ls(file_matching_pattern, is_removing_extension, sort_filename_key)
127
138
  if is_full_path:
128
139
  oResult = [os.path.join(self.base_folder, x) for x in sEntries]
129
140
  else:
130
141
  oResult = [x for x in sEntries]
131
-
132
142
  return oResult
133
143
  # --------------------------------------------------------------------------------------------------------
134
- @property
135
- def lis_folders(self, is_full_path=True):
144
+ def filelist(self, file_matching_pattern, is_removing_extension=False, sort_filename_key=None):
145
+ sEntries = self._ls(file_matching_pattern, is_removing_extension, sort_filename_key)
146
+ oFileList = FileList(self.base_folder)
147
+ for x in sEntries:
148
+ oFileList.append(x)
149
+ return oFileList
150
+ # --------------------------------------------------------------------------------------------------------
151
+ def list_folders(self, is_full_path=True):
136
152
  sResult = []
137
153
  for sFolder in os.listdir(self.base_folder):
138
154
  sFullPath = os.path.join(self.base_folder, sFolder)
@@ -163,10 +179,10 @@ class FileStore(object):
163
179
  pass
164
180
  # ----------------------------------------------------------------------------------
165
181
  def __repr__(self)->str:
166
- return self.base_folder
182
+ return self.absolute_path
167
183
  # --------------------------------------------------------------------------------------------------------
168
184
  def __str__(self)->str:
169
- return self.base_folder
185
+ return self.absolute_path
170
186
  # --------------------------------------------------------------------------------------------------------
171
187
  # ======================================================================================================================
172
188
 
@@ -35,7 +35,7 @@ from radnn.system.files import JSONFile
35
35
  # =======================================================================================================================
36
36
  class FileSystem(object):
37
37
  # --------------------------------------------------------------------------------------------------------
38
- def __init__(self, config_folder="MLConfig", model_folder="MLModels", dataset_folder="MLData", must_exist=False, setup_filename="*auto*", is_custom_setup=False):
38
+ def __init__(self, config_folder="MLConfig", model_folder="MLModels", dataset_folder="MLData", must_exist=False, setup_filename="*auto*", is_custom_setup=True):
39
39
  '''
40
40
  Initializes the file system settings for an experiment
41
41
  :param config_folder: The folder that contains the experiment hyperparameter files.
@@ -28,6 +28,7 @@
28
28
 
29
29
  # .......................................................................................
30
30
  import win32api
31
+ import ctypes
31
32
  class WindowsHost(object):
32
33
  # --------------------------------------------------------------------------------------------------------------------
33
34
  @classmethod
@@ -66,4 +67,13 @@ class WindowsHost(object):
66
67
  str_info = u'\\StringFileInfo\\%04X%04X\\%s' % (sLanguageCode, sCodePage, sVersionString)
67
68
  dInfo[sVersionString] = repr(win32api.GetFileVersionInfo(dll_filename, str_info))
68
69
  return dInfo
70
+ # --------------------------------------------------------------------------------------------------------------------
71
+ @classmethod
72
+ def set_windows_sleep_resolution(cls, msecs=1):
73
+ """
74
+ Requests a minimum resolution for periodic timers. This increases accuracy
75
+ for the waiting interval of the time.sleep function
76
+ """
77
+ oWinMM = ctypes.WinDLL('oWinMM')
78
+ oWinMM.timeBeginPeriod(msecs)
69
79
  # --------------------------------------------------------------------------------------------------------------------
@@ -0,0 +1,5 @@
1
+ from .thread_context import ThreadContext, ThreadEx
2
+ from .thread_worker import ThreadWorker
3
+ from .semaphore_lock import SemaphoreLock
4
+ from .thread_safe_queue import ThreadSafeQueue
5
+ from .thread_safe_string_collection import ThreadSafeQueue
@@ -0,0 +1,58 @@
1
+ # ======================================================================================
2
+ #
3
+ # Rapid Deep Neural Networks
4
+ #
5
+ # Licensed under the MIT License
6
+ # ______________________________________________________________________________________
7
+ # ......................................................................................
8
+
9
+ # Copyright (c) 2018-2025 Pantelis I. Kaplanoglou
10
+
11
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
12
+ # of this software and associated documentation files (the "Software"), to deal
13
+ # in the Software without restriction, including without limitation the rights
14
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
+ # copies of the Software, and to permit persons to whom the Software is
16
+ # furnished to do so, subject to the following conditions:
17
+
18
+ # The above copyright notice and this permission notice shall be included in all
19
+ # copies or substantial portions of the Software.
20
+
21
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27
+ # SOFTWARE.
28
+
29
+ # .......................................................................................
30
+ from threading import BoundedSemaphore
31
+
32
+ #=======================================================================================================================
33
+ class SemaphoreLock(BoundedSemaphore):
34
+ # ------------------------------------------------------------------------------------------------------------------
35
+ def __init__(self, value=1):
36
+ super(SemaphoreLock, self).__init__(value)
37
+ # ------------------------------------------------------------------------------------------------------------------
38
+ def lock(self, blocking=True, timeout=None):
39
+ self.acquire(blocking, timeout)
40
+ # ------------------------------------------------------------------------------------------------------------------
41
+ def unlock(self):
42
+ self.release()
43
+ # ------------------------------------------------------------------------------------------------------------------
44
+ # //TODO: Not working, check if this can be fixed
45
+ '''
46
+ def __enter__(self):
47
+ self.Lock()
48
+ return self
49
+
50
+ def __exit__(self, exception_type, exception_val, trace):
51
+ try:
52
+ self.Unlock()
53
+ except:
54
+ print("Could not unlock semaphore")
55
+ return True
56
+ '''
57
+ # ------------------------------------------------------------------------------------------------------------------
58
+ #=======================================================================================================================
@@ -0,0 +1,175 @@
1
+ # ======================================================================================
2
+ #
3
+ # Rapid Deep Neural Networks
4
+ #
5
+ # Licensed under the MIT License
6
+ # ______________________________________________________________________________________
7
+ # ......................................................................................
8
+
9
+ # Copyright (c) 2018-2025 Pantelis I. Kaplanoglou
10
+
11
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
12
+ # of this software and associated documentation files (the "Software"), to deal
13
+ # in the Software without restriction, including without limitation the rights
14
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
+ # copies of the Software, and to permit persons to whom the Software is
16
+ # furnished to do so, subject to the following conditions:
17
+
18
+ # The above copyright notice and this permission notice shall be included in all
19
+ # copies or substantial portions of the Software.
20
+
21
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27
+ # SOFTWARE.
28
+
29
+ # .......................................................................................
30
+ import time
31
+ from threading import Thread, Event, get_ident
32
+ from datetime import datetime
33
+
34
+
35
+ #=======================================================================================================================
36
+ class ThreadEx(Thread):
37
+ # ------------------------------------------------------------------------------------------------------------------
38
+ def __init__(self,target=None, name=None, args=(), kwargs=None):
39
+ #//TODO: delegate target, args and kwargs properly
40
+ super(ThreadEx, self).__init__(target=target, name=name, args=args, kwargs=kwargs)
41
+ self._stop_event = Event()
42
+ # ------------------------------------------------------------------------------------------------------------------
43
+ def stop(self):
44
+ self._stop_event.set()
45
+ # ------------------------------------------------------------------------------------------------------------------
46
+ @property
47
+ def is_stopped(self):
48
+ return self._stop_event.is_set()
49
+ # ------------------------------------------------------------------------------------------------------------------
50
+ #=======================================================================================================================
51
+
52
+
53
+
54
+
55
+
56
+
57
+
58
+
59
+
60
+ #=======================================================================================================================
61
+ class ThreadContext(object):
62
+ __NEXT_ID = 0
63
+
64
+ # ------------------------------------------------------------------------------------------------------------------
65
+ def __init__(self, name=None, is_daemon_thread=True, verbose_level=1):
66
+ #........................... | Instance Attributes | ...........................
67
+ type(self).__NEXT_ID += 1
68
+ if name is None:
69
+ self.name = str(type(self).__NEXT_ID)
70
+ else:
71
+ self.name = f"{name}{str(type(self).__NEXT_ID)}"
72
+ self.thread_id = None
73
+ self.verbose_level = verbose_level
74
+
75
+ #// Settings \\
76
+ self.is_daemon_thread = is_daemon_thread
77
+ self.join_timeout = 5 #secs
78
+
79
+ # // Control Variables \\
80
+ self.must_continue = False
81
+ self.has_finished = False
82
+ self.has_started = False
83
+
84
+ # // Agregated Objects \\
85
+ self.thread_handle = None
86
+ self.thread_args = None
87
+ self.on_after_finish_handler = None
88
+ self.run_once_func = None
89
+ #................................................................................
90
+ # ------------------------------------------------------------------------------------------------------------------
91
+ def sleep(self, interval_in_msecs):
92
+ time.sleep(interval_in_msecs / 1000.0)
93
+ # ------------------------------------------------------------------------------------------------------------------
94
+ def _thread_start(self, args):
95
+ self.thread_id = get_ident()
96
+ self.thread_args = args
97
+ self.has_started = True
98
+
99
+ if self.verbose_level > 0:
100
+ print(f"{self} is starting with arguments:", args)
101
+
102
+ self.has_finished = False
103
+ try:
104
+ if self.run_once_func is None:
105
+ self.loop()
106
+ else:
107
+ self.run_once_func(args)
108
+ finally:
109
+ self.has_finished = True
110
+ # ------------------------------------------------------------------------------------------------------------------
111
+ def _thread_finish(self):
112
+ while not self.has_finished:
113
+ pass
114
+
115
+ # Callback after finishing
116
+ if self.on_after_finish_handler is not None:
117
+ self.on_after_finish_handler()
118
+
119
+ # Signal the thread to stop via the event
120
+ self.thread_handle.stop()
121
+
122
+ # Wait for the thread to finish
123
+ if self.verbose_level > 1:
124
+ print(f"{self} joining...")
125
+
126
+ self.thread_handle.join(self.join_timeout)
127
+
128
+ if self.verbose_level > 1:
129
+ nTimeDelta = datetime.now() - self._stop_action_start
130
+ print(f"{self} joined after {(nTimeDelta.microseconds / 1000):.3f} msecs")
131
+ # ------------------------------------------------------------------------------------------------------------------
132
+ def start(self, args=None):
133
+ self.must_continue = True
134
+
135
+ self.thread_handle = ThreadEx(target=self._thread_start, args=(), kwargs={"args": args})
136
+ self.thread_handle.setDaemon(True)
137
+ self.thread_handle.start()
138
+ # ------------------------------------------------------------------------------------------------------------------
139
+ def resume(self, args=None):
140
+ if not self.has_started:
141
+ self.start(args)
142
+ # ------------------------------------------------------------------------------------------------------------------
143
+ def stop(self):
144
+ self._stop_action_start = datetime.now()
145
+ if self.verbose_level > 0:
146
+ print(f"{self} is stopping ...")
147
+ # Break the loop and wait for the method to exit
148
+ self.must_continue = False
149
+ self._thread_finish()
150
+ # ------------------------------------------------------------------------------------------------------------------
151
+ def terminate(self):
152
+ self.stop()
153
+ # ------------------------------------------------------------------------------------------------------------------
154
+ def loop(self):
155
+ pass
156
+ # ------------------------------------------------------------------------------------------------------------------
157
+ def __str__(self):
158
+ return f"{self.name} ({self.thread_id})"
159
+ # ------------------------------------------------------------------------------------------------------------------
160
+ def __repr__(self):
161
+ return self.__str__()
162
+ # ------------------------------------------------------------------------------------------------------------------
163
+ #=======================================================================================================================
164
+
165
+
166
+
167
+
168
+
169
+
170
+
171
+
172
+
173
+
174
+
175
+
@@ -0,0 +1,163 @@
1
+ # ======================================================================================
2
+ #
3
+ # Rapid Deep Neural Networks
4
+ #
5
+ # Licensed under the MIT License
6
+ # ______________________________________________________________________________________
7
+ # ......................................................................................
8
+
9
+ # Copyright (c) 2018-2025 Pantelis I. Kaplanoglou
10
+
11
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
12
+ # of this software and associated documentation files (the "Software"), to deal
13
+ # in the Software without restriction, including without limitation the rights
14
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
+ # copies of the Software, and to permit persons to whom the Software is
16
+ # furnished to do so, subject to the following conditions:
17
+
18
+ # The above copyright notice and this permission notice shall be included in all
19
+ # copies or substantial portions of the Software.
20
+
21
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27
+ # SOFTWARE.
28
+
29
+ # .......................................................................................
30
+ from .semaphore_lock import SemaphoreLock
31
+
32
+
33
+
34
+ class ThreadSafeQueue(object):
35
+ #-------------------------------------------------------------------------------------------------------------------
36
+ def __init__(self, name="Queue", max_queued_items=None):
37
+ #........................... | Instance Attributes | ...........................
38
+ self.name = name
39
+ self.queue=[]
40
+
41
+ # // Settings \\
42
+ self.max_queued_items = max_queued_items
43
+ self.can_delete = True
44
+
45
+ # // Control Params \\
46
+ self.is_queue_locked = False
47
+
48
+ # // Composites \\
49
+ self.update_lock = SemaphoreLock()
50
+ #................................................................................
51
+
52
+ # -------------------------------------------------------------------------------------------------------------------
53
+ @property
54
+ def count(self):
55
+ return len(self.queue)
56
+
57
+ # -------------------------------------------------------------------------------------------------------------------
58
+ @property
59
+ def is_empty(self):
60
+ bResult = (len(self.queue) == 0)
61
+
62
+ return bResult
63
+ #-------------------------------------------------------------------------------------------------------------------
64
+ def push(self, value):
65
+ self.update_lock.lock()
66
+ try:
67
+ if self.max_queued_items is None:
68
+ bCanAppend = True
69
+ else:
70
+ bCanAppend = len(self.queue) < self.max_queued_items
71
+
72
+ if bCanAppend:
73
+ self.queue.append(value)
74
+ finally:
75
+ self.update_lock.unlock()
76
+ #-------------------------------------------------------------------------------------------------------------------
77
+ def pop(self, index=0):
78
+ nValue = None
79
+ if self.can_delete:
80
+ self.update_lock.lock()
81
+ try:
82
+ bMustPop = len(self.queue) > 0
83
+ if bMustPop:
84
+ if index == -1:
85
+ index = len(self.queue) - 1
86
+ nValue = self.queue.pop(index)
87
+ finally:
88
+ self.update_lock.unlock()
89
+
90
+ return nValue
91
+ #-------------------------------------------------------------------------------------------------------------------
92
+ def clear(self):
93
+ self.update_lock.lock()
94
+ try:
95
+ self.queue = []
96
+ finally:
97
+ self.update_lock.unlock()
98
+ #-------------------------------------------------------------------------------------------------------------------
99
+ '''
100
+ def pop_ex(self, index=0):
101
+ nValue,nRemainingItemCount = [None,None]
102
+ if self.can_delete:
103
+ self.update_lock.Lock()
104
+ try:
105
+ nRemainingItemCount = len(self.queue)
106
+ bMustPop = nRemainingItemCount > 0
107
+ if bMustPop:
108
+ if index == -1:
109
+ index = len(self.queue) - 1
110
+ nValue = self.queue.pop(index)
111
+ nRemainingItemCount = len(self.queue)
112
+ finally:
113
+ self.update_lock.UnLock()
114
+
115
+ return nValue, nRemainingItemCount
116
+ '''
117
+ #-------------------------------------------------------------------------------------------------------------------
118
+ def push_ex(self, message):
119
+ while self.is_queue_locked:
120
+ pass
121
+
122
+ if self.max_queued_items is None:
123
+ bCanAppend = True
124
+ else:
125
+ bCanAppend = len(self.queue) < self.max_queued_items
126
+
127
+ if not bCanAppend:
128
+ return
129
+
130
+ self.is_queue_locked = True
131
+ try:
132
+ self.queue.append(message)
133
+ finally:
134
+ self.is_queue_locked = False
135
+ #-------------------------------------------------------------------------------------------------------------------
136
+ def pop_ex(self):
137
+ sMessage = None
138
+ if self.can_delete:
139
+ while self.is_queue_locked:
140
+ pass
141
+
142
+ self.is_queue_locked = True
143
+ try:
144
+ if len(self.queue) > 0:
145
+ sMessage = self.queue.pop(0)
146
+ finally:
147
+ self.is_queue_locked = False
148
+
149
+ return sMessage
150
+ #-------------------------------------------------------------------------------------------------------------------
151
+
152
+
153
+
154
+
155
+
156
+
157
+
158
+
159
+
160
+
161
+
162
+
163
+
@@ -0,0 +1,66 @@
1
+ from .thread_safe_queue import ThreadSafeQueue
2
+
3
+ class StringCollectionThreadSafe(ThreadSafeQueue):
4
+ # -------------------------------------------------------------------------------------------------------------------
5
+ def __init__(self, filename=None, name="Text"):
6
+ super(StringCollectionThreadSafe, self).__init__(name)
7
+
8
+ self.filename = filename
9
+ self.__count = 0
10
+ self.__index = 0
11
+ # -------------------------------------------------------------------------------------------------------------------
12
+ def append(self, text):
13
+ self.push(text)
14
+ # -------------------------------------------------------------------------------------------------------------------
15
+ def print(self, text, *args):
16
+ if args is None:
17
+ self.push(text)
18
+ else:
19
+ self.push(text + " " + " ".join(map(str, args)))
20
+ # -------------------------------------------------------------------------------------------------------------------
21
+ def flush(self):
22
+ if self.CanDelete:
23
+ with open(self.filename, "a") as oFile:
24
+ for sLine in self.queue:
25
+ print(sLine, file=oFile)
26
+ self.clear()
27
+ # -------------------------------------------------------------------------------------------------------------------
28
+ def display_and_flush(self):
29
+ if self.CanDelete:
30
+ if self.filename is None:
31
+ for sLine in self.queue:
32
+ print(sLine)
33
+ else:
34
+ with open(self.filename, "a") as oFile:
35
+ for sLine in self.queue:
36
+ print(sLine, file=oFile)
37
+ self.clear()
38
+ # -------------------------------------------------------------------------------------------------------------------
39
+ def __iter__(self):
40
+ self.update_lock.Lock()
41
+ try:
42
+ self.__index = 0
43
+ self.__count = len(self.queue)
44
+ self.CanDelete = False
45
+ finally:
46
+ self.update_lock.UnLock()
47
+
48
+ return self
49
+ # -------------------------------------------------------------------------------------------------------------------
50
+ def __next__(self):
51
+ if self.__index < self.__count:
52
+ oResult = self.queue[self.__index]
53
+ self.__index += 1
54
+ return oResult
55
+ else:
56
+ self.CanDelete = True
57
+ raise StopIteration()
58
+ # -------------------------------------------------------------------------------------------------------------------
59
+
60
+
61
+
62
+
63
+
64
+
65
+
66
+