summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md3
-rw-r--r--adblock/__init__.py29
-rw-r--r--adblock/adblock.pyi21
-rw-r--r--src/lib.rs40
-rw-r--r--tests/test_engine.py11
-rw-r--r--tests/test_exceptions.py10
-rw-r--r--tests/test_imports.py6
7 files changed, 112 insertions, 8 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 245a88a..a62516d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,9 @@ This project adheres to [Semantic Versioning](http://semver.org/) and [Keep a Ch
5 5
6## Unreleased 6## Unreleased
7--- 7---
8### Breaks
9* Library now throws the custom `adblock.AdblockException` exception, instead of `ValueError`.
10
8 11
9## 0.4.4 - (2021-04-13) 12## 0.4.4 - (2021-04-13)
10--- 13---
diff --git a/adblock/__init__.py b/adblock/__init__.py
index 0cc1876..85d3614 100644
--- a/adblock/__init__.py
+++ b/adblock/__init__.py
@@ -1,4 +1,29 @@
1from adblock.adblock import __version__, Engine, FilterSet, BlockerResult, UrlSpecificResources 1from adblock.adblock import (
2 __version__,
3 Engine,
4 FilterSet,
5 BlockerResult,
6 UrlSpecificResources,
7 AdblockException,
8 BlockerException,
9 SerializationError,
10 DeserializationError,
11 OptimizedFilterExistence,
12 BadFilterAddUnsupported,
13 FilterExists,
14)
2 15
3 16
4__all__ = ("Engine", "FilterSet", "BlockerResult", "UrlSpecificResources") 17__all__ = (
18 "Engine",
19 "FilterSet",
20 "BlockerResult",
21 "UrlSpecificResources",
22 "AdblockException",
23 "BlockerException",
24 "SerializationError",
25 "DeserializationError",
26 "OptimizedFilterExistence",
27 "BadFilterAddUnsupported",
28 "FilterExists",
29)
diff --git a/adblock/adblock.pyi b/adblock/adblock.pyi
index d977629..0515674 100644
--- a/adblock/adblock.pyi
+++ b/adblock/adblock.pyi
@@ -1,5 +1,26 @@
1from typing import Optional, Dict, List, Set 1from typing import Optional, Dict, List, Set
2 2
3class AdblockException(Exception):
4 pass
5
6class BlockerException(AdblockException):
7 pass
8
9class SerializationError(BlockerException):
10 pass
11
12class DeserializationError(BlockerException):
13 pass
14
15class OptimizedFilterExistence(BlockerException):
16 pass
17
18class BadFilterAddUnsupported(BlockerException):
19 pass
20
21class FilterExists(BlockerException):
22 pass
23
3class BlockerResult: 24class BlockerResult:
4 matched: bool 25 matched: bool
5 explicit_cancel: bool 26 explicit_cancel: bool
diff --git a/src/lib.rs b/src/lib.rs
index 54031dd..172f025 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -17,7 +17,8 @@ use adblock::engine::Engine as RustEngine;
17use adblock::lists::FilterFormat; 17use adblock::lists::FilterFormat;
18use adblock::lists::FilterSet as RustFilterSet; 18use adblock::lists::FilterSet as RustFilterSet;
19use pyo3::class::PyObjectProtocol; 19use pyo3::class::PyObjectProtocol;
20use pyo3::exceptions::PyValueError; 20use pyo3::create_exception;
21use pyo3::exceptions::PyException;
21use pyo3::prelude::*; 22use pyo3::prelude::*;
22use pyo3::types::PyBytes; 23use pyo3::types::PyBytes;
23use pyo3::PyErr; 24use pyo3::PyErr;
@@ -31,12 +32,28 @@ use std::io::{Read, Write};
31 32
32/// Brave's adblocking library in Python! 33/// Brave's adblocking library in Python!
33#[pymodule] 34#[pymodule]
34fn adblock(_py: Python<'_>, m: &PyModule) -> PyResult<()> { 35fn adblock(py: Python<'_>, m: &PyModule) -> PyResult<()> {
35 m.add("__version__", env!("CARGO_PKG_VERSION"))?; 36 m.add("__version__", env!("CARGO_PKG_VERSION"))?;
36 m.add_class::<Engine>()?; 37 m.add_class::<Engine>()?;
37 m.add_class::<FilterSet>()?; 38 m.add_class::<FilterSet>()?;
38 m.add_class::<BlockerResult>()?; 39 m.add_class::<BlockerResult>()?;
39 m.add_class::<UrlSpecificResources>()?; 40 m.add_class::<UrlSpecificResources>()?;
41 m.add("AdblockException", py.get_type::<AdblockException>())?;
42 m.add("BlockerException", py.get_type::<BlockerException>())?;
43 m.add("SerializationError", py.get_type::<SerializationError>())?;
44 m.add(
45 "DeserializationError",
46 py.get_type::<DeserializationError>(),
47 )?;
48 m.add(
49 "OptimizedFilterExistence",
50 py.get_type::<OptimizedFilterExistence>(),
51 )?;
52 m.add(
53 "BadFilterAddUnsupported",
54 py.get_type::<BadFilterAddUnsupported>(),
55 )?;
56 m.add("FilterExists", py.get_type::<FilterExists>())?;
40 Ok(()) 57 Ok(())
41} 58}
42 59
@@ -141,9 +158,24 @@ impl Display for BlockerError {
141 } 158 }
142} 159}
143 160
161create_exception!(adblock, AdblockException, PyException);
162create_exception!(adblock, BlockerException, AdblockException);
163create_exception!(adblock, SerializationError, BlockerException);
164create_exception!(adblock, DeserializationError, BlockerException);
165create_exception!(adblock, OptimizedFilterExistence, BlockerException);
166create_exception!(adblock, BadFilterAddUnsupported, BlockerException);
167create_exception!(adblock, FilterExists, BlockerException);
168
144impl Into<PyErr> for BlockerError { 169impl Into<PyErr> for BlockerError {
145 fn into(self) -> PyErr { 170 fn into(self) -> PyErr {
146 PyErr::new::<PyValueError, _>(format!("{:?}", self)) 171 let msg = format!("{:?}", self);
172 match self {
173 Self::SerializationError => PyErr::new::<SerializationError, _>(msg),
174 Self::DeserializationError => PyErr::new::<DeserializationError, _>(msg),
175 Self::OptimizedFilterExistence => PyErr::new::<OptimizedFilterExistence, _>(msg),
176 Self::BadFilterAddUnsupported => PyErr::new::<BadFilterAddUnsupported, _>(msg),
177 Self::FilterExists => PyErr::new::<FilterExists, _>(msg),
178 }
147 } 179 }
148} 180}
149 181
@@ -163,7 +195,7 @@ fn filter_format_from_string(filter_format: &str) -> PyResult<FilterFormat> {
163 match filter_format { 195 match filter_format {
164 "standard" => Ok(FilterFormat::Standard), 196 "standard" => Ok(FilterFormat::Standard),
165 "hosts" => Ok(FilterFormat::Hosts), 197 "hosts" => Ok(FilterFormat::Hosts),
166 _ => Err(PyErr::new::<PyValueError, _>("Invalid format value")), 198 _ => Err(PyErr::new::<AdblockException, _>("Invalid format value")),
167 } 199 }
168} 200}
169 201
diff --git a/tests/test_engine.py b/tests/test_engine.py
index a3d2898..8a7421c 100644
--- a/tests/test_engine.py
+++ b/tests/test_engine.py
@@ -52,6 +52,17 @@ def test_serde_file(tmpdir):
52 assert deserialization_result is None 52 assert deserialization_result is None
53 53
54 54
55def test_deserialize_corrupt(tmpdir):
56 path = str(tmpdir / "corrupt_cache.dat")
57 with open(path, "w", encoding="utf-8") as f:
58 f.write("abc")
59
60 engine = empty_engine()
61 with pytest.raises(adblock.DeserializationError):
62 engine.deserialize_from_file(path)
63 with pytest.raises(adblock.DeserializationError):
64 engine.deserialize(b"abc")
65
55def test_serde(): 66def test_serde():
56 engine = empty_engine() 67 engine = empty_engine()
57 serialization_result = engine.serialize() 68 serialization_result = engine.serialize()
diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py
new file mode 100644
index 0000000..497b3ef
--- /dev/null
+++ b/tests/test_exceptions.py
@@ -0,0 +1,10 @@
1import adblock
2
3def test_correct_baseclasses():
4 assert issubclass(adblock.AdblockException, Exception)
5 assert issubclass(adblock.BlockerException, adblock.AdblockException)
6 assert issubclass(adblock.SerializationError, adblock.BlockerException)
7 assert issubclass(adblock.DeserializationError, adblock.BlockerException)
8 assert issubclass(adblock.OptimizedFilterExistence, adblock.BlockerException)
9 assert issubclass(adblock.BadFilterAddUnsupported, adblock.BlockerException)
10 assert issubclass(adblock.FilterExists, adblock.BlockerException) \ No newline at end of file
diff --git a/tests/test_imports.py b/tests/test_imports.py
index 7692483..09ef5d5 100644
--- a/tests/test_imports.py
+++ b/tests/test_imports.py
@@ -14,16 +14,18 @@ def get_added_classes():
14 match = re.match(r"m\.add_class::<(.+)>\(\)\?;", line.strip()) 14 match = re.match(r"m\.add_class::<(.+)>\(\)\?;", line.strip())
15 if match is not None: 15 if match is not None:
16 classes.append(match.group(1)) 16 classes.append(match.group(1))
17 continue
17 return classes 18 return classes
18 19
19 20
20def test_added_classes(): 21def test_added_classes():
21 """ 22 """
22 Make sure that there's no class that we added in Rust but didn't import in 23 Make sure that there's no class that we added in Rust but didn't import in
23 `__init__.py` and vice versa. 24 `__init__.py`.
24 """ 25 """
25 added_classes = get_added_classes() 26 added_classes = get_added_classes()
26 assert added_classes == list(adblock.__all__) 27 for c in added_classes:
28 assert c in adblock.__all__
27 29
28 30
29def test_dunder_all_classes_imported(): 31def test_dunder_all_classes_imported():