From cd52438691264ad46de98e31673ff553ea69f96f Mon Sep 17 00:00:00 2001 From: Wolfgang Fahl Date: Fri, 29 Dec 2023 18:46:22 +0100 Subject: [PATCH] fixes #28 and #29 --- ceurspt/__init__.py | 2 +- ceurspt/ceurws.py | 55 +++++++++++++++++++++++- ceurspt/version.py | 2 +- ceurspt/webserver.py | 48 +++++++++++++++++++++ pyproject.toml | 2 + static/icons/32px-Wikibase_logo.svg.png | Bin 0 -> 1532 bytes static/icons/32px-YAML_Logo.svg.png | Bin 0 -> 670 bytes 7 files changed, 105 insertions(+), 4 deletions(-) create mode 100644 static/icons/32px-Wikibase_logo.svg.png create mode 100644 static/icons/32px-YAML_Logo.svg.png diff --git a/ceurspt/__init__.py b/ceurspt/__init__.py index 77842ed..10ce742 100644 --- a/ceurspt/__init__.py +++ b/ceurspt/__init__.py @@ -1 +1 @@ -__version__="0.0.6" \ No newline at end of file +__version__="0.0.7" \ No newline at end of file diff --git a/ceurspt/ceurws.py b/ceurspt/ceurws.py index ce4ffa3..30c1b4f 100644 --- a/ceurspt/ceurws.py +++ b/ceurspt/ceurws.py @@ -5,7 +5,7 @@ ''' import ceurspt.ceurws_base import ceurspt.models.dblp - +import json from bs4 import BeautifulSoup from ceurspt.profiler import Profiler from ceurspt.version import Version @@ -165,7 +165,40 @@ def as_wb_dict(self)->dict: "P1545": f"{index+1}" }}) return wb - + + def as_wbi_cli_text(self, qid: str) -> str: + """ + Generates a series of Wikibase CLI command strings to add claims to the entity + represented by this paper, based on the provided QID. + + Args: + qid (str): The QID of the Wikibase item to which the claims will be added. + + Returns: + str: A string containing all the 'wb add-claim' commands separated by newlines. + """ + # Get the dictionary representation of the paper + wb_dict = self.as_wb_dict() + + # Initialize an empty list to hold all commands + cli_commands = [] + + # Iterate through each claim to create a separate wb add-claim command + for prop, value in wb_dict['claims'].items(): + # Handle different structures in claims (e.g., simple vs. complex with qualifiers) + if isinstance(value, list): # Expecting a list of values (or complex value structures) + for val in value: + # Convert value to a JSON string and escape quotes for command line + val_json = json.dumps(val).replace('"', '\\"') + cli_commands.append(f'wb add-claim {qid} {prop} "{val_json}"') + else: # A single value or simple structure + # Convert value to a JSON string and escape quotes for command line + value_json = json.dumps(value).replace('"', '\\"') + cli_commands.append(f'wb add-claim {qid} {prop} "{value_json}"') + + # Combine all commands into a single string separated by newlines + cli = "\n".join(cli_commands) + return cli def as_quickstatements(self)->str: """ @@ -438,11 +471,23 @@ def getIconBar(self,soup): "link":f"/{pdf_name}.wbjson", "valid":True }, + { + "src": "/static/icons/32px-Wikibase_logo.svg.png", + "title": "wikibase CLI", + "link":f"/{pdf_name}.wbcli", + "valid":True + }, { "src": "/static/icons/32px-JSON_vector_logo.svg.png", "title": "JSON metadata", "link":f"/{pdf_name}.json", "valid":True + }, + { + "src": "/static/icons/32px-YAML_Logo.svg.png", + "title": "YAML metadata", + "link":f"/{pdf_name}.yaml", + "valid":True } ] icon_tag=Volume.create_icon_bar(soup, icon_list=icon_list) @@ -734,6 +779,12 @@ def getIconBar(self,soup): "link":f"/Vol-{self.number}.json", "valid":True }, + { + "src": "/static/icons/32px-YAML_Logo.svg.png", + "title": "YML metadata", + "link":f"/Vol-{self.number}.yaml", + "valid":True + } ] icon_tag=Volume.create_icon_bar(soup, icon_list=icon_list) diff --git a/ceurspt/version.py b/ceurspt/version.py index 52091ff..2d9dc53 100644 --- a/ceurspt/version.py +++ b/ceurspt/version.py @@ -13,7 +13,7 @@ class Version(object): name = "" version = ceurspt.__version__ date = '2023-03-17' - updated = '2023-07-12' + updated = '2023-12-29' description = 'CEUR-WS Single Point of Truth RestFUL server', authors = 'Tim Holzheim, Wolfgang Fahl' diff --git a/ceurspt/webserver.py b/ceurspt/webserver.py index 1590847..89bdbec 100644 --- a/ceurspt/webserver.py +++ b/ceurspt/webserver.py @@ -4,6 +4,7 @@ @author: wf """ from typing import Optional +import yaml from fastapi import FastAPI, HTTPException from fastapi.responses import FileResponse, HTMLResponse, PlainTextResponse, Response, RedirectResponse @@ -69,6 +70,15 @@ async def paperWikibaseCliJson(number: int, pdf_name: str): paper_dict = paper.as_wb_dict() return paper_dict + @self.app.get("/Vol-{number:int}/{pdf_name}/{qid}.wbcli") + async def paperWikibaseCli(number: int, pdf_name,qid: str): + """ + get the json response to the wikibase-cli for the given paper + """ + paper = self.getPaper(number, pdf_name) + paper_cli_text = paper.as_wbi_cli_text(qid) + return PlainTextResponse(paper_cli_text) + @self.app.get("/Vol-{number:int}/{pdf_name}.html") async def paperHtml(number: int, pdf_name: str): """ @@ -237,6 +247,44 @@ async def volume_paper_citation(number: int, pdf_name: str): return PlainTextResponse(content=citation) else: return {"error": f"unknown volume number {number} or paper {pdf_name}"} + + @self.app.get("/Vol-{number:int}/{pdf_name}.yaml") + async def paperYaml(number: int, pdf_name: str): + paper = self.getPaper(number, pdf_name) + paper_dict = paper.getMergedDict() + yaml_content = yaml.dump(paper_dict) + return Response(content=yaml_content, media_type="application/x-yaml") + + @self.app.get("/Vol-{number:int}.yaml") + async def volumeYaml(number: int): + vol = self.getVolume(number) + if vol: + volume_dict = vol.getMergedDict() + else: + volume_dict = {"error": f"unknown volume number {number}"} + yaml_content = yaml.dump(volume_dict) + return Response(content=yaml_content, media_type="application/x-yaml") + + @self.app.get("/volume/{number:int}/paper.yaml", tags=["yaml"]) + async def volume_papers_yaml(number: int): + vol = self.getVolume(number) + if vol: + paper_records = [paper.getMergedDict() for paper in vol.papers] + else: + paper_records = {"error": f"unknown volume number {number}"} + yaml_content = yaml.dump(paper_records) + return Response(content=yaml_content, media_type="application/x-yaml") + + @self.app.get("/volume/{number:int}/paper/{pdf_name:str}.yaml", tags=["yaml"]) + async def volume_paper_yaml(number: int, pdf_name: str): + paper = self.getPaper(number, pdf_name) + if paper: + paper_dict = paper.getMergedDict() + else: + paper_dict = {"error": f"unknown volume number {number} or paper {pdf_name}"} + yaml_content = yaml.dump(paper_dict) + return Response(content=yaml_content, media_type="application/x-yaml") + def volumeHtml(self, number: int, ext: str = ".pdf") -> HTMLResponse: """ diff --git a/pyproject.toml b/pyproject.toml index d356588..a1e7945 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,6 +27,8 @@ dependencies = [ # https://github.com/tqdm/tqdm # optional? "tqdm", + # https://pypi.org/project/PyYAML/ + "PyYAML", # https://github.com/ijl/orjson "orjson>=3.8.9", "bibtexparser", diff --git a/static/icons/32px-Wikibase_logo.svg.png b/static/icons/32px-Wikibase_logo.svg.png new file mode 100644 index 0000000000000000000000000000000000000000..55cd502fec7d94106b0578d010c4dd1b75924329 GIT binary patch literal 1532 zcmV004R>004l5008;`004mK004C`008P>0026e000+ooVrmw00006 zVoOIv0RI600RN!9r;`8x1rtd`K~zY`#g%(Zm30`$Kfm`q=e!&^96=G#xE>)9&<2v0 z;U!G_!|W<+Dk`lK6`Fo_@@$4lXi=Rt1RtrGu$sG0;E-WA89eXs{kn8>H2Q~ z3fGK7^uxHof$CIwZPM$_9JqhsGKr_>?=^jpj0FxMFX|=cLWJmBA+PX zDKtG55$$pS^q+#1y`2*y=dGA^?#lyj(cPT@(!$v6RN`GeT*)8N*w9I!_X3H@A9i(g zgej{fAtY)@tH6=IUUOYr{=&J$Wn4qUSH~_HU_@nCye3kqG*uNbZo>HUE5BaCovC@m z#S2IfnqEMH3pzapLH0Q)<@Gis=jNa}yF;zA2 z3KbixFKq}*OLdwep2O1j5(}p`Q&2n`C9{BZEcz~nrCf{E_8^OIK1}WtHo_gQ;KA3t z5j%NGi)OXP3W)Oi*VP>^-%4M|04&CGS}v@_ceeX)e_y|-$3kwdN%5}lks$w%NM1ky zO*agG()C$}Zm}D+KvYch1zpoZT%j7ZWu+uVhT#vGG+p#;xqeXS7E{_WMM#WuKD6hg zjov_j#E1b@H=bkKs6^^p+lg`pGdMJuL#JE$X5PBUU)IpQb`{7eux`WbyG;wSy^uU( z=4#zAo&xoah|2SR@OJr~8A*2c_;gBk9wH_@ln95N)=nR7o^FOmhXe55mnX^1N~XH; z9HZl-*n02;V_ie2Z*6C4T0F0PRzt&u4$gh=kL+Ka`K#j*79b=*U>=)`UUg_{yJi^K zO5}ZzVZP4xR~p(nZP&#PrsDV+?#@i6rs+HYw~UD6Xmfw86igZ(L(@eMJDsLdK#FD&_aFndM3=@+HvHo?;79OV4#$vx2tDmMdi!t~R-ASlZQgD+R8+HQas~;5ocIGK zzTW;$M>&K4nSO`m*VnyAk&G7(-GOl;>qhM*}Wbl4_Jm$RXm*Y z#g%(ON%=jPVp8^QJ(#KVbZsXsb19~_nNg!gqN#97OFu>rEFo*k6T}UihN+)P8=GY} z(T3G!hrE7eZYbgd5k7yd2B^Wkb~%DzVJbyA8$k)<-Fax@<>04}QvCV~fIy}1MqQcS zE4Smtleho2KI&scb|7p@-{+0=_jCmxe|%vuqL!h!lHg`+05UK#GA%GN zEiyDzF*G_bIXW~lD=;uRFfil;$~pi503~!qSaf7zbY(hiZ)9m^c>ppnGBPbNGA%MR iR53II9+NB0|VnSPZ!4!jq|M&&U=Rh${e*XuI)R^!{fudM{v=B62%t+ zCpzpsBu{p6d1WL%IK`x!A?V2RXih(F_6_1x!RiCZVwx2dXu21Aa z=8sAVzcl}+X-pIA=l5;$pQ@uM$7G_jsAV13LcgP}0rQvaw^D3*^h$8mts{%$j9i_m03*T^ALUrz9KttVntK z}ldDzun^b%Qxof^LCi>9QbwGep&1JH5U%mzW+brks-V2 z>V0-B364csW@0LyT?*$v$al2aK9B#x9I)f!*W_OluipH(kUh_sk7vSzg0%+Eq~f0@ zyq4CsO