From 2ce0c1b667decfea1190f16fcda5f72706ecbde0 Mon Sep 17 00:00:00 2001
From: Tpt <thomaspt@hotmail.fr>
Date: Mon, 21 Aug 2023 21:31:11 +0200
Subject: [PATCH] Python and & JS: Renames "mime_type" parameter to "format"

- adds support of extensions
- MIME type is a deprecated wording
---
 js/README.md               | 30 ++++++------
 js/src/store.rs            | 22 +++++----
 python/src/io.rs           | 72 +++++++++++++++-------------
 python/src/store.rs        | 98 +++++++++++++++++---------------------
 python/tests/test_io.py    |  2 +-
 python/tests/test_store.py | 20 ++++----
 6 files changed, 125 insertions(+), 119 deletions(-)

diff --git a/js/README.md b/js/README.md
index 576c9739..0ee92e9b 100644
--- a/js/README.md
+++ b/js/README.md
@@ -197,40 +197,42 @@ Example of update:
 store.update("DELETE WHERE { <http://example.com/s> ?p ?o }")
 ```
 
-#### `Store.prototype.load(String data, String mimeType, NamedNode|String? baseIRI, NamedNode|BlankNode|DefaultGraph? toNamedGraph)`
+#### `Store.prototype.load(String data, String format, NamedNode|String? baseIRI, NamedNode|BlankNode|DefaultGraph? toNamedGraph)`
 
 Loads serialized RDF triples or quad into the store.
 The method arguments are:
 1. `data`: the serialized RDF triples or quads.
-2. `mimeType`: the MIME type of the serialization. See below for the supported mime types.
+2. `format`: the format of the serialization. See below for the supported formats.
 3. `baseIRI`: the base IRI to use to resolve the relative IRIs in the serialization.
 4. `toNamedGraph`: for triple serialization formats, the name of the named graph the triple should be loaded to.
 
 The available formats are:
-* [Turtle](https://www.w3.org/TR/turtle/): `text/turtle`
-* [TriG](https://www.w3.org/TR/trig/): `application/trig`
-* [N-Triples](https://www.w3.org/TR/n-triples/): `application/n-triples`
-* [N-Quads](https://www.w3.org/TR/n-quads/): `application/n-quads`
-* [RDF/XML](https://www.w3.org/TR/rdf-syntax-grammar/): `application/rdf+xml`
+* [Turtle](https://www.w3.org/TR/turtle/): `text/turtle` or `ttl`
+* [TriG](https://www.w3.org/TR/trig/): `application/trig` or `trig`
+* [N-Triples](https://www.w3.org/TR/n-triples/): `application/n-triples` or `nt`
+* [N-Quads](https://www.w3.org/TR/n-quads/): `application/n-quads` or `nq`
+* [N3](https://w3c.github.io/N3/spec/): `text/n3` or `n3`
+* [RDF/XML](https://www.w3.org/TR/rdf-syntax-grammar/): `application/rdf+xml` or `rdf`
 
 Example of loading a Turtle file into the named graph `<http://example.com/graph>` with the base IRI `http://example.com`:
 ```js
 store.load("<http://example.com> <http://example.com> <> .", "text/turtle", "http://example.com", oxigraph.namedNode("http://example.com/graph"));
 ```
 
-#### `Store.prototype.dump(String mimeType, NamedNode|BlankNode|DefaultGraph? fromNamedGraph)`
+#### `Store.prototype.dump(String format, NamedNode|BlankNode|DefaultGraph? fromNamedGraph)`
 
 Returns serialized RDF triples or quad from the store.
 The method arguments are:
-1. `mimeType`: the MIME type of the serialization. See below for the supported mime types.
+1. `format`: the format type of the serialization. See below for the supported types.
 2. `fromNamedGraph`: for triple serialization formats, the name of the named graph the triple should be loaded from.
 
 The available formats are:
