From 2268a77947e1e27f844a58104f3d15a3f671ea87 Mon Sep 17 00:00:00 2001 From: Wolfgang Fahl Date: Fri, 29 May 2020 16:36:41 +0200 Subject: [PATCH] adds initial steps for #1 --- tests/test_SMWApi.py | 66 +++++++++++++++++++++++++++++++++++++ tests/test_wikibot.py | 4 +++ wikibot/smw.py | 76 +++++++++++++++++++++++++++++++++++++++++++ wikibot/wikibot.py | 34 +++++++++++-------- 4 files changed, 167 insertions(+), 13 deletions(-) create mode 100644 tests/test_SMWApi.py create mode 100644 wikibot/smw.py diff --git a/tests/test_SMWApi.py b/tests/test_SMWApi.py new file mode 100644 index 0000000..bfba133 --- /dev/null +++ b/tests/test_SMWApi.py @@ -0,0 +1,66 @@ +''' +Created on 25.05.2020 + +@author: wf +''' +import unittest +import getpass +from wikibot.wikibot import WikiBot +from wikibot.smw import SMW + +class TestSMW(unittest.TestCase): + """ test access to SemanticMediaWiki API""" + debug=True + testask1="""{{#ask: [[Concept:Semantic MediaWiki Cons 2012]] + |?Has_Wikidata_item_ID = WikiDataId + |?Has planned finish = finish + |?Has planned start = start + |?Has_location = location + | format=table }}""" + + def testFixAsk(self): + smw=SMW() + fixedAsk=smw.fixAsk(TestSMW.testask1) + expected="""[[Concept:Semantic_MediaWiki_Cons_2012]]|?Has_Wikidata_item_ID=WikiDataId|?Has_planned_finish=finish|?Has_planned_start=start|?Has_location=location|format=table""" + if TestSMW.debug: + print(fixedAsk) + self.assertEqual(expected,fixedAsk) + + def testSMWInfo(self): + if not getpass.getuser()=="travis": + ''' + needs: + .mediawiki-japi/smw.ini as: + #Mediawiki JAPI credentials for semantic-mediawiki + #manually entered 2020-05-39 + url=https://www.semantic-mediawiki.org + scriptPath=/w + wikiId=smw + version=MediaWiki 1.31.7 + ''' + wikibot=WikiBot.ofWikiId("smw") + smw=SMW(wikibot.site) + result=smw.info() + if (TestSMW.debug): + print (result) + self.assertTrue('info' in result) + info=result['info'] + expectedlist=['propcount','usedpropcount','declaredpropcount'] + for expected in expectedlist: + self.assertTrue(expected in info) + + + def testSMWAskRaw(self): + if not getpass.getuser()=="travis": + wikibot=WikiBot.ofWikiId("smw") + smw=SMW(wikibot.site) + result=smw.rawquery(TestSMW.testask1) + if TestSMW.debug: + print (result) + self.assertTrue('query' in result) + query=result['query'] + self.assertTrue('printrequests' in query) + +if __name__ == "__main__": + #import sys;sys.argv = ['', 'Test.testSMWApi'] + unittest.main() \ No newline at end of file diff --git a/tests/test_wikibot.py b/tests/test_wikibot.py index 123e391..d7125e1 100644 --- a/tests/test_wikibot.py +++ b/tests/test_wikibot.py @@ -37,6 +37,10 @@ def testCrypt(self): self.assertEquals(secret,secret1) pw=c.decrypt(secret) self.assertEquals(expected,pw) + + def testWikiBotNoLogin(self): + wikibot=WikiBot.ofWikiId("smw") + def testWikiBot(self): ''' diff --git a/wikibot/smw.py b/wikibot/smw.py new file mode 100644 index 0000000..51a4eed --- /dev/null +++ b/wikibot/smw.py @@ -0,0 +1,76 @@ +''' +Created on 29.05.2020 + +@author: wf +''' +from pywikibot.data.api import Request +import re + +class SMW(object): + ''' + Semantic MediaWiki Access e.g. for ask API + see + * https://www.semantic-mediawiki.org/wiki/Help:API + * https://www.semantic-mediawiki.org/wiki/Serialization_(JSON) + + adapted from Java SimpleGraph Module + https://github.com/BITPlan/com.bitplan.simplegraph/blob/master/simplegraph-smw/src/main/java/com/bitplan/simplegraph/smw/SmwSystem.java + ''' + + def __init__(self, site=None): + ''' + Constructor + ''' + self.site=site + + def submit(self, parameters): + request=Request(site=self.site,parameters=parameters) + return request.submit() + + def info(self): + parameters={"action": "smwinfo"} + return self.submit(parameters) + + def rawquery(self,ask): + """ send a query """ + # allow usage of original Wiki ask content - strip all non needed parts + fixedAsk=self.fixAsk(ask) + # set parameters for request + parameters={"action": "ask","query":fixedAsk} + result=self.submit(parameters) + return result + + def query(self,ask): + return self.rawquery(ask) + + def fixAsk(self,ask): + """ fix an ask String to be usable for the API + @param ask + - a "normal" ask query + @return - the fixed asked query + """ + # ^\\s*\\{\\{ + # remove {{ with surrounding white space at beginning + fixedAsk = re.sub(r"^\s*\{\{", "",ask) + # remove #ask: + fixedAsk = re.sub(r"#ask:", "",fixedAsk) + # remove }} with surrounding white space at end + fixedAsk = re.sub(r"\}\}\s*$", "",fixedAsk) + # split by lines (with side effect to remove newlines) + parts = fixedAsk.split(r"\n") + fixedAsk = "" + for part in parts: + # remove whitespace around part + part = part.strip(); + # remove whitespace around pipe sign + part = re.sub(r"\s*\|\s*", "|",part); + # remove whitespace around assignment = + part = re.sub(r"\s*=\s*", "=",part); + # remove whitespace in query parts + part = re.sub(r"\]\s*\[", "][",part); + # replace blanks with _ + part = re.sub(" ", "_",part); + fixedAsk = fixedAsk+ part; + return fixedAsk + + \ No newline at end of file diff --git a/wikibot/wikibot.py b/wikibot/wikibot.py index 607de7d..83b076d 100644 --- a/wikibot/wikibot.py +++ b/wikibot/wikibot.py @@ -75,21 +75,26 @@ def __init__(self,iniFile): else: raise Exception("wikiId missing for %s" % iniFile) self.family=self.wikiId.replace("-","").replace("_","") - self.user=config['user'] self.url=config['url'].replace("\\:",":") if not self.url: raise Exception("url is missing for %s" % iniFile) - - self.email=config['email'] - self.salt=config['salt'] - self.cypher=config['cypher'] - self.secret=config['secret'] + self.scriptPath=config['scriptPath'] self.version=config['version'] o=urlparse(self.url) self.scheme=o.scheme self.netloc=o.netloc self.scriptPath=o.path+self.scriptPath + + # if a user is configured a login will be tried + if 'user' in config: + self.user=config['user'] + self.email=config['email'] + self.salt=config['salt'] + self.cypher=config['cypher'] + self.secret=config['secret'] + else: + self.user=None self.checkFamily() def getPassword(self): @@ -115,7 +120,7 @@ def scriptpath(self, code): return '%s' def isPublic(self): - return False + return %s def version(self, code): return "%s" # The MediaWiki version used. Very important in most cases. (contrary to documentation) @@ -124,17 +129,20 @@ def protocol(self, code): return '%s' ''' mw_version=self.version.lower().replace("mediawiki ","") - code=template % (self.family,self.netloc,self.scriptPath,mw_version,self.scheme) + ispublic='False' if self.user is not None else 'True' + code=template % (self.family,self.netloc,self.scriptPath,ispublic,mw_version,self.scheme) with open(famfile,"w") as py_file: py_file.write(code) config2.register_family_file(self.family, famfile) - config2.usernames[self.family]['en'] = self.user + if self.user: + config2.usernames[self.family]['en'] = self.user #config2.authenticate[self.netloc] = (self.user,self.getPassword()) self.site=pywikibot.Site('en',self.family) - # needs patch as outlined in https://phabricator.wikimedia.org/T248471 - #self.site.login(password=self.getPassword()) - lm = LoginManager(password=self.getPassword(), site=self.site, user=self.user) - lm.login() + if self.user: + # needs patch as outlined in https://phabricator.wikimedia.org/T248471 + #self.site.login(password=self.getPassword()) + lm = LoginManager(password=self.getPassword(), site=self.site, user=self.user) + lm.login() def getPage(self,pageTitle): ''' get the page with the given title'''