diff --git a/profiwiki/__init__.py b/profiwiki/__init__.py index bb9eb74..0a8da88 100644 --- a/profiwiki/__init__.py +++ b/profiwiki/__init__.py @@ -1 +1 @@ -__version__="0.1.6" \ No newline at end of file +__version__ = "0.1.6" diff --git a/profiwiki/docker.py b/profiwiki/docker.py index 71781ac..785def0 100644 --- a/profiwiki/docker.py +++ b/profiwiki/docker.py @@ -1,49 +1,52 @@ -''' +""" Created on 2023-04-01 @author: wf -''' +""" +import tempfile + from mwdocker.docker import DockerContainer from python_on_whales import DockerException -import tempfile -class ProfiWikiContainer(): + +class ProfiWikiContainer: """ a profiwiki docker container wrapper """ - def __init__(self,dc:DockerContainer): + + def __init__(self, dc: DockerContainer): """ Args: dc(DockerContainer): the to wrap """ - self.dc=dc - - def log_action(self,action:str): + self.dc = dc + + def log_action(self, action: str): """ log the given action - + Args: action(str): the d """ if self.dc: - print(f"{action} {self.dc.kind} {self.dc.name}",flush=True) + print(f"{action} {self.dc.kind} {self.dc.name}", flush=True) else: - print(f"{action}",flush=True) - - def upload(self,text:str,path:str): + print(f"{action}", flush=True) + + def upload(self, text: str, path: str): """ upload the given text to the given path """ with tempfile.NamedTemporaryFile() as tmp: self.log_action(f"uploading {tmp.name} as {path} to ") - with open(tmp.name,"w") as text_file: + with open(tmp.name, "w") as text_file: text_file.write(text) - self.dc.container.copy_to(tmp.name,path) - - def killremove(self,volumes:bool=False): + self.dc.container.copy_to(tmp.name, path) + + def killremove(self, volumes: bool = False): """ kill and remove me - + Args: volumes(bool): if True remove anonymous volumes associated with the container, default=True (to avoid e.g. passwords to get remembered / stuck """ @@ -55,42 +58,42 @@ def killremove(self,volumes:bool=False): def start_cron(self): """ Starting periodic command scheduler: cron. - """ - self.dc.container.execute(["/usr/sbin/service","cron","start"],tty=True) - + """ + self.dc.container.execute(["/usr/sbin/service", "cron", "start"], tty=True) + def install_plantuml(self): """ install plantuml to this container """ - script="""#!/bin/bash + script = """#!/bin/bash # install plantuml # WF 2023-05-01 apt-get update apt-get install -y plantuml """ # https://gabrieldemarmiesse.github.io/python-on-whales/docker_objects/containers/ - script_path="/root/install_plantuml.sh" + script_path = "/root/install_plantuml.sh" self.install_and_run_script(script, script_path) pass - - def install_and_run_script(self,script:str,script_path:str): + + def install_and_run_script(self, script: str, script_path: str): """ install and run the given script - + Args: script(str): the source code of the script script_path(str): the path to copy the script to and then execute """ - self.upload(script,script_path) + self.upload(script, script_path) # make executable - self.dc.container.execute(["chmod","+x",script_path]) - self.dc.container.execute([script_path],tty=True) - + self.dc.container.execute(["chmod", "+x", script_path]) + self.dc.container.execute([script_path], tty=True) + def install_fontawesome(self): """ install fontawesome to this container """ - script="""#!/bin/bash + script = """#!/bin/bash # install fontawesome # WF 2023-01-25 version=6.4.0 @@ -116,12 +119,12 @@ def install_fontawesome(self): EOS a2enconf font-awesome """ - script_path="/root/install_fontawesome" + script_path = "/root/install_fontawesome" self.install_and_run_script(script, script_path) try: - self.dc.container.execute(["service","apache2","restart"]) + self.dc.container.execute(["service", "apache2", "restart"]) except DockerException as e: # we expect a SIGTERM - if not e.return_code==143: + if not e.return_code == 143: raise e - pass \ No newline at end of file + pass diff --git a/profiwiki/patch.py b/profiwiki/patch.py index a1523fa..c14fd13 100644 --- a/profiwiki/patch.py +++ b/profiwiki/patch.py @@ -1,14 +1,16 @@ -''' +""" Created on 2023-04-09 @author: wf -''' +""" import re + class Patch: """ A class for patch a text file """ + def __init__(self, file_path: str): """ Initializes a Patch instance with the file path file to be patched. @@ -16,21 +18,21 @@ def __init__(self, file_path: str): Args: file_path (str): The file path of the PHP file to be patched. """ - self.lines=[] + self.lines = [] self.file_path = file_path # https://stackoverflow.com/a/3277516/1497139 - with open(self.file_path, 'r', encoding='UTF-8') as file: + with open(self.file_path, "r", encoding="UTF-8") as file: while line := file.readline(): self.lines.append(line.rstrip()) - + def save(self): """ save my lines """ - with open(self.file_path, 'w') as f: + with open(self.file_path, "w") as f: for line in self.lines: f.write(f"{line}\n") - + def patch_mediawiki_config_var(self, var_name: str, var_value: str) -> None: """ Patches a MediaWiki configuration variable in the PHP file with the given name and value. @@ -50,10 +52,10 @@ def patch_mediawiki_config_var(self, var_name: str, var_value: str) -> None: # Use fileinput to replace the matched line in the file for i, line in enumerate(self.lines): - new_line=(re.sub(pattern, replacement, line)) - self.lines[i]=new_line - - def add_text(self,text:str,avoid_duplication:bool=True): + new_line = re.sub(pattern, replacement, line) + self.lines[i] = new_line + + def add_text(self, text: str, avoid_duplication: bool = True): """ Adds text avoiding duplication if specified @@ -61,10 +63,10 @@ def add_text(self,text:str,avoid_duplication:bool=True): text (str): the text to add avoid_duplication(bool): if True avoid duplication of existing lines """ - new_lines=text.split("\n") + new_lines = text.split("\n") for new_line in new_lines: - do_add=True + do_add = True if avoid_duplication: - do_add=not new_line in self.lines + do_add = not new_line in self.lines if do_add: - self.lines.append(new_line) \ No newline at end of file + self.lines.append(new_line) diff --git a/profiwiki/profiwiki_cmd.py b/profiwiki/profiwiki_cmd.py index 8f84032..2514dac 100644 --- a/profiwiki/profiwiki_cmd.py +++ b/profiwiki/profiwiki_cmd.py @@ -1,59 +1,103 @@ -''' +""" Created on 2023-04-01 @author: wf -''' -from argparse import ArgumentParser #Namespace -from argparse import RawDescriptionHelpFormatter -from profiwiki.version import Version -from profiwiki.profiwiki_core import ProfiWiki -#from pathlib import Path +""" +# from pathlib import Path import sys import traceback import webbrowser +from argparse import ArgumentParser # Namespace +from argparse import RawDescriptionHelpFormatter + from mwdocker.config import MwClusterConfig -class ProfiWikiCmd(): +from profiwiki.profiwiki_core import ProfiWiki +from profiwiki.version import Version + + +class ProfiWikiCmd: """ ProfiWiki command line """ - - def get_arg_parser(self,config:MwClusterConfig, description: str, version_msg: str) -> ArgumentParser: + + def get_arg_parser( + self, config: MwClusterConfig, description: str, version_msg: str + ) -> ArgumentParser: """ Setup command line argument parser - + Args: config(MwClusterConfig): the mediawiki cluster configuration description(str): the description version_msg(str): the version message - + Returns: ArgumentParser: the argument parser """ - #script_path=Path(__file__) - parser = ArgumentParser(description=description, formatter_class=RawDescriptionHelpFormatter) + # script_path=Path(__file__) + parser = ArgumentParser( + description=description, formatter_class=RawDescriptionHelpFormatter + ) config.addArgs(parser) - parser.add_argument("--about", help="show about info [default: %(default)s]", action="store_true") - parser.add_argument("--apache",help="generate apache configuration",action="store_true") - parser.add_argument("--all",help="do all necessary steps for a full setup",action="store_true") - parser.add_argument("--bash",help="bash into container",action="store_true") - parser.add_argument("--create",action="store_true",help="create the wiki") - parser.add_argument("--check",action="store_true",help="check the wiki") - parser.add_argument("--update",action="store_true",help="start the update script -e.g. to fix SMW key") - parser.add_argument("--cron",action="store_true",help="start cron service") - parser.add_argument("--down", action="store_true", help="shutdown the wiki [default: %(default)s]") - parser.add_argument("--patch", action="store_true", help="apply LocalSettings.php patches [default: %(default)s]") - parser.add_argument("--list",action="store_true",help="list the available profi wikis [default: %(default)s]") - parser.add_argument("-fa", "--fontawesome", action="store_true", help="install fontawesome") - parser.add_argument("-wuc", "--wikiuser_check", action="store_true", help="check wikiuser") - parser.add_argument("-pu", "--plantuml", action="store_true", help="install plantuml") - parser.add_argument("-i", "--info", help="show system info", action="store_true") - parser.add_argument("-V", "--version", action='version', version=version_msg) + parser.add_argument( + "--about", + help="show about info [default: %(default)s]", + action="store_true", + ) + parser.add_argument( + "--apache", help="generate apache configuration", action="store_true" + ) + parser.add_argument( + "--all", help="do all necessary steps for a full setup", action="store_true" + ) + parser.add_argument("--bash", help="bash into container", action="store_true") + parser.add_argument("--create", action="store_true", help="create the wiki") + parser.add_argument("--check", action="store_true", help="check the wiki") + parser.add_argument( + "--update", + action="store_true", + help="start the update script -e.g. to fix SMW key", + ) + parser.add_argument("--cron", action="store_true", help="start cron service") + parser.add_argument( + "--down", + action="store_true", + help="shutdown the wiki [default: %(default)s]", + ) + parser.add_argument( + "--patch", + action="store_true", + help="apply LocalSettings.php patches [default: %(default)s]", + ) + parser.add_argument( + "--list", + action="store_true", + help="list the available profi wikis [default: %(default)s]", + ) + parser.add_argument( + "-fa", "--fontawesome", action="store_true", help="install fontawesome" + ) + parser.add_argument( + "-wuc", "--wikiuser_check", action="store_true", help="check wikiuser" + ) + parser.add_argument( + "-pu", "--plantuml", action="store_true", help="install plantuml" + ) + parser.add_argument( + "-i", "--info", help="show system info", action="store_true" + ) + parser.add_argument("-V", "--version", action="version", version=version_msg) # debug args - parser.add_argument('--debugServer', help="remote debug Server") - parser.add_argument('--debugPort', type=int, help="remote debug Port", default=5678) - parser.add_argument('--debugPathMapping', nargs='+', - help="remote debug Server path mapping - needs two arguments 1st: remotePath 2nd: local Path") + parser.add_argument("--debugServer", help="remote debug Server") + parser.add_argument( + "--debugPort", type=int, help="remote debug Port", default=5678 + ) + parser.add_argument( + "--debugPathMapping", + nargs="+", + help="remote debug Server path mapping - needs two arguments 1st: remotePath 2nd: local Path", + ) return parser def optional_debug(self, args): @@ -66,19 +110,33 @@ def optional_debug(self, args): if args.debugServer: import pydevd import pydevd_file_utils + print(args.debugPathMapping, flush=True) if args.debugPathMapping: if len(args.debugPathMapping) == 2: - remotePath = args.debugPathMapping[0] # path on the remote debugger side - localPath = args.debugPathMapping[1] # path on the local machine where the code runs - MY_PATHS_FROM_ECLIPSE_TO_PYTHON = [(remotePath, localPath), ] + remotePath = args.debugPathMapping[ + 0 + ] # path on the remote debugger side + localPath = args.debugPathMapping[ + 1 + ] # path on the local machine where the code runs + MY_PATHS_FROM_ECLIPSE_TO_PYTHON = [ + (remotePath, localPath), + ] pydevd_file_utils.setup_client_server_paths( - MY_PATHS_FROM_ECLIPSE_TO_PYTHON) # os.environ["PATHS_FROM_ECLIPSE_TO_PYTHON"]='[["%s", "%s"]]' % (remotePath,localPath) # print("trying to debug with PATHS_FROM_ECLIPSE_TO_PYTHON=%s" % os.environ["PATHS_FROM_ECLIPSE_TO_PYTHON"]); + MY_PATHS_FROM_ECLIPSE_TO_PYTHON + ) # os.environ["PATHS_FROM_ECLIPSE_TO_PYTHON"]='[["%s", "%s"]]' % (remotePath,localPath) # print("trying to debug with PATHS_FROM_ECLIPSE_TO_PYTHON=%s" % os.environ["PATHS_FROM_ECLIPSE_TO_PYTHON"]); - pydevd.settrace(args.debugServer, port=args.debugPort, stdoutToServer=True, stderrToServer=True) + pydevd.settrace( + args.debugServer, + port=args.debugPort, + stdoutToServer=True, + stderrToServer=True, + ) print("command line args are: %s" % str(sys.argv)) pass - + + def main(argv=None): # IGNORE:C0111 """main program.""" @@ -88,16 +146,17 @@ def main(argv=None): # IGNORE:C0111 program_name = "profiwiki" program_version = f"v{Version.version}" program_build_date = str(Version.date) - program_version_message = f'{program_name} ({program_version},{program_build_date})' + program_version_message = f"{program_name} ({program_version},{program_build_date})" args = None try: - pw=ProfiWiki() + pw = ProfiWiki() pw_cmd = ProfiWikiCmd() parser = pw_cmd.get_arg_parser( config=pw.config, - description=Version.license, - version_msg=program_version_message) + description=Version.license, + version_msg=program_version_message, + ) args = parser.parse_args(argv) if len(argv) < 1: parser.print_usage() @@ -108,7 +167,7 @@ def main(argv=None): # IGNORE:C0111 webbrowser.open(Version.doc_url) pw_cmd.optional_debug(args) if args.info: - info=pw.system_info() + info = pw.system_info() print(info) pw.work(args) @@ -129,8 +188,9 @@ def main(argv=None): # IGNORE:C0111 print(traceback.format_exc()) return 2 + DEBUG = 1 if __name__ == "__main__": if DEBUG: sys.argv.append("-d") - sys.exit(main()) \ No newline at end of file + sys.exit(main()) diff --git a/profiwiki/profiwiki_core.py b/profiwiki/profiwiki_core.py index 370210e..aee1b69 100644 --- a/profiwiki/profiwiki_core.py +++ b/profiwiki/profiwiki_core.py @@ -1,91 +1,121 @@ -''' +""" Created on 2023-04-01 @author: wf -''' +""" import datetime import json -import tempfile -import platform import os -from mwdocker.mwcluster import MediaWikiCluster +import platform +import tempfile + +from mwdocker.config import MwClusterConfig from mwdocker.docker import DockerApplication +from mwdocker.mwcluster import MediaWikiCluster +from wikibot3rd.wikiuser import WikiUser + from profiwiki.docker import ProfiWikiContainer -from mwdocker.config import MwClusterConfig from profiwiki.patch import Patch -from wikibot3rd.wikiuser import WikiUser -class ProfiWiki(): + +class ProfiWiki: """ ProfiWiki """ - - def __init__(self,prefix:str="pw",smw_version="4.1.1",mw_version="1.39.3",port:int=9079): + + def __init__( + self, + prefix: str = "pw", + smw_version="4.1.3", + mw_version="1.39.7", + port: int = 9079, + ): """ constructor - """ - self.os_name=platform.system() - self.os_uname=os.uname() - self.os_release=platform.release() - self.args=None - self.config=MwClusterConfig() - self.config.smw_version=smw_version - self.config.random_password=True - self.config.prefix=prefix - self.config.base_port=port - self.config.sql_port=port-1 - self.config.port=port - self.config.versions=[mw_version] - self.config.container_base_name="pw" - self.config.extensionNameList=["Admin Links","Diagrams","Graph","Header Tabs","ImageMap","ImageLink","MagicNoCache","Maps9", - "Mermaid","MsUpload","Nuke","Page Forms","ParserFunctions","PDFEmbed","Renameuser", - "Replace Text","Semantic Result Formats","SyntaxHighlight","Variables","UserFunctions"] - self.config.logo="https://wiki.bitplan.com/images/wiki/thumb/6/63/Profiwikiicon.png/96px-Profiwikiicon.png" + """ + self.os_name = platform.system() + self.os_uname = os.uname() + self.os_release = platform.release() + self.args = None + self.config = MwClusterConfig() + self.config.smw_version = smw_version + self.config.random_password = True + self.config.prefix = prefix + self.config.base_port = port + self.config.sql_port = port - 1 + self.config.port = port + self.config.versions = [mw_version] + self.config.container_base_name = "pw" + self.config.extensionNameList = [ + "Admin Links", + "Diagrams", + "Graph", + "Header Tabs", + "ImageMap", + "ImageLink", + "MagicNoCache", + "Maps9", + "Mermaid", + "MsUpload", + "Nuke", + "Page Forms", + "ParserFunctions", + "PDFEmbed", + "Renameuser", + "Replace Text", + "Semantic Result Formats", + "SyntaxHighlight", + "Variables", + "UserFunctions", + ] + self.config.logo = "https://wiki.bitplan.com/images/wiki/thumb/6/63/Profiwikiicon.png/96px-Profiwikiicon.png" self.config.__post_init__() - self.mwCluster=None + self.mwCluster = None pass - - def system_info(self)->str: + + def system_info(self) -> str: """ collect system information """ - info=f"""os: {self.os_name}""" + info = f"""os: {self.os_name}""" if "Darwin" in info: - release,_version,_machine=platform.mac_ver() - info+=f" MacOS {release}" + release, _version, _machine = platform.mac_ver() + info += f" MacOS {release}" else: - info+=f"{self.os_release}" + info += f"{self.os_release}" return info - - def work(self,args): + + def work(self, args): """ work as instructed by the arguments - + Args: args(Namespace): the command line arguments """ self.config.fromArgs(args) # make sure the wikiId is set from the container base name - config_path=self.config.get_config_path() + config_path = self.config.get_config_path() if os.path.isfile(config_path) and not self.config.forceRebuild: # reload the previous configuration e.g. based on container_name only - previous_config=self.config.load(config_path) + previous_config = self.config.load(config_path) if self.config.verbose: print(f"ProfiWiki with previous configuration from {config_path}...") - self.config=previous_config - self.config.wikiId=self.config.container_base_name + self.config = previous_config + self.config.wikiId = self.config.container_base_name if args.bash: - cmd=f"docker exec -it {self.config.container_base_name}-mw /bin/bash" + cmd = f"docker exec -it {self.config.container_base_name}-mw /bin/bash" print(cmd) return - mwApp=self.getMwApp(withGenerate=args.forceRebuild) + mwApp = self.getMwApp(withGenerate=args.forceRebuild) if self.config.verbose: - print(f"ProfiWiki {mwApp.config.container_base_name} using port {mwApp.config.port} sqlport {mwApp.config.sql_port}") + print( + f"ProfiWiki {mwApp.config.container_base_name} using port {mwApp.config.port} sqlport {mwApp.config.sql_port}" + ) if args.force_user: mwApp.createWikiUser(store=True) if args.all: self.create(mwApp, args.forceRebuild) - pmw,_pdb=self.getProfiWikiContainers(mwApp) + pmw, _pdb = self.getProfiWikiContainers(mwApp) pmw.install_fontawesome() pmw.install_plantuml() self.patch(pmw) @@ -94,18 +124,18 @@ def work(self,args): if args.wikiuser_check: self.check_wikiuser(mwApp) if args.apache: - apache_config=self.apache_config(mwApp) + apache_config = self.apache_config(mwApp) print(apache_config) if args.create: self.create(mwApp, args.forceRebuild) if args.check: self.check(mwApp) if args.down: - self.down(mwApp,args.forceRebuild) + self.down(mwApp, args.forceRebuild) if args.list: self.list(mwApp) if args.plantuml or args.fontawesome or args.cron or args.patch: - pmw,_pdb=self.getProfiWikiContainers(mwApp) + pmw, _pdb = self.getProfiWikiContainers(mwApp) if args.plantuml: pmw.install_plantuml() if args.fontawesome: @@ -116,61 +146,63 @@ def work(self,args): self.patch(pmw) if args.update: self.update(mwApp) - - def getMwCluster(self,withGenerate:bool=True)->MediaWikiCluster: + + def getMwCluster(self, withGenerate: bool = True) -> MediaWikiCluster: """ get a mediawiki Cluster for my configuration - + Args: withGenerate(bool): if True regenerate the configuration files - + Returns: MediaWikiCluster: the MediaWiki Cluser """ if self.mwCluster is not None: return self.mwCluster - mwCluster=MediaWikiCluster(config=self.config) + mwCluster = MediaWikiCluster(config=self.config) # generate mwCluster.createApps(withGenerate=withGenerate) - self.mwCluster=mwCluster + self.mwCluster = mwCluster return mwCluster - - def getMwApp(self,withGenerate:bool=True): + + def getMwApp(self, withGenerate: bool = True): """ - get my mediawiki Docker application - """ - mwCluster=self.getMwCluster(withGenerate) - mwApp=mwCluster.apps[self.config.version] + get my mediawiki Docker application + """ + mwCluster = self.getMwCluster(withGenerate) + mwApp = mwCluster.apps[self.config.version] return mwApp - - def getProfiWikiContainers(self,mwApp:DockerApplication): + + def getProfiWikiContainers(self, mwApp: DockerApplication): """ get the two containers - for mediawiki and the database - + Args: mwApp(DockerApplication): the MediaWiki Docker Application - + Returns: Tuple(ProfiWikiContainer,ProfiWikiContainer): MediaWiki, Database """ - mw,db=mwApp.getContainers() - pmw=ProfiWikiContainer(mw) - pdb=ProfiWikiContainer(db) - return pmw,pdb - - def patch(self,pwc:ProfiWikiContainer): + mw, db = mwApp.getContainers() + pmw = ProfiWikiContainer(mw) + pdb = ProfiWikiContainer(db) + return pmw, pdb + + def patch(self, pwc: ProfiWikiContainer): """ apply profi wiki patches to the given ProfiWikiContainer """ if not pwc.dc: - raise("no container to apply patch") - ls_path="/var/www/html/LocalSettings.php" - timestamp=datetime.datetime.utcnow().strftime('%Y-%m-%d') - with tempfile.NamedTemporaryFile(mode='w', prefix='LocalSettings_', suffix='.php') as ls_file: + raise ("no container to apply patch") + ls_path = "/var/www/html/LocalSettings.php" + timestamp = datetime.datetime.utcnow().strftime("%Y-%m-%d") + with tempfile.NamedTemporaryFile( + mode="w", prefix="LocalSettings_", suffix=".php" + ) as ls_file: pwc.log_action(f"patching {ls_file.name}") - pwc.dc.container.copy_from(ls_path,ls_file.name) - patch=Patch(file_path=ls_file.name) - lines=f"""// modified by profiwiki + pwc.dc.container.copy_from(ls_path, ls_file.name) + patch = Patch(file_path=ls_file.name) + lines = f"""// modified by profiwiki // use WikiEditor e.g. for MsUpload wfLoadExtension( 'WikiEditor' ); # make this an intranet - comment out if you want this to be a public wiki @@ -246,66 +278,67 @@ def patch(self,pwc:ProfiWikiContainer): """ patch.add_text(lines) patch.save() - pwc.dc.container.copy_to(ls_file.name,ls_path) + pwc.dc.container.copy_to(ls_file.name, ls_path) - def update(self,mwApp): + def update(self, mwApp): """ run the update script """ mwApp.execute("/root/update.sh") - - def check(self,mwApp): + + def check(self, mwApp): """ check """ mwApp.check() - - def create(self,mwApp,forceRebuild:bool=False): + + def create(self, mwApp, forceRebuild: bool = False): """ create a profiwiki mediawiki """ mwApp.start(forceRebuild=forceRebuild) - - def down(self,mwApp,forceRebuild:bool=False): + + def down(self, mwApp, forceRebuild: bool = False): """ shut down the profiwiki base mediawiki """ mwApp.down(forceRebuild=forceRebuild) - - def list(self,mwApp): + + def list(self, mwApp): """ list the profi wikis """ - print (json.dumps(mwApp.config.as_dict(),indent=2)) + print(json.dumps(mwApp.config.as_dict(), indent=2)) pass - - def check_wikiuser(self,mwApp:DockerApplication): - """ - """ + + def check_wikiuser(self, mwApp: DockerApplication): + """ """ print(f"Checking WikiUser ... for {mwApp.config.container_base_name}") - wikiUsers=WikiUser.getWikiUsers(lenient=True) + wikiUsers = WikiUser.getWikiUsers(lenient=True) if not mwApp.config.wikiId: print("no WikiId configured") return if not mwApp.config.wikiId in wikiUsers: print(f"no wikiUser for wikiId {mwApp.config.wikiId} found") return - wikiUser=wikiUsers[mwApp.config.wikiId] + wikiUser = wikiUsers[mwApp.config.wikiId] if mwApp.config.password != wikiUser.getPassword(): print(f"configured password is different then {mwApp.config.wikiId}") else: - print(f"wikiUser for wikiId {mwApp.config.wikiId} is available and password as configured") + print( + f"wikiUser for wikiId {mwApp.config.wikiId} is available and password as configured" + ) pass - - def apache_config(self,mwApp:DockerApplication)->str: + + def apache_config(self, mwApp: DockerApplication) -> str: """ get the apache configuration for the given mediawiki Docker application - + Args: mwApp(DockerApplication): the docker application to generate the configuration for """ - config=mwApp.config - apache_config=f""" + config = mwApp.config + apache_config = f""" # The ServerName directive sets the request scheme, hostname and port that # the server uses to identify itself. This is used when creating # redirection URLs. In the context of virtual hosts, the ServerName @@ -339,5 +372,3 @@ def apache_config(self,mwApp:DockerApplication)->str: ProxyPassReverse / http://localhost:{config.port}/ """ return apache_config - - \ No newline at end of file diff --git a/profiwiki/version.py b/profiwiki/version.py index 1c24718..2d096c1 100644 --- a/profiwiki/version.py +++ b/profiwiki/version.py @@ -1,30 +1,30 @@ -''' +""" Created on 2023-04-01 @author: wf -''' +""" import profiwiki + class Version(object): - ''' + """ Version handling for ProfiWiki - ''' - name="pyProfiWiki" - description="""BITPlan's professional Semantic Mediawiki""" - version=profiwiki.__version__ - date = '2023-04-01' - updated = '2023-04-08' - authors='Wolfgang Fahl' - doc_url="https://wiki.bitplan.com/index.php/ProfiWiki" - chat_url="https://github.com/BITPlan/ProfiWiki/discussions" - cm_url="https://github.com/BITPlan/ProfiWiki" - license=f'''Copyright 2015-2023 contributors. All rights reserved. + """ + + name = "pyProfiWiki" + description = """BITPlan's professional Semantic Mediawiki""" + version = profiwiki.__version__ + date = "2023-04-01" + updated = "2023-04-08" + authors = "Wolfgang Fahl" + doc_url = "https://wiki.bitplan.com/index.php/ProfiWiki" + chat_url = "https://github.com/BITPlan/ProfiWiki/discussions" + cm_url = "https://github.com/BITPlan/ProfiWiki" + license = f"""Copyright 2015-2023 contributors. All rights reserved. Licensed under the Apache License 2.0 http://www.apache.org/licenses/LICENSE-2.0 Distributed on an "AS IS" basis without warranties - or conditions of any kind, either express or implied.''' - longDescription=f"""{name} version {version} + or conditions of any kind, either express or implied.""" + longDescription = f"""{name} version {version} {description} Created by {authors} on {date} last updated {updated}""" - - \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 2d08a8b..7f39682 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,20 +15,20 @@ readme = "README.md" license= "Apache-2.0" dependencies = [ #https://pypi.org/project/pymediawikidocker/ - "pymediawikidocker>=0.10.7", + "pymediawikidocker>=0.12.0", #https://pypi.org/project/py-3rdparty-mediawiki/ "py-3rdparty-mediawiki" ] -requires-python = ">=3.8" +requires-python = ">=3.9" classifiers=[ "Development Status :: 4 - Beta", "Environment :: Web Environment", "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", "Operating System :: OS Independent", "Topic :: Software Development :: Libraries :: Python Modules", "Intended Audience :: Developers", diff --git a/scripts/blackisort b/scripts/blackisort new file mode 100755 index 0000000..7aaf827 --- /dev/null +++ b/scripts/blackisort @@ -0,0 +1,7 @@ +#!/bin/bash +# WF 2024-01-10 +package=profiwiki +isort tests/*.py +black tests/*.py +isort $package/*.py +black $package/*.py diff --git a/tests/basetest.py b/tests/basetest.py index 6192e36..8fca7e7 100644 --- a/tests/basetest.py +++ b/tests/basetest.py @@ -1,60 +1,63 @@ -''' +""" Created on 2021-08-19 @author: wf -''' -from unittest import TestCase -import time +""" import getpass +import time +from unittest import TestCase + class Basetest(TestCase): - ''' + """ base test case - ''' - - def setUp(self,debug=False,profile=True): - ''' + """ + + def setUp(self, debug=False, profile=True): + """ setUp test environment - ''' + """ TestCase.setUp(self) - self.debug=debug - self.profile=profile - msg=f"test {self._testMethodName}, debug={self.debug}" - self.profiler=Profiler(msg,profile=self.profile) - + self.debug = debug + self.profile = profile + msg = f"test {self._testMethodName}, debug={self.debug}" + self.profiler = Profiler(msg, profile=self.profile) + def tearDown(self): TestCase.tearDown(self) - self.profiler.time() - + self.profiler.time() + def inPublicCI(self): - ''' + """ are we running in a public Continuous Integration Environment? - ''' - return getpass.getuser() in [ "travis", "runner" ]; + """ + return getpass.getuser() in ["travis", "runner"] + class Profiler: - ''' + """ simple profiler - ''' - def __init__(self,msg,profile=True): - ''' + """ + + def __init__(self, msg, profile=True): + """ construct me with the given msg and profile active flag - + Args: msg(str): the message to show if profiling is active profile(bool): True if messages should be shown - ''' - self.msg=msg - self.profile=profile - self.starttime=time.time() + """ + self.msg = msg + self.profile = profile + self.starttime = time.time() if profile: print(f"Starting {msg} ...") - - def time(self,extraMsg=""): - ''' + + def time(self, extraMsg=""): + """ time the action and print if profile is active - ''' - elapsed=time.time()-self.starttime + """ + elapsed = time.time() - self.starttime if self.profile: print(f"{self.msg}{extraMsg} took {elapsed:5.1f} s") - return elapsed \ No newline at end of file + return elapsed diff --git a/tests/test_patch.py b/tests/test_patch.py index ca9b7cb..5dac433 100644 --- a/tests/test_patch.py +++ b/tests/test_patch.py @@ -1,27 +1,29 @@ -''' +""" Created on 2023-04-09 @author: wf -''' -from tests.basetest import Basetest -from profiwiki.patch import Patch +""" import tempfile +from profiwiki.patch import Patch +from tests.basetest import Basetest + + class TestPatch(Basetest): """ test Patching """ - + def setUp(self, debug=False, profile=True): Basetest.setUp(self, debug=debug, profile=profile) - + def getTestfile(self): - tmp=tempfile.NamedTemporaryFile(prefix="test",suffix=".php") + tmp = tempfile.NamedTemporaryFile(prefix="test", suffix=".php") return tmp.name - + def getPatch(self): # Create a temporary directory and a test PHP file with example variables - test_file_path=self.getTestfile() + test_file_path = self.getTestfile() with open(test_file_path, "w") as f: f.write("