pylode 2.8.3__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. pyLODE-2.8.3.dist-info/LICENSE +643 -0
  2. pyLODE-2.8.3.dist-info/METADATA +772 -0
  3. pyLODE-2.8.3.dist-info/RECORD +63 -0
  4. pyLODE-2.8.3.dist-info/WHEEL +6 -0
  5. pyLODE-2.8.3.dist-info/entry_points.txt +3 -0
  6. pyLODE-2.8.3.dist-info/top_level.txt +1 -0
  7. pylode/__init__.py +5 -0
  8. pylode/cli.py +191 -0
  9. pylode/common.py +191 -0
  10. pylode/curies.py +2208 -0
  11. pylode/profiles/__init__.py +4 -0
  12. pylode/profiles/base.py +463 -0
  13. pylode/profiles/ontdoc.py +1283 -0
  14. pylode/profiles/prof.py +276 -0
  15. pylode/profiles/profile.py +135 -0
  16. pylode/profiles/vocpub.py +605 -0
  17. pylode/server.py +24 -0
  18. pylode/style/pylode.css +179 -0
  19. pylode/templates/agent.html +11 -0
  20. pylode/templates/agent.md +11 -0
  21. pylode/templates/namespaces.html +9 -0
  22. pylode/templates/namespaces.md +5 -0
  23. pylode/templates/ontdoc/class.html +121 -0
  24. pylode/templates/ontdoc/class.md +40 -0
  25. pylode/templates/ontdoc/classes.html +11 -0
  26. pylode/templates/ontdoc/classes.md +7 -0
  27. pylode/templates/ontdoc/document.html +42 -0
  28. pylode/templates/ontdoc/document.md +16 -0
  29. pylode/templates/ontdoc/metadata.html +127 -0
  30. pylode/templates/ontdoc/metadata.md +111 -0
  31. pylode/templates/ontdoc/named_individual.html +65 -0
  32. pylode/templates/ontdoc/named_individual.md +25 -0
  33. pylode/templates/ontdoc/named_individuals.html +11 -0
  34. pylode/templates/ontdoc/named_individuals.md +7 -0
  35. pylode/templates/ontdoc/properties.html +65 -0
  36. pylode/templates/ontdoc/properties.md +45 -0
  37. pylode/templates/ontdoc/property.html +129 -0
  38. pylode/templates/ontdoc/property.md +37 -0
  39. pylode/templates/orcid.html +19 -0
  40. pylode/templates/orcid.md +1 -0
  41. pylode/templates/prof/prof.html +38 -0
  42. pylode/templates/prof/prof.md +16 -0
  43. pylode/templates/prof/profile.html +90 -0
  44. pylode/templates/prof/profile.md +85 -0
  45. pylode/templates/prof/resource_descriptor.html +49 -0
  46. pylode/templates/prof/resource_descriptor.md +21 -0
  47. pylode/templates/vocpub/collection.html +51 -0
  48. pylode/templates/vocpub/collection.md +23 -0
  49. pylode/templates/vocpub/collections.html +11 -0
  50. pylode/templates/vocpub/collections.md +7 -0
  51. pylode/templates/vocpub/concept.html +115 -0
  52. pylode/templates/vocpub/concept.md +40 -0
  53. pylode/templates/vocpub/concept_hierarchy.html +80 -0
  54. pylode/templates/vocpub/concept_scheme.html +105 -0
  55. pylode/templates/vocpub/concept_scheme.md +102 -0
  56. pylode/templates/vocpub/concepts.html +9 -0
  57. pylode/templates/vocpub/concepts.md +7 -0
  58. pylode/templates/vocpub/taxonomy.html +42 -0
  59. pylode/templates/vocpub/taxonomy.md +17 -0
  60. pylode/tests/__init__.py +0 -0
  61. pylode/tests/test_ont_html_description.py +7 -0
  62. pylode/tests/test_skos.py +8 -0
  63. pylode/tests/tests_all.py +50 -0
