corelp 1.0.37__py3-none-any.whl → 1.0.39__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 (43) hide show
  1. corelp/__init__.py +17 -10
  2. corelp/modules/Path_LP/functions/__template__.py +19 -0
  3. corelp/modules/Path_LP/test_Path.py +1 -1
  4. corelp/modules/debug_LP/functions/__template__.py +19 -0
  5. corelp/modules/folder_LP/functions/__template__.py +19 -0
  6. corelp/modules/getmodule_LP/functions/__template__.py +19 -0
  7. corelp/modules/getmodule_LP/getmodule.py +16 -33
  8. corelp/modules/icon_LP/functions/__init__.py +0 -0
  9. corelp/modules/icon_LP/functions/__template__.py +19 -0
  10. corelp/modules/icon_LP/icon.py +46 -0
  11. corelp/modules/icon_LP/test_icon.py +79 -0
  12. corelp/modules/kwargsself_LP/functions/__init__.py +0 -0
  13. corelp/modules/kwargsself_LP/functions/__template__.py +19 -0
  14. corelp/modules/prop_LP/functions/__init__.py +0 -0
  15. corelp/modules/prop_LP/functions/__template__.py +19 -0
  16. corelp/modules/rfrom_LP/functions/__init__.py +0 -0
  17. corelp/modules/rfrom_LP/functions/__template__.py +19 -0
  18. corelp/modules/rfrom_LP/test_rfrom.py +1 -1
  19. corelp/modules/selfkwargs_LP/functions/__init__.py +0 -0
  20. corelp/modules/selfkwargs_LP/functions/__template__.py +19 -0
  21. corelp/modules/test_LP/functions/__init__.py +0 -0
  22. corelp/modules/test_LP/functions/__template__.py +19 -0
  23. corelp/routines/__init__.py +0 -0
  24. {corelp-1.0.37.dist-info → corelp-1.0.39.dist-info}/METADATA +1 -6
  25. corelp-1.0.39.dist-info/RECORD +57 -0
  26. {corelp-1.0.37.dist-info → corelp-1.0.39.dist-info}/WHEEL +2 -2
  27. corelp/modules/Section_LP/Section.py +0 -176
  28. corelp/modules/Section_LP/test_Section.py +0 -43
  29. corelp/modules/main_LP/main.py +0 -251
  30. corelp/modules/main_LP/test_main.py +0 -74
  31. corelp/modules/print_LP/print.py +0 -326
  32. corelp/modules/print_LP/test_print.py +0 -108
  33. corelp/modules/user_inputs_LP/test_user_inputs.py +0 -46
  34. corelp/modules/user_inputs_LP/user_inputs.py +0 -87
  35. corelp/modules.json +0 -80
  36. corelp/pythonLP.png:Zone.Identifier +0 -0
  37. corelp/scripts.json +0 -1
  38. corelp-1.0.37.dist-info/RECORD +0 -49
  39. /corelp/modules/{Section_LP → Path_LP/functions}/__init__.py +0 -0
  40. /corelp/modules/{main_LP → debug_LP/functions}/__init__.py +0 -0
  41. /corelp/modules/{print_LP → folder_LP/functions}/__init__.py +0 -0
  42. /corelp/modules/{user_inputs_LP → getmodule_LP/functions}/__init__.py +0 -0
  43. /corelp/{scripts → modules/icon_LP}/__init__.py +0 -0
