1 # -*- coding: utf-8 -*-
3 # Copyright 2019-2022 Jean-Pierre LEDURE, Rafael LIMA, Alain ROMEDENNE
5 # ======================================================================================================================
6 # === The ScriptForge library and its associated libraries are part of the LibreOffice project. ===
7 # === Full documentation is available on https://help.libreoffice.org/ ===
8 # ======================================================================================================================
10 # ScriptForge is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 # ScriptForge is free software; you can redistribute it and/or modify it under the terms of either (at your option):
16 # 1) The Mozilla Public License, v. 2.0. If a copy of the MPL was not
17 # distributed with this file, you can obtain one at http://mozilla.org/MPL/2.0/ .
19 # 2) The GNU Lesser General Public License as published by
20 # the Free Software Foundation, either version 3 of the License, or
21 # (at your option) any later version. If a copy of the LGPL was not
22 # distributed with this file, see http://www.gnu.org/licenses/ .
25 Collection of Python helper functions called from the ScriptForge Basic libraries
26 to execute specific services that are not or not easily available from Basic directly.
27 When relevant, the methods present in the ScriptForge Python module (scriptforge.py) might call the
28 functions below for compatibility reasons.
40 class _Singleton(type):
42 A Singleton design pattern
43 Credits: « Python in a Nutshell » by Alex Martelli, O'Reilly
47 def __call__(cls
, *args
, **kwargs
):
48 if cls
not in cls
.instances
:
49 cls
.instances
[cls
] = super(_Singleton
, cls
).__call
__(*args
, **kwargs
)
50 return cls
.instances
[cls
]
53 # #################################################################
55 # #################################################################
57 def _SF_Dictionary__ConvertToJson(propval
, indent
= None) -> str:
58 # used by Dictionary.ConvertToJson() Basic method
60 Given an array of PropertyValues as argument, convert it to a JSON string
62 # Array of property values => Dict(ionary) => JSON
65 pvDict
[pv
.Name
] = pv
.Value
66 return json
.dumps(pvDict
, indent
=indent
, skipkeys
=True)
69 def _SF_Dictionary__ImportFromJson(jsonstr
: str): # used by Dictionary.ImportFromJson() Basic method
71 Given a JSON string as argument, convert it to a list of tuples (name, value)
72 The value must not be a (sub)dict. This doesn't pass the python-basic bridge.
74 # JSON => Dictionary => Array of tuples/lists
75 dico
= json
.loads(jsonstr
)
77 for key
in iter(dico
):
80 if isinstance(value
, dict): # check that first level is not itself a (sub)dict
82 elif isinstance(value
, list): # check every member of the list is not a (sub)dict
83 for i
in range(len(value
)):
84 if isinstance(value
[i
], dict):
86 result
.append((key
, item
))
90 # #################################################################
92 # #################################################################
94 def _SF_Exception__PythonPrint(string
: str) -> bool:
95 # used by SF_Exception.PythonPrint() Basic method
97 Write the argument to stdout.
98 If the APSO shell console is active, the argument will be displayed in the console window
104 # #################################################################
106 # #################################################################
108 def _SF_FileSystem__CompareFiles(filename1
: str, filename2
: str, comparecontents
=True) -> bool:
109 # used by SF_FileSystem.CompareFiles() Basic method
111 Compare the 2 files, returning True if they seem equal, False otherwise.
112 By default, only their signatures (modification time, ...) are compared.
113 When comparecontents == True, their contents are compared.
116 return filecmp
.cmp(filename1
, filename2
, not comparecontents
)
121 def _SF_FileSystem__GetFilelen(systemfilepath
: str) -> str: # used by SF_FileSystem.GetFilelen() Basic method
122 return str(os
.path
.getsize(systemfilepath
))
125 def _SF_FileSystem__HashFile(filename
: str, algorithm
: str) -> str: # used by SF_FileSystem.HashFile() Basic method
127 Hash a given file with the given hashing algorithm
128 cfr. https://www.pythoncentral.io/hashing-files-with-python/
130 hash = _SF_FileSystem__HashFile('myfile.txt','MD5')
132 algo
= algorithm
.lower()
134 if algo
in hashlib
.algorithms_guaranteed
:
135 BLOCKSIZE
= 65535 # Provision for large size files
137 hasher
= hashlib
.md5()
139 hasher
= hashlib
.sha1()
140 elif algo
== 'sha224':
141 hasher
= hashlib
.sha224()
142 elif algo
== 'sha256':
143 hasher
= hashlib
.sha256()
144 elif algo
== 'sha384':
145 hasher
= hashlib
.sha384()
146 elif algo
== 'sha512':
147 hasher
= hashlib
.sha512()
150 with
open(filename
, 'rb') as file: # open in binary mode
151 buffer = file.read(BLOCKSIZE
)
152 while len(buffer) > 0:
153 hasher
.update(buffer)
154 buffer = file.read(BLOCKSIZE
)
155 return hasher
.hexdigest()
162 def _SF_FileSystem__Normalize(systemfilepath
: str) -> str:
163 # used by SF_FileSystem.Normalize() Basic method
165 Normalize a pathname by collapsing redundant separators and up-level references so that
166 A//B, A/B/, A/./B and A/foo/../B all become A/B.
167 On Windows, it converts forward slashes to backward slashes.
169 return os
.path
.normpath(systemfilepath
)
172 # #################################################################
174 # #################################################################
176 def _SF_Platform(propertyname
: str): # used by SF_Platform Basic module
178 Switch between SF_Platform properties (read the documentation about the ScriptForge.Platform service)
181 if propertyname
== 'Architecture':
182 return pf
.Architecture
183 elif propertyname
== 'ComputerName':
184 return pf
.ComputerName
185 elif propertyname
== 'CPUCount':
187 elif propertyname
== 'CurrentUser':
188 return pf
.CurrentUser
189 elif propertyname
== 'Machine':
191 elif propertyname
== 'OSName':
193 elif propertyname
== 'OSPlatform':
195 elif propertyname
== 'OSRelease':
197 elif propertyname
== 'OSVersion':
199 elif propertyname
== 'Processor':
201 elif propertyname
== 'PythonVersion':
202 return pf
.PythonVersion
207 class Platform(object, metaclass
= _Singleton
):
209 def Architecture(self
): return platform
.architecture()[0]
211 @property # computer's network name
212 def ComputerName(self
): return platform
.node()
214 @property # number of CPU's
215 def CPUCount(self
): return os
.cpu_count()
218 def CurrentUser(self
):
220 return getpass
.getuser()
224 @property # machine type e.g. 'i386'
225 def Machine(self
): return platform
.machine()
227 @property # system/OS name e.g. 'Darwin', 'Java', 'Linux', ...
228 def OSName(self
): return platform
.system().replace('Darwin', 'macOS')
230 @property # underlying platform e.g. 'Windows-10-...'
231 def OSPlatform(self
): return platform
.platform(aliased
= True)
233 @property # system's release e.g. '2.2.0'
234 def OSRelease(self
): return platform
.release()
236 @property # system's version
237 def OSVersion(self
): return platform
.version()
239 @property # real processor name e.g. 'amdk'
240 def Processor(self
): return platform
.processor()
242 @property # Python major.minor.patchlevel
243 def PythonVersion(self
): return 'Python ' + platform
.python_version()
246 # #################################################################
248 # #################################################################
250 def _SF_Session__OpenURLInBrowser(url
: str): # Used by SF_Session.OpenURLInBrowser() Basic method
252 Display url using the default browser
255 webbrowser
.open(url
, new
= 2)
260 # #################################################################
262 # #################################################################
264 def _SF_String__HashStr(string
: str, algorithm
: str) -> str: # used by SF_String.HashStr() Basic method
266 Hash a given UTF-8 string with the given hashing algorithm
268 hash = _SF_String__HashStr('This is a UTF-8 encoded string.','MD5')
270 algo
= algorithm
.lower()
272 if algo
in hashlib
.algorithms_guaranteed
:
274 bytestring
= string
.encode(ENCODING
) # Hashing functions expect bytes, not strings
276 hasher
= hashlib
.md5(bytestring
)
278 hasher
= hashlib
.sha1(bytestring
)
279 elif algo
== 'sha224':
280 hasher
= hashlib
.sha224(bytestring
)
281 elif algo
== 'sha256':
282 hasher
= hashlib
.sha256(bytestring
)
283 elif algo
== 'sha384':
284 hasher
= hashlib
.sha384(bytestring
)
285 elif algo
== 'sha512':
286 hasher
= hashlib
.sha512(bytestring
)
289 return hasher
.hexdigest()
296 # #################################################################
297 # lists the scripts, that shall be visible inside the Basic/Python IDE
298 # #################################################################
300 g_exportedScripts
= ()
302 if __name__
== "__main__":
303 print(_SF_Platform('Architecture'))
304 print(_SF_Platform('ComputerName'))
305 print(_SF_Platform('CPUCount'))
306 print(_SF_Platform('CurrentUser'))
307 print(_SF_Platform('Machine'))
308 print(_SF_Platform('OSName'))
309 print(_SF_Platform('OSPlatform'))
310 print(_SF_Platform('OSRelease'))
311 print(_SF_Platform('OSVersion'))
312 print(_SF_Platform('Processor'))
313 print(_SF_Platform('PythonVersion'))
315 print(hashlib
.algorithms_guaranteed
)
316 print(_SF_FileSystem__HashFile('/opt/libreoffice7.3/program/libbootstraplo.so', 'md5'))
317 print(_SF_FileSystem__HashFile('/opt/libreoffice7.3/share/Scripts/python/Capitalise.py', 'sha512'))
318 print(_SF_FileSystem__Normalize('A/foo/../B/C/./D//E'))
320 print(_SF_String__HashStr('œ∑¡™£¢∞§¶•ªº–≠œ∑´®†¥¨ˆøπ“‘åß∂ƒ©˙∆˚¬', 'MD5')) # 616eb9c513ad07cd02924b4d285b9987
322 # _SF_Session__OpenURLInBrowser('https://docs.python.org/3/library/webbrowser.html')
325 {"firstName": "John","lastName": "Smith","isAlive": true,"age": 27,
326 "address": {"streetAddress": "21 2nd Street","city": "New York","state": "NY","postalCode": "10021-3100"},
327 "phoneNumbers": [{"type": "home","number": "212 555-1234"},{"type": "office","number": "646 555-4567"}],
328 "children": ["Q", "M", "G", "T"],"spouse": null}
330 arr
= _SF_Dictionary__ImportFromJson(js
)