-* [Turtle](https://www.w3.org/TR/turtle/): `text/turtle`
-* [TriG](https://www.w3.org/TR/trig/): `application/trig`
-* [N-Triples](https://www.w3.org/TR/n-triples/): `application/n-triples`
-* [N-Quads](https://www.w3.org/TR/n-quads/): `application/n-quads`
-* [RDF/XML](https://www.w3.org/TR/rdf-syntax-grammar/): `application/rdf+xml`
+* [Turtle](https://www.w3.org/TR/turtle/): `text/turtle` or `ttl`
+* [TriG](https://www.w3.org/TR/trig/): `application/trig` or `trig`
+* [N-Triples](https://www.w3.org/TR/n-triples/): `application/n-triples` or `nt`
+* [N-Quads](https://www.w3.org/TR/n-quads/): `application/n-quads` or `nq`
+* [N3](https://w3c.github.io/N3/spec/): `text/n3` or `n3`
+* [RDF/XML](https://www.w3.org/TR/rdf-syntax-grammar/): `application/rdf+xml` or `rdf`
 
 Example of building a Turtle file from the named graph `<http://example.com/graph>`:
 ```js
diff --git a/js/src/store.rs b/js/src/store.rs
index bffac273..008f24f0 100644
--- a/js/src/store.rs
+++ b/js/src/store.rs
@@ -144,13 +144,11 @@ impl JsStore {
     pub fn load(
         &self,
         data: &str,
-        mime_type: &str,
+        format: &str,
         base_iri: &JsValue,
         to_graph_name: &JsValue,
     ) -> Result<(), JsValue> {
-        let Some(format) = RdfFormat::from_media_type(mime_type) else {
-            return Err(format_err!("Not supported MIME type: {mime_type}"));
-        };
+        let format = rdf_format(format)?;
         let base_iri = if base_iri.is_null() || base_iri.is_undefined() {
             None
         } else if base_iri.is_string() {
@@ -177,10 +175,8 @@ impl JsStore {
         .map_err(to_err)
     }
 
-    pub fn dump(&self, mime_type: &str, from_graph_name: &JsValue) -> Result<String, JsValue> {
-        let Some(format) = RdfFormat::from_media_type(mime_type) else {
-            return Err(format_err!("Not supported MIME type: {mime_type}"));
-        };
+    pub fn dump(&self, format: &str, from_graph_name: &JsValue) -> Result<String, JsValue> {
+        let format = rdf_format(format)?;
         let buffer =
             if let Some(from_graph_name) = FROM_JS.with(|c| c.to_optional_term(from_graph_name))? {
                 self.store
@@ -192,3 +188,13 @@ impl JsStore {
         String::from_utf8(buffer).map_err(to_err)
     }
 }
+
+fn rdf_format(format: &str) -> Result<RdfFormat, JsValue> {
+    if format.contains('/') {
+        RdfFormat::from_media_type(format)
+            .ok_or_else(|| format_err!("Not supported RDF format media type: {format}"))
+    } else {
+        RdfFormat::from_extension(format)
+            .ok_or_else(|| format_err!("Not supported RDF format extension: {format}"))
+    }
+}
diff --git a/python/src/io.rs b/python/src/io.rs
index 9585dcdc..f365af50 100644
--- a/python/src/io.rs
+++ b/python/src/io.rs
@@ -22,20 +22,21 @@ pub fn add_to_module(module: &PyModule) -> PyResult<()> {
 ///
 /// It currently supports the following formats:
 ///
-/// * `N-Triples <https://www.w3.org/TR/n-triples/>`_ (``application/n-triples``)
-/// * `N-Quads <https://www.w3.org/TR/n-quads/>`_ (``application/n-quads``)
-/// * `Turtle <https://www.w3.org/TR/turtle/>`_ (``text/turtle``)
-/// * `TriG <https://www.w3.org/TR/trig/>`_ (``application/trig``)
-/// * `RDF/XML <https://www.w3.org/TR/rdf-syntax-grammar/>`_ (``application/rdf+xml``)
+/// * `N-Triples <https://www.w3.org/TR/n-triples/>`_ (``application/n-triples`` or ``nt``)
+/// * `N-Quads <https://www.w3.org/TR/n-quads/>`_ (``application/n-quads`` or ``nq``)
+/// * `Turtle <https://www.w3.org/TR/turtle/>`_ (``text/turtle`` or ``ttl``)
+/// * `TriG <https://www.w3.org/TR/trig/>`_ (``application/trig`` or ``trig``)
+/// * `N3 <https://w3c.github.io/N3/spec/>`_ (``text/n3`` or ``n3``)
+/// * `RDF/XML <https://www.w3.org/TR/rdf-syntax-grammar/>`_ (``application/rdf+xml`` or ``rdf``)
 ///
-/// It supports also some MIME type aliases.
+/// It supports also some media type and extension aliases.
 /// For example, ``application/turtle`` could also be used for `Turtle <https://www.w3.org/TR/turtle/>`_
-/// and ``application/xml`` for `RDF/XML <https://www.w3.org/TR/rdf-syntax-grammar/>`_.
+/// and ``application/xml`` or ``xml`` for `RDF/XML <https://www.w3.org/TR/rdf-syntax-grammar/>`_.
 ///
 /// :param input: The binary I/O object or file path to read from. For example, it could be a file path as a string or a file reader opened in binary mode with ``open('my_file.ttl', 'rb')``.
 /// :type input: io(bytes) or io(str) or str or pathlib.Path
-/// :param mime_type: the MIME type of the RDF serialization.
-/// :type mime_type: str
+/// :param format: the format of the RDF serialization using a media type like ``text/turtle`` or an extension like `ttl`.
+/// :type format: str
 /// :param base_iri: the base IRI used to resolve the relative IRIs in the file or :py:const:`None` if relative IRI resolution should not be done.
 /// :type base_iri: str or None, optional
 /// :param without_named_graphs: Sets that the parser must fail if parsing a named graph.
@@ -44,27 +45,23 @@ pub fn add_to_module(module: &PyModule) -> PyResult<()> {
 /// :type rename_blank_nodes: bool, optional
 /// :return: an iterator of RDF triples or quads depending on the format.
 /// :rtype: iterator(Quad)
-/// :raises ValueError: if the MIME type is not supported.
+/// :raises ValueError: if the format is not supported.
 /// :raises SyntaxError: if the provided data is invalid.
 ///
 /// >>> input = io.BytesIO(b'<foo> <p> "1" .')
 /// >>> list(parse(input, "text/turtle", base_iri="http://example.com/"))
 /// [<Quad subject=<NamedNode value=http://example.com/foo> predicate=<NamedNode value=http://example.com/p> object=<Literal value=1 datatype=<NamedNode value=http://www.w3.org/2001/XMLSchema#string>> graph_name=<DefaultGraph>>]
 #[pyfunction]
-#[pyo3(signature = (input, mime_type, *, base_iri = None, without_named_graphs = false, rename_blank_nodes = false))]
+#[pyo3(signature = (input, format, *, base_iri = None, without_named_graphs = false, rename_blank_nodes = false))]
 pub fn parse(
     input: PyObject,
-    mime_type: &str,
+    format: &str,
     base_iri: Option<&str>,
     without_named_graphs: bool,
     rename_blank_nodes: bool,
     py: Python<'_>,
 ) -> PyResult<PyObject> {
-    let Some(format) = RdfFormat::from_media_type(mime_type) else {
-        return Err(PyValueError::new_err(format!(
-            "Not supported MIME type: {mime_type}"
-        )));
-    };
+    let format = rdf_format(format)?;
     let input = if let Ok(path) = input.extract::<PathBuf>(py) {
         PyReadable::from_file(&path, py).map_err(map_io_err)?
     } else {
@@ -92,24 +89,25 @@ pub fn parse(
 ///
 /// It currently supports the following formats:
 ///
-/// * `N-Triples <https://www.w3.org/TR/n-triples/>`_ (``application/n-triples``)
-/// * `N-Quads <https://www.w3.org/TR/n-quads/>`_ (``application/n-quads``)
-/// * `Turtle <https://www.w3.org/TR/turtle/>`_ (``text/turtle``)
-/// * `TriG <https://www.w3.org/TR/trig/>`_ (``application/trig``)
-/// * `RDF/XML <https://www.w3.org/TR/rdf-syntax-grammar/>`_ (``application/rdf+xml``)
+/// * `N-Triples <https://www.w3.org/TR/n-triples/>`_ (``application/n-triples`` or ``nt``)
+/// * `N-Quads <https://www.w3.org/TR/n-quads/>`_ (``application/n-quads`` or ``nq``)
+/// * `Turtle <https://www.w3.org/TR/turtle/>`_ (``text/turtle`` or ``ttl``)
+/// * `TriG <https://www.w3.org/TR/trig/>`_ (``application/trig`` or ``trig``)
+/// * `N3 <https://w3c.github.io/N3/spec/>`_ (``text/n3`` or ``n3``)
+/// * `RDF/XML <https://www.w3.org/TR/rdf-syntax-grammar/>`_ (``application/rdf+xml`` or ``rdf``)
 ///
-/// It supports also some MIME type aliases.
+/// It supports also some media type and extension aliases.
 /// For example, ``application/turtle`` could also be used for `Turtle <https://www.w3.org/TR/turtle/>`_
-/// and ``application/xml`` for `RDF/XML <https://www.w3.org/TR/rdf-syntax-grammar/>`_.
+/// and ``application/xml`` or ``xml`` for `RDF/XML <https://www.w3.org/TR/rdf-syntax-grammar/>`_.
 ///
 /// :param input: the RDF triples and quads to serialize.
 /// :type input: iterable(Triple) or iterable(Quad)
 /// :param output: The binary I/O object or file path to write to. For example, it could be a file path as a string or a file writer opened in binary mode with ``open('my_file.ttl', 'wb')``.
 /// :type output: io(bytes) or str or pathlib.Path
-/// :param mime_type: the MIME type of the RDF serialization.
-/// :type mime_type: str
+/// :param format: the format of the RDF serialization using a media type like ``text/turtle`` or an extension like `ttl`.
+/// :type format: str
 /// :rtype: None
-/// :raises ValueError: if the MIME type is not supported.
+/// :raises ValueError: if the format is not supported.
 /// :raises TypeError: if a triple is given during a quad format serialization or reverse.
 ///
 /// >>> output = io.BytesIO()
@@ -117,12 +115,8 @@ pub fn parse(
 /// >>> output.getvalue()
 /// b'<http://example.com> <http://example.com/p> "1" .\n'
 #[pyfunction]
-pub fn serialize(input: &PyAny, output: PyObject, mime_type: &str, py: Python<'_>) -> PyResult<()> {
-    let Some(format) = RdfFormat::from_media_type(mime_type) else {
-        return Err(PyValueError::new_err(format!(
-            "Not supported MIME type: {mime_type}"
-        )));
-    };
+pub fn serialize(input: &PyAny, output: PyObject, format: &str, py: Python<'_>) -> PyResult<()> {
+    let format = rdf_format(format)?;
     let output = if let Ok(path) = output.extract::<PathBuf>(py) {
         PyWritable::from_file(&path, py).map_err(map_io_err)?
     } else {
@@ -293,6 +287,18 @@ impl Write for PyIo {
     }
 }
 
+pub fn rdf_format(format: &str) -> PyResult<RdfFormat> {
+    if format.contains('/') {
+        RdfFormat::from_media_type(format).ok_or_else(|| {
+            PyValueError::new_err(format!("Not supported RDF format media type: {format}"))
+        })
+    } else {
+        RdfFormat::from_extension(format).ok_or_else(|| {
+            PyValueError::new_err(format!("Not supported RDF format extension: {format}"))
+        })
+    }
+}
+
 fn to_io_err(error: PyErr) -> io::Error {
     io::Error::new(io::ErrorKind::Other, error)
 }
diff --git a/python/src/store.rs b/python/src/store.rs
index da20686a..d71d4936 100644
--- a/python/src/store.rs
+++ b/python/src/store.rs
@@ -1,9 +1,10 @@
 #![allow(clippy::needless_option_as_deref)]
 
-use crate::io::{allow_threads_unsafe, map_io_err, map_parse_error, PyReadable, PyWritable};
+use crate::io::{
+    allow_threads_unsafe, map_io_err, map_parse_error, rdf_format, PyReadable, PyWritable,
+};
 use crate::model::*;
 use crate::sparql::*;
-use oxigraph::io::RdfFormat;
 use oxigraph::model::{GraphName, GraphNameRef};
 use oxigraph::sparql::Update;
 use oxigraph::store::{self, LoaderError, SerializerError, StorageError, Store};
@@ -348,26 +349,27 @@ impl PyStore {
     ///
     /// It currently supports the following formats:
     ///
-    /// * `N-Triples <https://www.w3.org/TR/n-triples/>`_ (``application/n-triples``)
-    /// * `N-Quads <https://www.w3.org/TR/n-quads/>`_ (``application/n-quads``)
-    /// * `Turtle <https://www.w3.org/TR/turtle/>`_ (``text/turtle``)
-    /// * `TriG <https://www.w3.org/TR/trig/>`_ (``application/trig``)
-    /// * `RDF/XML <https://www.w3.org/TR/rdf-syntax-grammar/>`_ (``application/rdf+xml``)
+    /// * `N-Triples <https://www.w3.org/TR/n-triples/>`_ (``application/n-triples`` or ``nt``)
+    /// * `N-Quads <https://www.w3.org/TR/n-quads/>`_ (``application/n-quads`` or ``nq``)
+    /// * `Turtle <https://www.w3.org/TR/turtle/>`_ (``text/turtle`` or ``ttl``)
+    /// * `TriG <https://www.w3.org/TR/trig/>`_ (``application/trig`` or ``trig``)
+    /// * `N3 <https://w3c.github.io/N3/spec/>`_ (``text/n3`` or ``n3``)
+    /// * `RDF/XML <https://www.w3.org/TR/rdf-syntax-grammar/>`_ (``application/rdf+xml`` or ``rdf``)
     ///
-    /// It supports also some MIME type aliases.
+    /// It supports also some media type and extension aliases.
     /// For example, ``application/turtle`` could also be used for `Turtle <https://www.w3.org/TR/turtle/>`_
-    /// and ``application/xml`` for `RDF/XML <https://www.w3.org/TR/rdf-syntax-grammar/>`_.
+    /// and ``application/xml`` or ``xml`` for `RDF/XML <https://www.w3.org/TR/rdf-syntax-grammar/>`_.
     ///
     /// :param input: The binary I/O object or file path to read from. For example, it could be a file path as a string or a file reader opened in binary mode with ``open('my_file.ttl', 'rb')``.
     /// :type input: io(bytes) or io(str) or str or pathlib.Path
-    /// :param mime_type: the MIME type of the RDF serialization.
-    /// :type mime_type: str
+    /// :param format: the format of the RDF serialization using a media type like ``text/turtle`` or an extension like `ttl`.
+    /// :type format: str
     /// :param base_iri: the base IRI used to resolve the relative IRIs in the file or :py:const:`None` if relative IRI resolution should not be done.
     /// :type base_iri: str or None, optional
     /// :param to_graph: if it is a file composed of triples, the graph in which the triples should be stored. By default, the default graph is used.
     /// :type to_graph: NamedNode or BlankNode or DefaultGraph or None, optional
     /// :rtype: None
-    /// :raises ValueError: if the MIME type is not supported.
+    /// :raises ValueError: if the format is not supported.
     /// :raises SyntaxError: if the provided data is invalid.
     /// :raises OSError: if an error happens during a quad insertion.
     ///
@@ -375,20 +377,16 @@ impl PyStore {
     /// >>> store.load(io.BytesIO(b'<foo> <p> "1" .'), "text/turtle", base_iri="http://example.com/", to_graph=NamedNode("http://example.com/g"))
     /// >>> list(store)
     /// [<Quad subject=<NamedNode value=http://example.com/foo> predicate=<NamedNode value=http://example.com/p> object=<Literal value=1 datatype=<NamedNode value=http://www.w3.org/2001/XMLSchema#string>> graph_name=<NamedNode value=http://example.com/g>>]
-    #[pyo3(signature = (input, mime_type, *, base_iri = None, to_graph = None))]
+    #[pyo3(signature = (input, format, *, base_iri = None, to_graph = None))]
     fn load(
         &self,
         input: PyObject,
-        mime_type: &str,
+        format: &str,
         base_iri: Option<&str>,
         to_graph: Option<&PyAny>,
         py: Python<'_>,
     ) -> PyResult<()> {
-        let Some(format) = RdfFormat::from_media_type(mime_type) else {
-            return Err(PyValueError::new_err(format!(
-                "Not supported MIME type: {mime_type}"
-            )));
-        };
+        let format = rdf_format(format)?;
         let to_graph_name = if let Some(graph_name) = to_graph {
             Some(GraphName::from(&PyGraphNameRef::try_from(graph_name)?))
         } else {
@@ -419,26 +417,27 @@ impl PyStore {
     ///
     /// It currently supports the following formats:
     ///
-    /// * `N-Triples <https://www.w3.org/TR/n-triples/>`_ (``application/n-triples``)
-    /// * `N-Quads <https://www.w3.org/TR/n-quads/>`_ (``application/n-quads``)
-    /// * `Turtle <https://www.w3.org/TR/turtle/>`_ (``text/turtle``)
-    /// * `TriG <https://www.w3.org/TR/trig/>`_ (``application/trig``)
-    /// * `RDF/XML <https://www.w3.org/TR/rdf-syntax-grammar/>`_ (``application/rdf+xml``)
+    /// * `N-Triples <https://www.w3.org/TR/n-triples/>`_ (``application/n-triples`` or ``nt``)
+    /// * `N-Quads <https://www.w3.org/TR/n-quads/>`_ (``application/n-quads`` or ``nq``)
+    /// * `Turtle <https://www.w3.org/TR/turtle/>`_ (``text/turtle`` or ``ttl``)
+    /// * `TriG <https://www.w3.org/TR/trig/>`_ (``application/trig`` or ``trig``)
+    /// * `N3 <https://w3c.github.io/N3/spec/>`_ (``text/n3`` or ``n3``)
+    /// * `RDF/XML <https://www.w3.org/TR/rdf-syntax-grammar/>`_ (``application/rdf+xml`` or ``rdf``)
     ///
-    /// It supports also some MIME type aliases.
+    /// It supports also some media type and extension aliases.
     /// For example, ``application/turtle`` could also be used for `Turtle <https://www.w3.org/TR/turtle/>`_
-    /// and ``application/xml`` for `RDF/XML <https://www.w3.org/TR/rdf-syntax-grammar/>`_.
+    /// and ``application/xml`` or ``xml`` for `RDF/XML <https://www.w3.org/TR/rdf-syntax-grammar/>`_.
     ///
     /// :param input: The binary I/O object or file path to read from. For example, it could be a file path as a string or a file reader opened in binary mode with ``open('my_file.ttl', 'rb')``.
     /// :type input: io(bytes) or io(str) or str or pathlib.Path
-    /// :param mime_type: the MIME type of the RDF serialization.
-    /// :type mime_type: str
+    /// :param format: the format of the RDF serialization using a media type like ``text/turtle`` or an extension like `ttl`.
+    /// :type format: str
     /// :param base_iri: the base IRI used to resolve the relative IRIs in the file or :py:const:`None` if relative IRI resolution should not be done.
     /// :type base_iri: str or None, optional
     /// :param to_graph: if it is a file composed of triples, the graph in which the triples should be stored. By default, the default graph is used.
     /// :type to_graph: NamedNode or BlankNode or DefaultGraph or None, optional
     /// :rtype: None
-    /// :raises ValueError: if the MIME type is not supported.
+    /// :raises ValueError: if the format is not supported.
     /// :raises SyntaxError: if the provided data is invalid.
     /// :raises OSError: if an error happens during a quad insertion.
     ///
@@ -446,20 +445,16 @@ impl PyStore {
     /// >>> store.bulk_load(io.BytesIO(b'<foo> <p> "1" .'), "text/turtle", base_iri="http://example.com/", to_graph=NamedNode("http://example.com/g"))
     /// >>> list(store)
     /// [<Quad subject=<NamedNode value=http://example.com/foo> predicate=<NamedNode value=http://example.com/p> object=<Literal value=1 datatype=<NamedNode value=http://www.w3.org/2001/XMLSchema#string>> graph_name=<NamedNode value=http://example.com/g>>]
-    #[pyo3(signature = (input, mime_type, *, base_iri = None, to_graph = None))]
+    #[pyo3(signature = (input, format, *, base_iri = None, to_graph = None))]
     fn bulk_load(
         &self,
         input: PyObject,
-        mime_type: &str,
+        format: &str,
         base_iri: Option<&str>,
         to_graph: Option<&PyAny>,
         py: Python<'_>,
     ) -> PyResult<()> {
-        let Some(format) = RdfFormat::from_media_type(mime_type) else {
-            return Err(PyValueError::new_err(format!(
-                "Not supported MIME type: {mime_type}"
-            )));
-        };
+        let format = rdf_format(format)?;
         let to_graph_name = if let Some(graph_name) = to_graph {
             Some(GraphName::from(&PyGraphNameRef::try_from(graph_name)?))
         } else {
@@ -488,24 +483,25 @@ impl PyStore {
     ///
     /// It currently supports the following formats:
     ///
-    /// * `N-Triples <https://www.w3.org/TR/n-triples/>`_ (``application/n-triples``)
-    /// * `N-Quads <https://www.w3.org/TR/n-quads/>`_ (``application/n-quads``)
-    /// * `Turtle <https://www.w3.org/TR/turtle/>`_ (``text/turtle``)
-    /// * `TriG <https://www.w3.org/TR/trig/>`_ (``application/trig``)
-    /// * `RDF/XML <https://www.w3.org/TR/rdf-syntax-grammar/>`_ (``application/rdf+xml``)
+    /// * `N-Triples <https://www.w3.org/TR/n-triples/>`_ (``application/n-triples`` or ``nt``)
+    /// * `N-Quads <https://www.w3.org/TR/n-quads/>`_ (``application/n-quads`` or ``nq``)
+    /// * `Turtle <https://www.w3.org/TR/turtle/>`_ (``text/turtle`` or ``ttl``)
+    /// * `TriG <https://www.w3.org/TR/trig/>`_ (``application/trig`` or ``trig``)
+    /// * `N3 <https://w3c.github.io/N3/spec/>`_ (``text/n3`` or ``n3``)
+    /// * `RDF/XML <https://www.w3.org/TR/rdf-syntax-grammar/>`_ (``application/rdf+xml`` or ``rdf``)
     ///
-    /// It supports also some MIME type aliases.
+    /// It supports also some media type and extension aliases.
     /// For example, ``application/turtle`` could also be used for `Turtle <https://www.w3.org/TR/turtle/>`_
-    /// and ``application/xml`` for `RDF/XML <https://www.w3.org/TR/rdf-syntax-grammar/>`_.
+    /// and ``application/xml`` or ``xml`` for `RDF/XML <https://www.w3.org/TR/rdf-syntax-grammar/>`_.
     ///
     /// :param output: The binary I/O object or file path to write to. For example, it could be a file path as a string or a file writer opened in binary mode with ``open('my_file.ttl', 'wb')``.
     /// :type output: io(bytes) or str or pathlib.Path
-    /// :param mime_type: the MIME type of the RDF serialization.
-    /// :type mime_type: str
+    /// :param format: the format of the RDF serialization using a media type like ``text/turtle`` or an extension like `ttl`.
+    /// :type format: str
     /// :param from_graph: the store graph from which dump the triples. Required if the serialization format does not support named graphs. If it does supports named graphs the full dataset is written.
     /// :type from_graph: NamedNode or BlankNode or DefaultGraph or None, optional
     /// :rtype: None
-    /// :raises ValueError: if the MIME type is not supported or the `from_graph` parameter is not given with a syntax not supporting named graphs.
+    /// :raises ValueError: if the format is not supported or the `from_graph` parameter is not given with a syntax not supporting named graphs.
     /// :raises OSError: if an error happens during a quad lookup
     ///
     /// >>> store = Store()
@@ -514,19 +510,15 @@ impl PyStore {
     /// >>> store.dump(output, "text/turtle", from_graph=NamedNode("http://example.com/g"))
     /// >>> output.getvalue()
     /// b'<http://example.com> <http://example.com/p> "1" .\n'
-    #[pyo3(signature = (output, mime_type, *, from_graph = None))]
+    #[pyo3(signature = (output, format, *, from_graph = None))]
     fn dump(
         &self,
         output: PyObject,
-        mime_type: &str,
+        format: &str,
         from_graph: Option<&PyAny>,
         py: Python<'_>,
     ) -> PyResult<()> {
-        let Some(format) = RdfFormat::from_media_type(mime_type) else {
-            return Err(PyValueError::new_err(format!(
-                "Not supported MIME type: {mime_type}"
-            )));
-        };
+        let format = rdf_format(format)?;
         let from_graph_name = if let Some(graph_name) = from_graph {
             Some(GraphName::from(&PyGraphNameRef::try_from(graph_name)?))
         } else {
diff --git a/python/tests/test_io.py b/python/tests/test_io.py
index d3f535c4..e9069e08 100644
--- a/python/tests/test_io.py
+++ b/python/tests/test_io.py
@@ -69,7 +69,7 @@ class TestParse(unittest.TestCase):
 
     def test_parse_io_error(self) -> None:
         with self.assertRaises(UnsupportedOperation) as _, TemporaryFile("wb") as fp:
-            list(parse(fp, mime_type="application/n-triples"))
+            list(parse(fp, "nt"))
 
     def test_parse_quad(self) -> None:
         self.assertEqual(
diff --git a/python/tests/test_store.py b/python/tests/test_store.py
index ee02e830..a3ed8fe0 100644
--- a/python/tests/test_store.py
+++ b/python/tests/test_store.py
@@ -225,7 +225,7 @@ class TestStore(unittest.TestCase):
         store = Store()
         store.load(
             BytesIO(b"<http://foo> <http://bar> <http://baz> ."),
-            mime_type="application/n-triples",
+            "application/n-triples",
         )
         self.assertEqual(set(store), {Quad(foo, bar, baz, DefaultGraph())})
 
@@ -233,7 +233,7 @@ class TestStore(unittest.TestCase):
         store = Store()
         store.load(
             BytesIO(b"<http://foo> <http://bar> <http://baz> ."),
-            mime_type="application/n-triples",
+            "application/n-triples",
             to_graph=graph,
         )
         self.assertEqual(set(store), {Quad(foo, bar, baz, graph)})
@@ -242,7 +242,7 @@ class TestStore(unittest.TestCase):
         store = Store()
         store.load(
             BytesIO(b"<http://foo> <http://bar> <> ."),
-            mime_type="text/turtle",
+            "text/turtle",
             base_iri="http://baz",
         )
         self.assertEqual(set(store), {Quad(foo, bar, baz, DefaultGraph())})
@@ -251,7 +251,7 @@ class TestStore(unittest.TestCase):
         store = Store()
         store.load(
             BytesIO(b"<http://foo> <http://bar> <http://baz> <http://graph>."),
-            mime_type="application/n-quads",
+            "nq",
         )
         self.assertEqual(set(store), {Quad(foo, bar, baz, graph)})
 
@@ -259,7 +259,7 @@ class TestStore(unittest.TestCase):
         store = Store()
         store.load(
             BytesIO(b"<http://graph> { <http://foo> <http://bar> <> . }"),
-            mime_type="application/trig",
+            "application/trig",
             base_iri="http://baz",
         )
         self.assertEqual(set(store), {Quad(foo, bar, baz, graph)})
@@ -269,13 +269,13 @@ class TestStore(unittest.TestCase):
             file_name = Path(fp.name)
             fp.write(b"<http://foo> <http://bar> <http://baz> <http://graph>.")
         store = Store()
-        store.load(file_name, mime_type="application/n-quads")
+        store.load(file_name, "nq")
         file_name.unlink()
         self.assertEqual(set(store), {Quad(foo, bar, baz, graph)})
 
     def test_load_with_io_error(self) -> None:
         with self.assertRaises(UnsupportedOperation) as _, TemporaryFile("wb") as fp:
-            Store().load(fp, mime_type="application/n-triples")
+            Store().load(fp, "application/n-triples")
 
     def test_dump_ntriples(self) -> None:
         store = Store()
@@ -291,7 +291,7 @@ class TestStore(unittest.TestCase):
         store = Store()
         store.add(Quad(foo, bar, baz, graph))
         output = BytesIO()
-        store.dump(output, "application/n-quads")
+        store.dump(output, "nq")
         self.assertEqual(
             output.getvalue(),
             b"<http://foo> <http://bar> <http://baz> <http://graph> .\n",
@@ -314,7 +314,7 @@ class TestStore(unittest.TestCase):
             file_name = Path(fp.name)
         store = Store()
         store.add(Quad(foo, bar, baz, graph))
-        store.dump(file_name, "application/n-quads")
+        store.dump(file_name, "nq")
         self.assertEqual(
             file_name.read_text(),
             "<http://foo> <http://bar> <http://baz> <http://graph> .\n",
@@ -324,7 +324,7 @@ class TestStore(unittest.TestCase):
         store = Store()
         store.add(Quad(foo, bar, bar))
         with self.assertRaises(OSError) as _, TemporaryFile("rb") as fp:
-            store.dump(fp, mime_type="application/trig")
+            store.dump(fp, "application/trig")
 
     def test_write_in_read(self) -> None:
         store = Store()