123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330 |
- # -*- coding: utf-8 -*-
- # Copyright 2019-2022 Jean-Pierre LEDURE, Rafael LIMA, Alain ROMEDENNE
- # ======================================================================================================================
- # === The ScriptForge library and its associated libraries are part of the LibreOffice project. ===
- # === Full documentation is available on https://help.libreoffice.org/ ===
- # ======================================================================================================================
- # ScriptForge is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- # ScriptForge is free software; you can redistribute it and/or modify it under the terms of either (at your option):
- # 1) The Mozilla Public License, v. 2.0. If a copy of the MPL was not
- # distributed with this file, you can obtain one at http://mozilla.org/MPL/2.0/ .
- # 2) The GNU Lesser General Public License as published by
- # the Free Software Foundation, either version 3 of the License, or
- # (at your option) any later version. If a copy of the LGPL was not
- # distributed with this file, see http://www.gnu.org/licenses/ .
- """
- Collection of Python helper functions called from the ScriptForge Basic libraries
- to execute specific services that are not or not easily available from Basic directly.
- When relevant, the methods present in the ScripForge Python module might call the
- functions below for compatibility reasons.
- """
- import getpass
- import os
- import platform
- import hashlib
- import filecmp
- import webbrowser
- import json
- class _Singleton(type):
- """
- A Singleton design pattern
- Credits: « Python in a Nutshell » by Alex Martelli, O'Reilly
- """
- instances = {}
- def __call__(cls, *args, **kwargs):
- if cls not in cls.instances:
- cls.instances[cls] = super(_Singleton, cls).__call__(*args, **kwargs)
- return cls.instances[cls]
- # #################################################################
- # Dictionary service
- # #################################################################
- def _SF_Dictionary__ConvertToJson(propval, indent = None) -> str:
- # used by Dictionary.ConvertToJson() Basic method
- """
- Given an array of PropertyValues as argument, convert it to a JSON string
- """
- # Array of property values => Dict(ionary) => JSON
- pvDict = {}
- for pv in propval:
- pvDict[pv.Name] = pv.Value
- return json.dumps(pvDict, indent=indent, skipkeys=True)
- def _SF_Dictionary__ImportFromJson(jsonstr: str): # used by Dictionary.ImportFromJson() Basic method
- """
- Given a JSON string as argument, convert it to a list of tuples (name, value)
- The value must not be a (sub)dict. This doesn't pass the python-basic bridge.
- """
- # JSON => Dictionary => Array of tuples/lists
- dico = json.loads(jsonstr)
- result = []
- for key in iter(dico):
- value = dico[key]
- item = value
- if isinstance(value, dict): # check that first level is not itself a (sub)dict
- item = None
- elif isinstance(value, list): # check every member of the list is not a (sub)dict
- for i in range(len(value)):
- if isinstance(value[i], dict): value[i] = None
- result.append((key, item))
- return result
- # #################################################################
- # Exception service
- # #################################################################
- def _SF_Exception__PythonPrint(string: str) -> bool:
- # used by SF_Exception.PythonPrint() Basic method
- """
- Write the argument to stdout.
- If the APSO shell console is active, the argument will be displayed in the console window
- """
- print(string)
- return True
- # #################################################################
- # FileSystem service
- # #################################################################
- def _SF_FileSystem__CompareFiles(filename1: str, filename2: str, comparecontents=True) -> bool:
- # used by SF_FileSystem.CompareFiles() Basic method
- """
- Compare the 2 files, returning True if they seem equal, False otherwise.
- By default, only their signatures (modification time, ...) are compared.
- When comparecontents == True, their contents are compared.
- """
- try:
- return filecmp.cmp(filename1, filename2, not comparecontents)
- except Exception:
- return False
- def _SF_FileSystem__GetFilelen(systemfilepath: str) -> str: # used by SF_FileSystem.GetFilelen() Basic method
- return str(os.path.getsize(systemfilepath))
- def _SF_FileSystem__HashFile(filename: str, algorithm: str) -> str: # used by SF_FileSystem.HashFile() Basic method
- """
- Hash a given file with the given hashing algorithm
- cfr. https://www.pythoncentral.io/hashing-files-with-python/
- Example
- hash = _SF_FileSystem__HashFile('myfile.txt','MD5')
- """
- algo = algorithm.lower()
- try:
- if algo in hashlib.algorithms_guaranteed:
- BLOCKSIZE = 65535 # Provision for large size files
- if algo == 'md5':
- hasher = hashlib.md5()
- elif algo == 'sha1':
- hasher = hashlib.sha1()
- elif algo == 'sha224':
- hasher = hashlib.sha224()
- elif algo == 'sha256':
- hasher = hashlib.sha256()
- elif algo == 'sha384':
- hasher = hashlib.sha384()
- elif algo == 'sha512':
- hasher = hashlib.sha512()
- else:
- return ''
- with open(filename, 'rb') as file: # open in binary mode
- buffer = file.read(BLOCKSIZE)
- while len(buffer) > 0:
- hasher.update(buffer)
- buffer = file.read(BLOCKSIZE)
- return hasher.hexdigest()
- else:
- return ''
- except Exception:
- return ''
- def _SF_FileSystem__Normalize(systemfilepath: str) -> str:
- # used by SF_FileSystem.Normalize() Basic method
- """
- Normalize a pathname by collapsing redundant separators and up-level references so that
- A//B, A/B/, A/./B and A/foo/../B all become A/B.
- On Windows, it converts forward slashes to backward slashes.
- """
- return os.path.normpath(systemfilepath)
- # #################################################################
- # Platform service
- # #################################################################
- def _SF_Platform(propertyname: str): # used by SF_Platform Basic module
- """
- Switch between SF_Platform properties (read the documentation about the ScriptForge.Platform service)
- """
- pf = Platform()
- if propertyname == 'Architecture':
- return pf.Architecture
- elif propertyname == 'ComputerName':
- return pf.ComputerName
- elif propertyname == 'CPUCount':
- return pf.CPUCount
- elif propertyname == 'CurrentUser':
- return pf.CurrentUser
- elif propertyname == 'Machine':
- return pf.Machine
- elif propertyname == 'OSName':
- return pf.OSName
- elif propertyname == 'OSPlatform':
- return pf.OSPlatform
- elif propertyname == 'OSRelease':
- return pf.OSRelease
- elif propertyname == 'OSVersion':
- return pf.OSVersion
- elif propertyname == 'Processor':
- return pf.Processor
- elif propertyname == 'PythonVersion':
- return pf.PythonVersion
- else:
- return None
- class Platform(object, metaclass = _Singleton):
- @property
- def Architecture(self): return platform.architecture()[0]
- @property # computer's network name
- def ComputerName(self): return platform.node()
- @property # number of CPU's
- def CPUCount(self): return os.cpu_count()
- @property
- def CurrentUser(self):
- try:
- return getpass.getuser()
- except Exception:
- return ''
- @property # machine type e.g. 'i386'
- def Machine(self): return platform.machine()
- @property # system/OS name e.g. 'Darwin', 'Java', 'Linux', ...
- def OSName(self): return platform.system().replace('Darwin', 'macOS')
- @property # underlying platform e.g. 'Windows-10-...'
- def OSPlatform(self): return platform.platform(aliased = True)
- @property # system's release e.g. '2.2.0'
- def OSRelease(self): return platform.release()
- @property # system's version
- def OSVersion(self): return platform.version()
- @property # real processor name e.g. 'amdk'
- def Processor(self): return platform.processor()
- @property # Python major.minor.patchlevel
- def PythonVersion(self): return 'Python ' + platform.python_version()
- # #################################################################
- # Session service
- # #################################################################
- def _SF_Session__OpenURLInBrowser(url: str): # Used by SF_Session.OpenURLInBrowser() Basic method
- """
- Display url using the default browser
- """
- try:
- webbrowser.open(url, new = 2)
- finally:
- return None
- # #################################################################
- # String service
- # #################################################################
- def _SF_String__HashStr(string: str, algorithm: str) -> str: # used by SF_String.HashStr() Basic method
- """
- Hash a given UTF-8 string with the given hashing algorithm
- Example
- hash = _SF_String__HashStr('This is a UTF-8 encoded string.','MD5')
- """
- algo = algorithm.lower()
- try:
- if algo in hashlib.algorithms_guaranteed:
- ENCODING = 'utf-8'
- bytestring = string.encode(ENCODING) # Hashing functions expect bytes, not strings
- if algo == 'md5':
- hasher = hashlib.md5(bytestring)
- elif algo == 'sha1':
- hasher = hashlib.sha1(bytestring)
- elif algo == 'sha224':
- hasher = hashlib.sha224(bytestring)
- elif algo == 'sha256':
- hasher = hashlib.sha256(bytestring)
- elif algo == 'sha384':
- hasher = hashlib.sha384(bytestring)
- elif algo == 'sha512':
- hasher = hashlib.sha512(bytestring)
- else:
- return ''
- return hasher.hexdigest()
- else:
- return ''
- except Exception:
- return ''
- # #################################################################
- # lists the scripts, that shall be visible inside the Basic/Python IDE
- # #################################################################
- g_exportedScripts = ()
- if __name__ == "__main__":
- print(_SF_Platform('Architecture'))
- print(_SF_Platform('ComputerName'))
- print(_SF_Platform('CPUCount'))
- print(_SF_Platform('CurrentUser'))
- print(_SF_Platform('Machine'))
- print(_SF_Platform('OSName'))
- print(_SF_Platform('OSPlatform'))
- print(_SF_Platform('OSRelease'))
- print(_SF_Platform('OSVersion'))
- print(_SF_Platform('Processor'))
- print(_SF_Platform('PythonVersion'))
- #
- print(hashlib.algorithms_guaranteed)
- print(_SF_FileSystem__HashFile('/opt/libreoffice7.3/program/libbootstraplo.so', 'md5'))
- print(_SF_FileSystem__HashFile('/opt/libreoffice7.3/share/Scripts/python/Capitalise.py', 'sha512'))
- print(_SF_FileSystem__Normalize('A/foo/../B/C/./D//E'))
- #
- print(_SF_String__HashStr('œ∑¡™£¢∞§¶•ªº–≠œ∑´®†¥¨ˆøπ“‘åß∂ƒ©˙∆˚¬', 'MD5')) # 616eb9c513ad07cd02924b4d285b9987
- #
- # _SF_Session__OpenURLInBrowser('https://docs.python.org/3/library/webbrowser.html')
- #
- js = """
- {"firstName": "John","lastName": "Smith","isAlive": true,"age": 27,
- "address": {"streetAddress": "21 2nd Street","city": "New York","state": "NY","postalCode": "10021-3100"},
- "phoneNumbers": [{"type": "home","number": "212 555-1234"},{"type": "office","number": "646 555-4567"}],
- "children": ["Q", "M", "G", "T"],"spouse": null}
- """
- arr = _SF_Dictionary__ImportFromJson(js)
- print(arr)
|