@@ -0,0 +1,276 @@
1
+ from pylode.common import VERSION, STYLE_DIR, TEMPLATES_DIR
2
+ import collections
3
+ from os import path
4
+ from rdflib import URIRef, BNode, Literal
5
+ from rdflib.namespace import DC, DCTERMS, OWL, PROF, RDF, RDFS, SDO, SKOS
6
+ import dateutil.parser
7
+ from itertools import chain
8
+ import markdown
9
+ from jinja2 import Environment, FileSystemLoader
10
+ from os.path import join
11
+ from pylode.profiles.base import BaseProfile
12
+
13
+
14
+ class Prof(BaseProfile):
15
+ def __init__(self, g, source_info, outputformat="html", exclude_css=False, default_language="en", get_curies_online=False):
16
+ super().__init__(g, source_info, outputformat=outputformat, exclude_css=exclude_css, get_curies_online=False, default_language=default_language)
17
+ self.RESOURCE_DESCRIPTORS = collections.OrderedDict()
18
+
19
+ def _load_template(self, template_file):
20
+ return Environment(loader=FileSystemLoader(join(TEMPLATES_DIR, "prof"))).get_template(template_file)
21
+
22
+ def _make_formatted_uri(self, uri):
23
+ # set display to CURIE
24
+ short = self._get_curie(uri)
25
+ # if the URI base is within the default namespace of this ontology
26
+ # use the fragment URI
27
+ # else
28
+ # use the given URI
29
+ uri_base = self._get_namespace_from_uri(uri)
30
+ link = None
31
+ if uri_base == self.METADATA.get("default_namespace"):
32
+ if self.RESOURCE_DESCRIPTORS.get(uri):
33
+ link = "[{}]({})".format(self.RESOURCE_DESCRIPTORS[uri]["default_prefLabel"], self.RESOURCE_DESCRIPTORS[uri]["fid"]) \
34
+ if self.outputformat == "md" \
35
+ else '<a href="#{}">{}</a>'.format(self.RESOURCE_DESCRIPTORS[uri]["fid"], self.RESOURCE_DESCRIPTORS[uri]["default_prefLabel"])
36
+
37
+ if link is None:
38
+ link = "[{}]({})".format(short, uri) \
39
+ if self.outputformat == "md" \
40
+ else '<a href="{}">{}</a>'.format(uri, short)
41
+
42
+ return link
43
+
44
+ def _expand_graph(self):
45
+ # label
46
+ for s, o in chain(
47
+ self.G.subject_objects(DC.title),
48
+ self.G.subject_objects(SKOS.prefLabel),
49
+ self.G.subject_objects(DCTERMS.title)
50
+ ):
51
+ self.G.remove((s, DC.title, o))
52
+ self.G.remove((s, SKOS.prefLabel, o))
53
+ self.G.remove((s, DCTERMS.title, o))
54
+ self.G.add((s, RDFS.label, o))
55
+
56
+ # comment
57
+ for s, o in chain(
58
+ self.G.subject_objects(DC.description),
59
+ self.G.subject_objects(DCTERMS.description),
60
+ self.G.subject_objects(SDO.description),
61
+ self.G.subject_objects(SKOS.definition),
62
+ ):
63
+ self.G.remove((s, DC.description, o))
64
+ self.G.remove((s, DCTERMS.description, o))
65
+ self.G.remove((s, SDO.description, o))
66
+ self.G.remove((s, SKOS.definition, o))
67
+ self.G.add((s, RDFS.comment, o))
68
+
69
+ # Agents
70
+ # creator
71
+ for s, o in chain(
72
+ self.G.subject_objects(DC.creator),
73
+ self.G.subject_objects(SDO.creator),
74
+ self.G.subject_objects(SDO.author) # conflate SDO.author with DCTERMS.creator
75
+ ):
76
+ self.G.remove((s, DC.creator, o))
77
+ self.G.remove((s, SDO.creator, o))
78
+ self.G.remove((s, SDO.author, o))
79
+ self.G.add((s, DCTERMS.creator, o))
80
+
81
+ # contributor
82
+ for s, o in chain(
83
+ self.G.subject_objects(DC.contributor),
84
+ self.G.subject_objects(SDO.contributor)
85
+ ):
86
+ self.G.remove((s, DC.contributor, o))
87
+ self.G.remove((s, SDO.contributor, o))
88
+ self.G.add((s, DCTERMS.contributor, o))
89
+
90
+ # publisher
91
+ for s, o in chain(
92
+ self.G.subject_objects(DC.publisher),
93
+ self.G.subject_objects(SDO.publisher)
94
+ ):
95
+ self.G.remove((s, DC.publisher, o))
96
+ self.G.remove((s, SDO.publisher, o))
97
+ self.G.add((s, DCTERMS.publisher, o))
98
+
99
+ # Resource Descriptors
100
+ for s, o in self.G.subject_objects(PROF.hasResource):
101
+ self.G.add((o, RDF.type, PROF.ResourceDescriptor))
102
+
103
+ def _extract_resource_descriptors(self):
104
+ """Extracts Resource Descriptors"""
105
+ resource_descriptors = []
106
+ # TODO: handle OrderedCollections
107
+ for s in self.G.subjects(predicate=RDF.type, object=PROF.ResourceDescriptor):
108
+ resource_descriptors.append(s) # could be a URI or a BNode
109
+
110
+ # keeping the OrderedDict ordered
111
+ for rd in sorted(resource_descriptors):
112
+ self.RESOURCE_DESCRIPTORS[rd] = {}
113
+
114
+ # fill in each Resource Descriptor's details from the graph
115
+ for rd in self.RESOURCE_DESCRIPTORS.keys():
116
+ self.RESOURCE_DESCRIPTORS[rd]["fid"] = None
117
+ self.RESOURCE_DESCRIPTORS[rd]["label"] = None
118
+ self.RESOURCE_DESCRIPTORS[rd]["comment"] = None
119
+ self.RESOURCE_DESCRIPTORS[rd]["artifact"] = None
120
+ self.RESOURCE_DESCRIPTORS[rd]["roles"] = set()
121
+ self.RESOURCE_DESCRIPTORS[rd]["conforms"] = set()
122
+ self.RESOURCE_DESCRIPTORS[rd]["format"] = None
123
+
124
+ for p, o in self.G.predicate_objects(subject=rd):
125
+ if p == RDFS.label:
126
+ self.RESOURCE_DESCRIPTORS[rd]["label"] = str(o)
127
+ elif p == RDFS.comment:
128
+ self.RESOURCE_DESCRIPTORS[rd]["comment"] = str(o)
129
+ elif p == PROF.hasArtifact:
130
+ self.RESOURCE_DESCRIPTORS[rd]["artifact"] = self._make_formatted_uri(str(o))
131
+ elif p == PROF.hasRole:
132
+ self.RESOURCE_DESCRIPTORS[rd]["roles"].add(self._make_formatted_uri(str(o)))
133
+ elif p == DCTERMS.conformsTo:
134
+ self.RESOURCE_DESCRIPTORS[rd]["conforms"].add(self._make_formatted_uri(str(o)))
135
+ elif p == DCTERMS.format:
136
+ self.RESOURCE_DESCRIPTORS[rd]["format"] = str(o)
137
+
138
+ self.RESOURCE_DESCRIPTORS[rd]["roles"] = list(self.RESOURCE_DESCRIPTORS[rd]["roles"])
139
+ self.RESOURCE_DESCRIPTORS[rd]["conforms"] = list(self.RESOURCE_DESCRIPTORS[rd]["conforms"])
140
+
141
+ # make fid
142
+ if type(rd) is BNode:
143
+ self.RESOURCE_DESCRIPTORS[rd]["fid"] = str(rd)
144
+ else: # URI
145
+ self.RESOURCE_DESCRIPTORS[rd]["fid"] = self._make_fid(str(rd), str(rd))
146
+
147
+ def _extract_profile(self):
148
+ """Extracts standard prof:Profile metadata
149
+ """
150
+
151
+ self.METADATA["creators"] = set()
152
+ self.METADATA["contributors"] = set()
153
+ self.METADATA["publishers"] = set()
154
+ self.METADATA["profiles"] = set()
155
+ for s in self.G.subjects(predicate=RDF.type, object=PROF.Profile):
156
+ self.METADATA["uri"] = str(s)
157
+ for p, o in self.G.predicate_objects(subject=s):
158
+ if p == RDFS.label:
159
+ self.METADATA["label"] = str(o)
160
+
161
+ if p == RDFS.comment:
162
+ self.METADATA["comment"] = markdown.markdown(str(o))
163
+
164
+ # dates
165
+ if p in [DCTERMS.created, DCTERMS.modified, DCTERMS.issued]:
166
+ date_type = p.split("/")[-1]
167
+ self.METADATA[date_type] = dateutil.parser.parse(str(o)).strftime("%Y-%m-%d")
168
+
169
+ if p == OWL.versionIRI:
170
+ self.METADATA["versionIRI"] = self._make_formatted_uri(o)
171
+
172
+ if p == OWL.versionInfo:
173
+ self.METADATA["versionInfo"] = str(o)
174
+
175
+ if p == URIRef("http://purl.org/vocab/vann/preferredNamespacePrefix"):
176
+ self.METADATA["preferredNamespacePrefix"] = str(o)
177
+
178
+ if p == URIRef("http://purl.org/vocab/vann/preferredNamespaceUri"):
179
+ self.METADATA["preferredNamespaceUri"] = str(o)
180
+
181
+ if p == DCTERMS.license:
182
+ self.METADATA["license"] = (
183
+ self._make_formatted_uri(o)
184
+ if str(o).startswith("http")
185
+ else str(o)
186
+ )
187
+
188
+ if p == DCTERMS.rights:
189
+ self.METADATA["rights"] = (
190
+ str(o)
191
+ .replace("Copyright", "&copy;")
192
+ .replace("copyright", "&copy;")
193
+ .replace("(c)", "&copy;")
194
+ )
195
+
196
+ # Agents
197
+ if p in [DCTERMS.creator, DCTERMS.contributor, DCTERMS.publisher]:
198
+ agent_type = p.split("/")[-1] + "s"
199
+ if type(o) == Literal:
200
+ self.METADATA[agent_type].add(str(o))
201
+ else: # Blank Node or URI
202
+ self.METADATA[agent_type].add(self._make_agent_html(o))
203
+
204
+ if p == PROF.isProfileOf:
205
+ self.METADATA["profiles"].add(str(o))
206
+
207
+ # TODO: cater for other Agent representations
208
+
209
+ if self.METADATA.get("label") is None:
210
+ raise ValueError(
211
+ "Your profile does not indicate any form of title... "
212
+ "You must declare one of the following for it: rdfs:label, dct:title, skos:prefLabel"
213
+ )
214
+
215
+ def _make_profile(self):
216
+ return self._load_template("profile." + self.outputformat).render(
217
+ label=self.METADATA.get("label"),
218
+ uri=self.METADATA.get("uri"),
219
+ version_uri=self.METADATA.get("versionIRI"),
220
+ publishers=sorted(self.METADATA["publishers"]),
221
+ creators=sorted(self.METADATA["creators"]),
222
+ contributors=sorted(self.METADATA["contributors"]),
223
+ created=self.METADATA.get("created"),
224
+ modified=self.METADATA.get("modified"),
225
+ issued=self.METADATA.get("issued"),
226
+ comment=self.METADATA.get("comment"),
227
+ version_info=self.METADATA.get("versionInfo"),
228
+ license=self.METADATA.get("license"),
229
+ rights=self.METADATA.get("rights"),
230
+ repository=self.METADATA.get("repository"),
231
+ prof_rdf=self._make_source_file_link(),
232
+ profiles=self.METADATA["profiles"],
233
+ resource_descriptors=self.RESOURCE_DESCRIPTORS,
234
+ )
235
+
236
+ def _make_resource_descriptor(self, rd):
237
+ return self._load_template("resource_descriptor." + self.outputformat).render(
238
+ uri=rd.get("fid") if rd.get("fid").startswith("http") else None,
239
+ fid=rd.get("fid"),
240
+ label=rd.get("label"),
241
+ comment=rd.get("comment"),
242
+ artifact=rd.get("artifact"),
243
+ roles=rd.get("roles"),
244
+ conforms=rd.get("conforms"),
245
+ format=rd.get("format"),
246
+ )
247
+
248
+ def _make_resource_descriptors(self):
249
+ for rdid, rd in self.RESOURCE_DESCRIPTORS.items():
250
+ self.RESOURCE_DESCRIPTORS[rdid]["html"] = self._make_resource_descriptor(rd)
251
+
252
+ def _make_document(self):
253
+ css = None
254
+ if self.outputformat == "html":
255
+ if not self.exclude_css:
256
+ css = open(path.join(STYLE_DIR, "pylode.css")).read()
257
+
258
+ return self._load_template("prof." + self.outputformat).render(
259
+ schemaorg=self._make_schemaorg_metadata(), # only does something for the HTML template
260
+ label=self.METADATA["label"],
261
+ profile=self._make_profile(),
262
+ has_resource_descriptors=True if len(self.RESOURCE_DESCRIPTORS) > 0 else False,
263
+ resource_descriptors=self.RESOURCE_DESCRIPTORS,
264
+ namespaces=self._make_namespaces(),
265
+ css=css,
266
+ pylode_version=VERSION
267
+ )
268
+
269
+ def generate_document(self):
270
+ self._expand_graph()
271
+ self._extract_namespaces()
272
+ self._get_default_namespace()
273
+ self._extract_profile()
274
+ self._extract_resource_descriptors()
275
+ self._make_resource_descriptors()
276
+ return self._make_document()
@@ -0,0 +1,135 @@
1
+ class Profile:
2
+ """A Profile is a specification that constrains, extends, combines, or provides guidance or explanation about
3
+ the usage of other specifications.
4
+
5
+ This definition includes what are sometimes called "application profiles", "metadata application profiles", or
6
+ "metadata profiles". In this document, "data profile" and these other variants are all referred to as just
7
+ "profiles".
8
+
9
+ This definition of Profiles is from The Profiles Vocabulary: https://www.w3.org/TR/dx-prof/ and objects created
10
+ using this class are intended for use as prof:Profile instances.
11
+ """
12
+ def __init__(
13
+ self,
14
+ uri,
15
+ label,
16
+ comment,
17
+ mediatypes,
18
+ default_mediatype,
19
+ languages=None,
20
+ default_language='en',
21
+ is_profile_of=None
22
+ ):
23
+ """
24
+ Constructor
25
+
26
+ :param uri: The namespace URI for the *profile* view.
27
+ :type uri: str
28
+ :param label: The human-readable label for the Profile.
29
+ :type label: str
30
+ :param comment: A description of the Profile.
31
+ :type comment: str
32
+ :param mediatypes: The list of IANA MediaTypes that this Profile supports.
33
+ :type mediatypes: list
34
+ :param default_mediatype: The default MediaType that this Profile is delivered in.
35
+ :type default_mediatype: str
36
+ :param languages: A list of languages this Profile supports. Identified by ISO 639-1 2-letter language codes.
37
+ :type languages: list
38
+ :param default_language: The default language, by default it is 'en': English.
39
+ :type default_language: str
40
+ :param is_profile_of: A list of URIs (strings) that this Profile is a Profile of
41
+ :type is_profile_of: list
42
+ """
43
+ self.uri = uri
44
+ self.label = label
45
+ self.comment = comment
46
+ self.mediatypes = mediatypes
47
+ self.default_mediatype = default_mediatype
48
+ self.languages = languages if languages is not None else ['en']
49
+ self.default_language = default_language
50
+ self.is_profile_of = is_profile_of
51
+
52
+ def __str__(self):
53
+ return self.uri
54
+
55
+
56
+ RDF_MEDIA_TYPES = [
57
+ 'text/turtle',
58
+ 'application/rdf+xml',
59
+ 'application/ld+json',
60
+ 'text/n3',
61
+ 'application/n-triples'
62
+ ]
63
+ HTML_MEDIA_TYPE = "text/html"
64
+ PROF_PROFILE = Profile(
65
+ "https://www.w3.org/TR/dx-prof/",
66
+ "The Profiles Vocabulary",
67
+ "The Profiles Vocabulary is an RDF vocabulary created to allow the machine-readable description of profiles of "
68
+ "specifications for information resources.",
69
+ [HTML_MEDIA_TYPE, "text/markdown"],
70
+ HTML_MEDIA_TYPE,
71
+ languages=["en"],
72
+ default_language="en"
73
+ )
74
+ OWL_PROFILE = Profile(
75
+ "https://www.w3.org/TR/owl2-rdf-based-semantics/",
76
+ "Web Ontology Language (OWL)",
77
+ "The OWL 2 Web Ontology Language, informally OWL 2, is an ontology language for the Semantic Web with formally "
78
+ "defined meaning. OWL 2 ontologies provide classes, properties, individuals, and data values and are stored as "
79
+ "Semantic Web documents.",
80
+ [HTML_MEDIA_TYPE, "text/markdown"],
81
+ HTML_MEDIA_TYPE,
82
+ languages=["en"],
83
+ default_language="en"
84
+ )
85
+ ONT_DOC_PROFILE = Profile(
86
+ "https://w3id.org/profile/ontdocp",
87
+ "Ontology Documentation Profile",
88
+ "OWL Classes and Properties as well as additional SKOS, Dublin Core Terms and schema.org annotation "
89
+ "properties to be used to document ontologies.",
90
+ [HTML_MEDIA_TYPE, "text/markdown"],
91
+ HTML_MEDIA_TYPE,
92
+ languages=["en"],
93
+ default_language="en",
94
+ is_profile_of=["https://www.w3.org/TR/owl2-rdf-based-semantics/"]
95
+ )
96
+ SKOS_PROFILE = Profile(
97
+ "https://www.w3.org/TR/skos-reference/",
98
+ "Simple Knowledge Organization System (SKOS)",
99
+ "A common data model for sharing and linking knowledge organization systems, such as thesauri, taxonomies, "
100
+ "classification schemes and subject heading systems.",
101
+ RDF_MEDIA_TYPES + [HTML_MEDIA_TYPE, "text/markdown"],
102
+ HTML_MEDIA_TYPE,
103
+ languages=["en"],
104
+ default_language="en",
105
+ is_profile_of=["https://www.w3.org/TR/owl2-rdf-based-semantics/"]
106
+ )
107
+ VOC_PUB_PROFILE = Profile(
108
+ "https://w3id.org/profile/vocpub",
109
+ "Vocabulary Publication Profile",
110
+ "SKOS ConceptSchemes, Collections & Concepts as well as additional Dublin Core Terms & schema.org "
111
+ "annotation properties to be used to publish vocabularies.",
112
+ RDF_MEDIA_TYPES + [HTML_MEDIA_TYPE, "text/markdown"],
113
+ HTML_MEDIA_TYPE,
114
+ languages=["en"],
115
+ default_language="en",
116
+ is_profile_of=["https://www.w3.org/TR/skos-reference/"]
117
+ )
118
+
119
+ # MOD_PROFILE = Profile(
120
+ # "http://www.isibang.ac.in/ns/mod#MetadataForOntologyDescriptionAndPublication",
121
+ # "Metadata for Ontology Description and Publication (MOD)",
122
+ # "To describe the vocabularies, e.g., ontology, classification, metadata, etc.",
123
+ # RDF_MEDIA_TYPES + [HTML_MEDIA_TYPE, "text/markdown"],
124
+ # HTML_MEDIA_TYPE,
125
+ # languages=["en"],
126
+ # default_language="en",
127
+ # is_profile_of=["https://www.w3.org/TR/owl2-rdf-based-semantics/", "http://purl.org/dc/terms/"]
128
+ # )
129
+
130
+ PROFILES = {
131
+ "prof": PROF_PROFILE,
132
+ "ontdoc": ONT_DOC_PROFILE,
133
+ "vocpub": VOC_PUB_PROFILE,
134
+ # "modp": MOD_PROFILE
135
+ }