Skip to content

Commit c7cd09f

Browse files
authored
Merge pull request #31 from tstoeter/main
2 parents 54e6cb4 + bb5e4de commit c7cd09f

File tree

1 file changed

+62
-13
lines changed

1 file changed

+62
-13
lines changed

src/omero_rdf/__init__.py

Lines changed: 62 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
2020

2121

22+
import contextlib
23+
import gzip
24+
import sys
2225
import json
2326
import logging
2427
from argparse import Namespace
@@ -36,19 +39,24 @@
3639
from rdflib.namespace import DCTERMS, RDF
3740
from rdflib_pyld_compat import pyld_jsonld_from_rdflib_graph
3841

39-
HELP = """A plugin for exporting rdf from OMERO
42+
HELP = """A plugin for exporting RDF from OMERO
4043
4144
omero-rdf creates a stream of RDF triples from the starting object that
4245
it is given. This may be one of: Image, Dataset, Project, Plate, and Screen.
4346
4447
Examples:
4548
4649
omero rdf Image:123 # Streams each triple found in N-Triples format
50+
4751
omero rdf -F=jsonld Image:123 # Collects all triples and prints formatted output
4852
omero rdf -S=flat Project:123 # Do not recurse into containers ("flat-strategy")
4953
omero rdf --trim-whitespace ... # Strip leading and trailing whitespace from text
5054
omero rdf --first-handler-wins ... # First mapping wins; others will be ignored
5155
56+
omero rdf --file - ... # Write RDF triples to stdout
57+
omero rdf --file output.nt ... # Write RDF triples to the specified file
58+
omero rdf --file output.nt.gz # Write RDF triples to the specified file, gzipping
59+
5260
"""
5361

5462
# TYPE DEFINITIONS
@@ -60,6 +68,37 @@
6068
Handlers = List[Callable[[URIRef, URIRef, Data], Generator[Triple, None, bool]]]
6169

6270

71+
@contextlib.contextmanager
72+
def open_with_default(filename=None, filehandle=None):
73+
"""
74+
Open a file for writing if given and close on completion.
75+
76+
No closing will happen if the file name is "-" since stdout will be used.
77+
If no filehandle is given, stdout will also be used.
78+
Otherwise return the given filehandle will be used.
79+
"""
80+
close = False
81+
if filename:
82+
if filename == "-":
83+
fh = sys.stdout
84+
else:
85+
if filename.endswith(".gz"):
86+
fh = gzip.open(filename, "wt")
87+
else:
88+
fh = open(filename, "w")
89+
close = True
90+
else:
91+
if filehandle is None:
92+
filehandle = sys.stdout
93+
fh = filehandle
94+
95+
try:
96+
yield fh
97+
finally:
98+
if close:
99+
fh.close()
100+
101+
63102
def gateway_required(func: Callable) -> Callable: # type: ignore
64103
"""
65104
Decorator which initializes a client (self.client),
@@ -256,6 +295,7 @@ def __init__(
256295
use_ellide=False,
257296
first_handler_wins=False,
258297
descent="recursive",
298+
filehandle=sys.stdout,
259299
) -> None:
260300
self.gateway = gateway
261301
self.cache: Set[URIRef] = set()
@@ -268,6 +308,7 @@ def __init__(
268308
self._descent_level = 0
269309
self.annotation_handlers = self.load_handlers()
270310
self.info = self.load_server()
311+
self.filehandle = filehandle
271312

272313
def skip_descent(self):
273314
return self.descent != "recursive" and self._descent_level > 0
@@ -375,13 +416,13 @@ def handle(self, data: Data) -> URIRef:
375416

376417
def emit(self, triple: Triple):
377418
if self.formatter.streaming:
378-
print(self.formatter.serialize_triple(triple))
419+
print(self.formatter.serialize_triple(triple), file=self.filehandle)
379420
else:
380421
self.formatter.add(triple)
381422

382423
def close(self):
383424
if not self.formatter.streaming:
384-
print(self.formatter.serialize_graph())
425+
print(self.formatter.serialize_graph(), file=self.filehandle)
385426

386427
def rdf(
387428
self,
@@ -527,6 +568,12 @@ def _configure(self, parser: Parser) -> None:
527568
default=False,
528569
help="Remove leading and trailing whitespace from literals",
529570
)
571+
parser.add_argument(
572+
"--file",
573+
type=str,
574+
default=None,
575+
help="Write RDF triples to the specified file",
576+
)
530577
parser.set_defaults(func=self.action)
531578

532579
@gateway_required
@@ -538,16 +585,18 @@ def action(self, args: Namespace) -> None:
538585
else:
539586
args.format = format_mapping()[args.format]
540587

541-
handler = Handler(
542-
self.gateway,
543-
formatter=args.format,
544-
use_ellide=args.ellide,
545-
trim_whitespace=args.trim_whitespace,
546-
first_handler_wins=args.first_handler_wins,
547-
descent=args.descent,
548-
)
549-
self.descend(self.gateway, args.target, handler)
550-
handler.close()
588+
with open_with_default(args.file) as fh:
589+
handler = Handler(
590+
self.gateway,
591+
formatter=args.format,
592+
use_ellide=args.ellide,
593+
trim_whitespace=args.trim_whitespace,
594+
first_handler_wins=args.first_handler_wins,
595+
descent=args.descent,
596+
filehandle=fh,
597+
)
598+
self.descend(self.gateway, args.target, handler)
599+
handler.close()
551600

552601
# TODO: move to handler?
553602
def descend(

0 commit comments

Comments
 (0)