@@ -1,176 +0,0 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
- # Date : 2025-08-28
4
- # Author : Lancelot PINCET
5
- # GitHub : https://github.com/LancelotPincet
6
- # Library : coreLP
7
- # Module : Section
8
-
9
- """
10
- This class defines decorator instances allowing to create section functions.
11
- """
12
-
13
-
14
-
15
- # %% Libraries
16
- from corelp import print, folder, selfkwargs, kwargsself
17
- from dataclasses import dataclass
18
- import pickle
19
- import joblib
20
- from pathlib import Path
21
- from functools import wraps
22
- import hashlib
23
- import inspect
24
- import os
25
-
26
-
27
-
28
- # %% Class
29
- @dataclass(slots=True, kw_only=True)
30
- class Section() :
31
- '''
32
- This class defines decorator instances allowing to create section functions.
33
- Cache results into a folder, if another call occurs, can load-back the precalculated data.
34
-
35
- Parameters
36
- ----------
37
- path : str or Path
38
- path where to save section folder results.
39
- new : bool
40
- True to ignore pre-calculated data and crush them.
41
- num : int
42
- Index of section, after one call, adds 1 for next call.
43
- parent_path : str or Path
44
- Path to the parent folder if bulk processing.
45
-
46
- Examples
47
- --------
48
- >>> from corelp import Section
49
- ...
50
- >>> section = Section(path=export_path)
51
- ...
52
- >>> @section()
53
- ... def add(a, b=0) :
54
- ... testfunc.print('Hello World')
55
- ... return a + b
56
- ...
57
- >>> testfunc.print('3+0=', add(3)) # First call calculates and save result
58
- >>> testfunc.print('3+0=', add(3, 0)) # Second call loads back precalculated results
59
- >>> testfunc.print('1+3=', add(1, 3)) # New call with other parameters : crushed previous results with new ones
60
- >>> testfunc.print('1+3=', add(1, b=3)) # Second call with these parameters : loads precalculated results
61
- ...
62
- >>> @section(cache=False) # Creates an index of 2, does no caching
63
- ... def sub(a, b=0) :
64
- ... return a - b
65
- ...
66
- >>> @section(num=10) # Creates an index of 10
67
- ... def mul(a, b=0) :
68
- ... return a * b
69
- ...
70
- >>> @section(new=True) # Creates an index of 11, always creates new cache
71
- ... def div(a, b) :
72
- ... return a / b
73
- '''
74
-
75
- # Attributes
76
- path : Path | str = None
77
- new :bool = False
78
- num :int = 0
79
- parent_path : Path | str = None
80
-
81
- # Init
82
- def __post_init__(self) :
83
- if self.path is not None :
84
- self.path = Path(self.path)
85
- if self.parent_path is not None :
86
- self.parent_path = Path(self.parent_path)
87
-
88
- # Decorator
89
- def __call__(self, *, new=None, num=None, symlink=None, cache=True):
90
- if new is None :
91
- new = self.new
92
- if num is None :
93
- num = self.num
94
- self.num = num+1
95
-
96
- def decorator(func) :
97
- name = func.__name__
98
-
99
- @wraps(func)
100
- def wrapper(*args, **kwargs):
101
- wrapper.path = self.path / f"{num:03}_{name}"
102
- print(f'\n#### **{num}. {name.replace("_"," ")} section**\n')
103
-
104
- # Creating hash
105
- if cache :
106
- print('**Call hash:**', do_stdout=False)
107
- bound = inspect.signature(func).bind(*args, **kwargs)
108
- bound.apply_defaults()
109
- serialized = pickle.dumps(bound.arguments)
110
- args_hash = hashlib.md5(serialized).hexdigest()
111
- result_file = wrapper.path / f'{args_hash}.pkl'
112
- print(f'*{args_hash}*\n', do_stdout=False)
113
-
114
- # Checking already calculated exists
115
- if result_file.exists() and not new :
116
- print('**Loading from *precalculated* results...**')
117
- with open(result_file, 'rb') as f:
118
- result = joblib.load(f)
119
- print('...loaded\n')
120
- return result
121
-
122
- # Calculations
123
- folder(wrapper.path, warning=False)
124
- print('**Calculating results:**')
125
- print_status = kwargsself(print)
126
- print.file = wrapper.path / f'{name}_log.md'
127
- result = func(*args, **kwargs)
128
- selfkwargs(print, print_status)
129
- print('...calculated\n')
130
-
131
- # Caching
132
- if cache :
133
- print('**Saving results:**')
134
- with open(result_file, 'wb') as f:
135
- joblib.dump(result, f)
136
- print('...saved\n')
137
-
138
- # Create symlink
139
- if symlink is not None :
140
- print('**Creating symlinks:**')
141
- for link in symlink :
142
- print(f"- {link}")
143
- link_path = Path(link)
144
- link_folder = self.parent_path.parent / f'_outputs/{link_path.stem}'
145
- new_stem = str(self.subfolder.as_posix()).replace('/', '--').replace(' ', '_')
146
- if not link_folder.exists() :
147
- folder(link_folder, warning=False)
148
- link_from = wrapper.path / link_path
149
- link_to = link_folder / f"{new_stem}{link_path.suffix}"
150
- if link_to.exists() or link_to.is_symlink():
151
- link_to.unlink()
152
- if os.name == "nt":
153
- try :
154
- link_to.symlink_to(link_from, link_from.is_dir())
155
- except OSError :
156
- print("Windows does not allow to create symlink, aborting. Consider using Windows in Developper mode.")
157
- break
158
- else:
159
- link_to.symlink_to(link_from)
160
- print('...created\n')
161
-
162
-
163
- return result
164
- return wrapper
165
- return decorator
166
-
167
- @property
168
- def subfolder(self) :
169
- return self.path.relative_to(self.parent_path)
170
-
171
-
172
-
173
- # %% Test function run
174
- if __name__ == "__main__":
175
- from corelp import test
176
- test(__file__)
@@ -1,43 +0,0 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
- # Date : 2025-08-28
4
- # Author : Lancelot PINCET
5
- # GitHub : https://github.com/LancelotPincet
6
- # Library : coreLP
7
- # Module : Section
8
-
9
- """
10
- This file allows to test Section
11
-
12
- Section : This class defines decorator instances allowing to create section functions.
13
- """
14
-
15
-
16
-
17
- # %% Libraries
18
- from corelp import debug, Section
19
- debug_folder = debug(__file__)
20
-
21
-
22
-
23
- # %% Function test
24
- def test_function() :
25
- '''
26
- Test Section function
27
- '''
28
- section = Section(path=debug_folder)
29
-
30
- @section()
31
- def add(a, b=0) :
32
- return a+b
33
- assert add(3) == 3
34
- assert add(3, 0) == 3
35
- assert add(1, 3) == 4
36
- assert add(1, b=3) == 4
37
-
38
-
39
-
40
- # %% Test function run
41
- if __name__ == "__main__":
42
- from corelp import test
43
- test(__file__)
@@ -1,251 +0,0 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
- # Date : 2025-08-28
4
- # Author : Lancelot PINCET
5
- # GitHub : https://github.com/LancelotPincet
6
- # Library : coreLP
7
- # Module : main
8
-
9
- """
10
- This function can decorate the main function of a script.
11
- """
12
-
13
-
14
-
15
- # %% Libraries
16
- from corelp import print, Section, folder, selfkwargs, kwargsself, icon, Path
17
- import time
18
- import functools
19
- import os
20
- from datetime import datetime
21
- import tkinter as tk
22
- from tkinter import filedialog
23
- import types
24
-
25
-
26
-
27
- # %% Function
28
- def main() :
29
- '''
30
- This function can decorate the main function of a script.
31
- User inputs parameters shoud be put in the beginning of the main file, and the decorated function will recognize them.
32
- Decorated function can change the values of these parameters with keyword arguments when called.
33
- Section can be created bellow the mainfunction.
34
-
35
- Global parameters
36
- -----------------
37
- import_path : Path or str or None
38
- Path where to import script data to process.
39
- If None, will manually ask user to select it.
40
- If not existent, will be ignored.
41
- export_path : Path or str or None
42
- Path where to export script data to process.
43
- A new folder will be created inside at the call time as name.
44
- If None, will save in import_path. If not existent, will be ignored.
45
- If a previous call was already made in this same folder, and new is False, will try to reload data from this last folder.
46
- new : bool
47
- Overrides Decorator new parameter.
48
- bulk : function
49
- function(import_path) that returns a dictionnary of {import_subfolder:export_subfolder} for multiple decorated function run.
50
- If bulk is not None, the decorated function will run with import_subfolder, export_subfolder instead of import_path, export_path (see below).
51
- The import_subfolders and export_subfolder are defined from import_path and export_path respectively (they are not absolute from root path).
52
- overnight : bool
53
- If True and exception occurs, will skip and pass to the next run in bulk processing. To use for example for overnight bulk processing.
54
-
55
- Examples
56
- --------
57
- >>> from corelp import main
58
- ...
59
- >>> import_path = None # will be asked via a GUI
60
- >>> export_path = None # will create inside import_path
61
- >>> new = False # True to create a new export folder, False to reload precalculated data
62
- >>> bulk = None # function(import_path) that returns a dictionnary of {import_subfolder:export_subfolder} for multiple decorated function run.
63
- >>> overnight= False # If True and exception occurs, will skip and pass to the next run in bulk processing.
64
- >>> main_string = "Hello from main!" # User input parameter
65
- ...
66
- >>> @main(new=True) # if previous new is not defined, new is defined here
67
- ... def myscript() :
68
- ... print(main_string) # By default prints "Hello from main!"
69
- ... result = mysection() # Section defined bellow, result can be reloaded from previous run
70
- ... return result
71
- ...
72
- ... @main.section()
73
- ... def mysection() :
74
- ... print("Hello from section!")
75
- ... return True # Will be saved into export_path and can be reuploaded at next run with same inputs
76
- ...
77
- >>> # Launch
78
- >>> if __name__ == "__main__" :
79
- ... myscript() # prints "Hello from main!"
80
- ... myscript(main_string = "Hello changed!!") # prints "Hello changed!!" and loads section result from first run
81
- '''
82
-
83
-
84
-
85
- def decorator(func) :
86
- name = func.__name__
87
-
88
- # Get globals around function definition
89
- definition_globals = func.__globals__
90
-
91
- @functools.wraps(func)
92
- def wrapper(**overrides) -> None :
93
-
94
- # Creates new globals
95
- exec_globals = definition_globals.copy()
96
- exec_globals.update(overrides)
97
- _new = exec_globals.get("new", False)
98
- _bulk = exec_globals.get("bulk", None)
99
- _overnight = exec_globals.get("overnight", False)
100
-
101
- # Creates new function
102
- new_func = types.FunctionType(
103
- func.__code__,
104
- exec_globals,
105
- name=name,
106
- argdefs=func.__defaults__,
107
- closure=func.__closure__,
108
- )
109
-
110
- # Getting paths
111
- ipath = exec_globals.get('import_path', "None")
112
- if ipath is None :
113
- root = tk.Tk()
114
- root.title("Select import path")
115
- img = tk.PhotoImage(file=icon)
116
- root.iconphoto(True, img)
117
- root._icon_img = img # keep reference
118
- root.withdraw()
119
- root.update_idletasks()
120
- root.attributes("-topmost", True)
121
- root.update()
122
- root.focus_force()
123
- ipath = filedialog.askdirectory(title=f'Select import path for {name}')
124
- root.destroy()
125
- if not ipath :
126
- print('Searching for import_path was cancelled', style='red')
127
- raise ValueError('Searching for import_path was cancelled')
128
- epath = exec_globals.get('export_path', "None")
129
- if ipath != "None" :
130
- ipath = Path(ipath)
131
- if epath != "None" :
132
- epath = ipath.parent if epath is None else Path(epath)
133
-
134
- # Creating new export path
135
- prefix = name.replace('.', '_')
136
- if epath != "None" :
137
- if _new :
138
- base_path = folder(epath / (f'{prefix}_' + datetime.now().strftime("%Y-%m-%d-%Hh%Mmin%Ss")), warning=False)
139
- else :
140
- #Searching for newest old folder
141
- base_folder = None
142
- _date = None
143
- for f in epath.iterdir() :
144
- if (not f.is_dir()) or (not f.name.startswith(f'{prefix}_')) :
145
- continue
146
- date_str = f.name.split('_')[-1]
147
- date = datetime.strptime(date_str, "%Y-%m-%d-%Hh%Mmin%Ss")
148
- if _date is None or date > _date :
149
- _date, base_folder = date, f
150
- base_path = base_folder if base_folder is not None else epath / (f'{prefix}_' + datetime.now().strftime("%Y-%m-%d-%Hh%Mmin%Ss"))
151
- epath = base_path / 'export_folder'
152
- if not epath.exists():
153
- os.makedirs(epath) #creates folders until end
154
- if ipath != "None" :
155
- ilink = base_path / 'import_folder'
156
- if ilink.exists() or ilink.is_symlink():
157
- ilink.unlink()
158
- if os.name == "nt":
159
- try :
160
- ilink.symlink_to(ipath, ipath.is_dir())
161
- except OSError :
162
- print("Windows does not allow to create symlink, aborting. Consider using Windows in Developper mode.")
163
- else:
164
- ilink.symlink_to(ipath)
165
- md_file = epath / (name+'_log.md')
166
- html_file = epath / (name+'_log.html')
167
- else :
168
- md_file = None
169
- html_file = None
170
-
171
- # Defining bulk processing
172
- if _bulk is None :
173
- subfolders = {"" : ""}
174
- else :
175
- subfolders = _bulk(ipath)
176
-
177
- #Begining prints
178
- print_status = kwargsself(print)
179
- print.console = None
180
- print.file = md_file
181
- print(f'\n\n\n# **BEGIN {name}**\n')
182
- print(f"{time.ctime()}")
183
- if ipath != "None" :
184
- print(f'import_path : {ipath}\n')
185
- if epath != "None" :
186
- print(f'export_path : {epath}\n')
187
-
188
- # Bulk processing
189
- results = {} # {export_subfolder : fucntion result}
190
- for import_subfolder, export_subfolder in subfolders.items() :
191
- if ipath != "None" :
192
- impath = ipath / import_subfolder
193
- exec_globals["import_path"] = impath
194
- if epath != "None" :
195
- expath = epath / export_subfolder
196
- exec_globals["export_path"] = expath
197
-
198
- # Create export subfolder
199
- if not expath.exists() :
200
- os.mkdir(expath)
201
-
202
- # Updating sections
203
- wrapper.section.parent_path = epath
204
- wrapper.section.path = expath
205
- wrapper.section.new = _new
206
-
207
- #Applying function
208
- print("\n---\n")
209
- subfolder_string = f"{export_subfolder}" if export_subfolder != "" else ""
210
- print(f'## **Launched script {subfolder_string}**\n')
211
- tic = time.perf_counter()
212
- try :
213
- results[export_subfolder] = new_func()
214
-
215
- # Errors
216
- except Exception as e :
217
- toc = time.perf_counter()
218
- print.error()
219
- print(f'\n## **{subfolder_string} took {toc-tic:.2f}s**')
220
- print("\n---\n")
221
- if not _overnight :
222
- raise e
223
-
224
- # No error
225
- else :
226
- toc = time.perf_counter()
227
- print(f'\n## **{subfolder_string} took {toc-tic:.2f}s**')
228
- print("\n---\n")
229
-
230
- # END
231
- print(time.ctime())
232
- print(f'# **END {name}**\n\n')
233
- print.export_html(html_file)
234
- selfkwargs(print, print_status)
235
- if _bulk is None :
236
- results = results[""]
237
- return results
238
-
239
- # Making sections
240
- section = Section()
241
- wrapper.section = section
242
-
243
- return wrapper
244
- return decorator
245
-
246
-
247
-
248
- # %% Test function run
249
- if __name__ == "__main__":
250
- from corelp import test
251
- test(__file__)
@@ -1,74 +0,0 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
- # Date : 2025-08-28
4
- # Author : Lancelot PINCET
5
- # GitHub : https://github.com/LancelotPincet
6
- # Library : coreLP
7
- # Module : main
8
-
9
- """
10
- This file allows to test main
11
-
12
- main : This function can decorate the main function of a script.
13
- """
14
-
15
-
16
-
17
- # %% Libraries
18
- from corelp import print, debug, main
19
- from time import sleep
20
- import pytest
21
- debug_folder = debug(__file__)
22
-
23
-
24
-
25
- # %% User inputs
26
- search = False # True to apply manual search
27
- global import_path
28
- global export_path
29
- import_path = None if search else debug_folder # Path to the imported data
30
- export_path = import_path # Path to the exported data
31
- new = False # True to create new result folder at each run
32
- bulk = None # function(import_path) that returns a dictionnary of {import_subfolder:export_subfolder} for multiple decorated function run.
33
- overnight= False # If True and exception occurs, will skip and pass to the next run in bulk processing.
34
- myparam = "Hello from main!"
35
- apply_error = False
36
-
37
-
38
-
39
- @main()
40
- def mainfunc() :
41
- if apply_error :
42
- 1/0
43
- print(myparam)
44
- result = section_1()
45
- print(f"import_path = {import_path}")
46
- return result
47
-
48
- @mainfunc.section()
49
- def section_1() :
50
- print('> Hello from section!')
51
- return True
52
-
53
-
54
-
55
- # %% Function test
56
- def test_function() :
57
- '''
58
- Test main function
59
- '''
60
- mainfunc()
61
- sleep(2) # Ensure new folder
62
- mainfunc(myparam="Hello changed!!")
63
- sleep(2) # Ensure new folder
64
- mainfunc(new=True)
65
- sleep(2) # Ensure new folder
66
- with pytest.raises(ZeroDivisionError, match="division by zero") :
67
- mainfunc(apply_error=True)
68
-
69
-
70
-
71
- # %% Test function run
72
- if __name__ == "__main__":
73
- from corelp import test
74
- test(__file__)