Skip to content

Commit

Permalink
Use the property built-in as a decorator
Browse files Browse the repository at this point in the history
The use of the `property` built-in as a function does not allow for
the same type annotations as using `property` as a deocorator.

This change should not affect runtime behaviour, but I added tests to
cover all properties that were changed to decorators explicitly just to
make sure they work as they should.

There are still other places where the `property` built-in is used as a
function but this is outside of the core parts of RDFLib.
  • Loading branch information
aucampia committed Feb 2, 2022
1 parent b2cae90 commit ca12e19
Show file tree
Hide file tree
Showing 12 changed files with 262 additions and 44 deletions.
25 changes: 11 additions & 14 deletions rdflib/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -350,30 +350,27 @@ def __init__(
self.formula_aware = False
self.default_union = False

def __get_store(self):
@property
def store(self):
return self.__store

store = property(__get_store) # read-only attr

def __get_identifier(self):
@property
def identifier(self):
return self.__identifier

identifier = property(__get_identifier) # read-only attr

def _get_namespace_manager(self):
@property
def namespace_manager(self):
"""
this graph's namespace-manager
"""
if self.__namespace_manager is None:
self.__namespace_manager = NamespaceManager(self)
return self.__namespace_manager

def _set_namespace_manager(self, nm):
@namespace_manager.setter
def namespace_manager(self, nm):
self.__namespace_manager = nm

namespace_manager = property(
_get_namespace_manager,
_set_namespace_manager,
doc="this graph's namespace-manager",
)

def __repr__(self):
return "<Graph identifier=%s (%s)>" % (self.identifier, type(self))

Expand Down
13 changes: 7 additions & 6 deletions rdflib/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,24 +177,25 @@ def __init__(self, type_: str):
self.askAnswer: bool = None # type: ignore[assignment]
self.graph: "Graph" = None # type: ignore[assignment]

def _get_bindings(self):
@property
def bindings(self):
"""
a list of variable bindings as dicts
"""
if self._genbindings:
self._bindings += list(self._genbindings)
self._genbindings = None

return self._bindings

def _set_bindings(self, b):
@bindings.setter
def bindings(self, b):
if isinstance(b, (types.GeneratorType, itertools.islice)):
self._genbindings = b
self._bindings = []
else:
self._bindings = b

bindings = property(
_get_bindings, _set_bindings, doc="a list of variable bindings as dicts"
)

@staticmethod
def parse(
source=None,
Expand Down
8 changes: 6 additions & 2 deletions rdflib/resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -298,9 +298,13 @@ def __init__(self, graph, subject):
self._graph = graph
self._identifier = subject

graph = property(lambda self: self._graph)
@property
def graph(self):
return self._graph

identifier = property(lambda self: self._identifier)
@property
def identifier(self):
return self._identifier

def __hash__(self):
return hash(Resource) ^ hash(self._graph) ^ hash(self._identifier)
Expand Down
4 changes: 2 additions & 2 deletions rdflib/store.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,8 @@ def __init__(self, configuration=None, identifier=None):
if configuration:
self.open(configuration)

def __get_node_pickler(self):
@property
def node_pickler(self):
if self.__node_pickler is None:
from rdflib.term import URIRef
from rdflib.term import BNode
Expand All @@ -169,7 +170,6 @@ def __get_node_pickler(self):
np.register(Variable, "V")
return self.__node_pickler

node_pickler = property(__get_node_pickler)

# Database management methods
def create(self, configuration):
Expand Down
11 changes: 10 additions & 1 deletion test/conftest.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
from .earl import EarlReporter
import pytest

from rdflib import Graph

from .data import CONSISTENT_DATA_DIR
from .earl import EarlReporter

pytest_plugins = [EarlReporter.__module__]

# This is here so that asserts from these modules are formatted for human
# readibility.
pytest.register_assert_rewrite("test.testutils")


@pytest.fixture(scope="session")
def rdfs_graph() -> Graph:
return Graph().parse(CONSISTENT_DATA_DIR / "rdfs.ttl", format="turtle")
9 changes: 9 additions & 0 deletions test/consistent_test_data/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Consistent Test Data

This directory contains consistent graphs that can be used inside tests, the
graphs in this directory should not change.


## File origins

- `rdfs.ttl`: `http://www.w3.org/2000/01/rdf-schema#`
109 changes: 109 additions & 0 deletions test/consistent_test_data/rdfs.ttl
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix dc: <http://purl.org/dc/elements/1.1/> .

<http://www.w3.org/2000/01/rdf-schema#> a owl:Ontology ;
dc:title "The RDF Schema vocabulary (RDFS)" .

rdfs:Resource a rdfs:Class ;
rdfs:isDefinedBy <http://www.w3.org/2000/01/rdf-schema#> ;
rdfs:label "Resource" ;
rdfs:comment "The class resource, everything." .

rdfs:Class a rdfs:Class ;
rdfs:isDefinedBy <http://www.w3.org/2000/01/rdf-schema#> ;
rdfs:label "Class" ;
rdfs:comment "The class of classes." ;
rdfs:subClassOf rdfs:Resource .

rdfs:subClassOf a rdf:Property ;
rdfs:isDefinedBy <http://www.w3.org/2000/01/rdf-schema#> ;
rdfs:label "subClassOf" ;
rdfs:comment "The subject is a subclass of a class." ;
rdfs:range rdfs:Class ;
rdfs:domain rdfs:Class .

rdfs:subPropertyOf a rdf:Property ;
rdfs:isDefinedBy <http://www.w3.org/2000/01/rdf-schema#> ;
rdfs:label "subPropertyOf" ;
rdfs:comment "The subject is a subproperty of a property." ;
rdfs:range rdf:Property ;
rdfs:domain rdf:Property .

rdfs:comment a rdf:Property ;
rdfs:isDefinedBy <http://www.w3.org/2000/01/rdf-schema#> ;
rdfs:label "comment" ;
rdfs:comment "A description of the subject resource." ;
rdfs:domain rdfs:Resource ;
rdfs:range rdfs:Literal .

rdfs:label a rdf:Property ;
rdfs:isDefinedBy <http://www.w3.org/2000/01/rdf-schema#> ;
rdfs:label "label" ;
rdfs:comment "A human-readable name for the subject." ;
rdfs:domain rdfs:Resource ;
rdfs:range rdfs:Literal .

rdfs:domain a rdf:Property ;
rdfs:isDefinedBy <http://www.w3.org/2000/01/rdf-schema#> ;
rdfs:label "domain" ;
rdfs:comment "A domain of the subject property." ;
rdfs:range rdfs:Class ;
rdfs:domain rdf:Property .

rdfs:range a rdf:Property ;
rdfs:isDefinedBy <http://www.w3.org/2000/01/rdf-schema#> ;
rdfs:label "range" ;
rdfs:comment "A range of the subject property." ;
rdfs:range rdfs:Class ;
rdfs:domain rdf:Property .

rdfs:seeAlso a rdf:Property ;
rdfs:isDefinedBy <http://www.w3.org/2000/01/rdf-schema#> ;
rdfs:label "seeAlso" ;
rdfs:comment "Further information about the subject resource." ;
rdfs:range rdfs:Resource ;
rdfs:domain rdfs:Resource .

rdfs:isDefinedBy a rdf:Property ;
rdfs:isDefinedBy <http://www.w3.org/2000/01/rdf-schema#> ;
rdfs:subPropertyOf rdfs:seeAlso ;
rdfs:label "isDefinedBy" ;
rdfs:comment "The defininition of the subject resource." ;
rdfs:range rdfs:Resource ;
rdfs:domain rdfs:Resource .

rdfs:Literal a rdfs:Class ;
rdfs:isDefinedBy <http://www.w3.org/2000/01/rdf-schema#> ;
rdfs:label "Literal" ;
rdfs:comment "The class of literal values, eg. textual strings and integers." ;
rdfs:subClassOf rdfs:Resource .

rdfs:Container a rdfs:Class ;
rdfs:isDefinedBy <http://www.w3.org/2000/01/rdf-schema#> ;
rdfs:label "Container" ;
rdfs:subClassOf rdfs:Resource ;
rdfs:comment "The class of RDF containers." .

rdfs:ContainerMembershipProperty a rdfs:Class ;
rdfs:isDefinedBy <http://www.w3.org/2000/01/rdf-schema#> ;
rdfs:label "ContainerMembershipProperty" ;
rdfs:comment """The class of container membership properties, rdf:_1, rdf:_2, ...,
all of which are sub-properties of 'member'.""" ;
rdfs:subClassOf rdf:Property .

rdfs:member a rdf:Property ;
rdfs:isDefinedBy <http://www.w3.org/2000/01/rdf-schema#> ;
rdfs:label "member" ;
rdfs:comment "A member of the subject resource." ;
rdfs:domain rdfs:Resource ;
rdfs:range rdfs:Resource .

rdfs:Datatype a rdfs:Class ;
rdfs:isDefinedBy <http://www.w3.org/2000/01/rdf-schema#> ;
rdfs:label "Datatype" ;
rdfs:comment "The class of RDF datatypes." ;
rdfs:subClassOf rdfs:Class .

<http://www.w3.org/2000/01/rdf-schema#> rdfs:seeAlso <http://www.w3.org/2000/01/rdf-schema-more> .
4 changes: 4 additions & 0 deletions test/data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from pathlib import Path

TEST_DIR = Path(__file__).parent
CONSISTENT_DATA_DIR = TEST_DIR / "consistent_test_data"
33 changes: 32 additions & 1 deletion test/test_graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,44 @@
from rdflib import URIRef, Graph, plugin
from rdflib.exceptions import ParserError
from rdflib.plugin import PluginException
from rdflib.namespace import Namespace
from rdflib.namespace import Namespace, NamespaceManager

from pathlib import Path
from rdflib.store import Store
from rdflib.term import BNode

from test.testutils import GraphHelper


class TestGraphPT:
def test_property_store(self) -> None:
graph = Graph()
assert isinstance(graph.store, Store)

def test_property_identifier_default(self) -> None:
graph = Graph()
assert isinstance(graph.identifier, BNode)

def test_property_identifier(self) -> None:
id = URIRef("example:a")
graph = Graph(identifier=id)
assert id == graph.identifier

def test_property_namespace_manager(self) -> None:
graph = Graph()
# check repeats as property is a signleton
assert isinstance(graph.namespace_manager, NamespaceManager)
assert isinstance(graph.namespace_manager, NamespaceManager)

new_nsm = NamespaceManager(graph)
new_nsm.reset()
new_nsm.bind("test", URIRef("example:test:"))
graph.namespace_manager = new_nsm
assert isinstance(graph.namespace_manager, NamespaceManager)
nss = list(graph.namespace_manager.namespaces())
assert ("test", URIRef("example:test:")) in nss


class GraphTestCase(unittest.TestCase):
store = "default"
tmppath = None
Expand Down
9 changes: 9 additions & 0 deletions test/test_resource.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from rdflib import Graph
from rdflib.resource import Resource
from rdflib.namespace import RDFS


def test_properties(rdfs_graph: Graph) -> None:
cres = Resource(rdfs_graph, RDFS.Container)
assert cres.graph is rdfs_graph
assert cres.identifier == RDFS.Container
42 changes: 42 additions & 0 deletions test/test_sparql.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,3 +245,45 @@ def test_txtresult():
assert len(lines) == 3
vars_check = [Variable(var.strip()) for var in lines[0].split("|")]
assert vars_check == vars


def test_property_bindings(rdfs_graph: Graph) -> None:
result = rdfs_graph.query(
"""
SELECT ?class ?label WHERE {
?class rdf:type rdfs:Class.
?class rdfs:label ?label.
} ORDER BY ?class
"""
)
expected_bindings = [
{
Variable('class'): RDFS.Class,
Variable('label'): Literal('Class'),
},
{
Variable('class'): RDFS.Container,
Variable('label'): Literal('Container'),
},
{
Variable('class'): RDFS.ContainerMembershipProperty,
Variable('label'): Literal('ContainerMembershipProperty'),
},
{
Variable('class'): RDFS.Datatype,
Variable('label'): Literal('Datatype'),
},
{
Variable('class'): RDFS.Literal,
Variable('label'): Literal('Literal'),
},
{
Variable('class'): RDFS.Resource,
Variable('label'): Literal('Resource'),
},
]

assert expected_bindings == result.bindings

result.bindings = []
assert [] == result.bindings

0 comments on commit ca12e19

Please sign in to comment.