# Upgrading from RDFLib version 3.X to 4.X

RDFLib version 4.0 introduced a small number of backwards compatible changes that you should know about when porting code from version 3 or earlier.

## SPARQL and SPARQLStore are now included in core

For version 4.0 we’ve merged the SPARQL implementation from `rdflib-sparql`, the SPARQL(Update)Store from `rdflib-sparqlstore` and miscellaneous utilities from `rdfextras`. If you used any of these previously, everything you need should now be included.

## Datatyped literals

We separate lexical and value space operations for datatyped literals.

This mainly affects the way datatyped literals are compared. Lexical space comparisons are done by default for `==` and `!=`, meaning the exact lexical representation and the exact data-types have to match for literals to be equal. Value space comparisons are also available through the `rdflib.term.Identifier.eq()` and `rdflib.term.Identifier.neq()` methods, `< > <= >=` are also done in value space.

Most things now work in a fairly sane and sensible way, if you do not have existing stores/intermediate stored sorted lists, or hash-dependent something-or-other, you should be good to go.

Things to watch out for:

### Literals no longer compare equal across data-types with ``==``

i.e.

    >>> Literal(2, datatype=XSD.int) == Literal(2, datatype=XSD.float)
    False

But a new method `rdflib.term.Identifier.eq()` on all Nodes has been introduced, which does semantic equality checking, i.e.:

    >>> Literal(2, datatype=XSD.int).eq(Literal(2, datatype=XSD.float))
    True

The `eq` method is still limited to what data-types map to the same value space, i.e. all numeric types map to numbers and will compare, `xsd:string` and `plain literals` both map to strings and compare fine, but:

    >>> Literal(2, datatype=XSD.int).eq(Literal('2'))
    False

### Literals will be normalised according to datatype

If you care about the exact lexical representation of a literal, and not just the value. Either set `rdflib.NORMALIZE_LITERALS` to `False` before creating your literal, or pass `normalize=False` to the Literal constructor

### Ordering of literals and nodes has changed

Comparing literals with `<, >, <=, >=` now work same as in SPARQL filter expressions.

Greater-than/less-than ordering comparisons are also done in value space, when compatible datatypes are used. Incompatible datatypes are ordered by data-type, or by lang-tag. For other nodes the ordering is `None < BNode < URIRef < Literal`

Any comparison with non-rdflib Node are `NotImplemented` In PY2.X some stable order will be made up by python. In PY3 this is an error.

### Custom mapping of datatypes to python objects

You can add new mappings of datatype URIs to python objects using the `rdflib.term.bind()` method. This also allows you to specify a constructor for constructing objects from the lexical string representation, and a serialization method for generating a lexical string representation from an object.

## Minor Changes

- `rdflib.namespace.Namespace` is no longer a sub-class of `rdflib.term.URIRef` this was changed as it makes no sense for a namespace to be a node in a graph, and was causing numerous bug. Unless you do something very special, you should not notice this change.

- The identifiers for Graphs are now converted to URIRefs if they are not a `rdflib.term.Node`, i.e. no more graphs with string identifiers. Again, unless you do something quite unusual, you should not notice.

- String concatenation with URIRefs now returns URIRefs, not strings:

      >>> URIRef("http://example.org/people/") + "Bill"

  rdflib.term.URIRef(u’http://example.org/people/Bill‘)

  This is be convenient, but may cause trouble if you expected a string.