Skip to content

Commit 5b717ce

Browse files
KhoyoTristramg
authored andcommitted
Add callbacks instead of printing to stdout when a data issue is found
This is useful for osrd-data, where such issues are usually reported through the errdb mechanism, allowing more precise statistics. Signed-off-by: Younes Khoudli <younes.khoudli@epita.fr>
1 parent e02a6b5 commit 5b717ce

7 files changed

Lines changed: 130 additions & 15 deletions

File tree

python/liblrs_python.pyi

Lines changed: 4 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

python/src/lib.rs

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ fn liblrs_python(_py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> {
2727
m.add_class::<AnchorOnLrm>()?;
2828
m.add_class::<SegmentOfTraversal>()?;
2929
m.add_class::<Builder>()?;
30+
m.add_class::<DataIssueReporter>()?;
3031
Ok(())
3132
}
3233

@@ -576,15 +577,22 @@ impl Builder {
576577
/// Read the topology from an OpenStreetMap source
577578
///
578579
/// It reads the nodes, segments and traversals.
579-
pub fn read_from_osm(
580+
pub fn read_from_osm<'py>(
580581
&mut self,
581582
input_osm_file: PathBuf,
582583
lrm_tag: String,
583584
required: Vec<(String, String)>,
584585
to_reject: Vec<(String, String)>,
586+
reporter: Bound<'py, DataIssueReporter>,
585587
) {
586-
self.inner
587-
.read_from_osm(&input_osm_file, &lrm_tag, required, to_reject)
588+
let mut reporter = PythonDataIssueReporter(reporter);
589+
self.inner.read_from_osm(
590+
&input_osm_file,
591+
&lrm_tag,
592+
required,
593+
to_reject,
594+
Some(&mut reporter),
595+
)
588596
}
589597

590598
/// Save the lrs to a file
@@ -656,3 +664,52 @@ impl Builder {
656664
}
657665

658666
define_stub_info_gatherer!(stub_info);
667+
668+
#[gen_stub_pyclass]
669+
#[pyclass(subclass)]
670+
struct DataIssueReporter {}
671+
672+
#[pymethods]
673+
impl DataIssueReporter {
674+
#[new]
675+
fn new() -> Self {
676+
Self {}
677+
}
678+
}
679+
680+
#[allow(unused_variables)]
681+
#[gen_stub_pymethods]
682+
impl liblrs::DataIssueReporter for DataIssueReporter {
683+
fn report_ignoring_traversal_edges(
684+
&mut self,
685+
traversal_ref: &str,
686+
ignored_count: usize,
687+
total_count: usize,
688+
first_node: i64,
689+
last_node: i64,
690+
) {
691+
}
692+
}
693+
694+
struct PythonDataIssueReporter<'a>(Bound<'a, DataIssueReporter>);
695+
impl liblrs::DataIssueReporter for PythonDataIssueReporter<'_> {
696+
fn report_ignoring_traversal_edges(
697+
&mut self,
698+
traversal_ref: &str,
699+
ignored_count: usize,
700+
total_count: usize,
701+
first_node: i64,
702+
last_node: i64,
703+
) {
704+
let _ = self.0.call_method1(
705+
"report_ignoring_traversal_edges",
706+
(
707+
traversal_ref,
708+
ignored_count,
709+
total_count,
710+
first_node,
711+
last_node,
712+
),
713+
);
714+
}
715+
}

src/builder.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use crate::lrs::Properties;
1313
use crate::lrs_ext::ExtLrs;
1414
use crate::lrs_generated::{self, *};
1515
use crate::osm_helpers::sort_edges;
16-
use crate::properties;
16+
use crate::{DataIssueReporter, properties};
1717

1818
/// The linear position of an [`Anchor`] doesn’t always match the measured distance.
1919
/// For example if a road was transformed into a bypass, resulting in a longer road,
@@ -436,7 +436,10 @@ impl<'fbb> Builder<'fbb> {
436436
lrm_tag: &str,
437437
required: Vec<(String, String)>,
438438
to_reject: Vec<(String, String)>,
439+
reporter: Option<&mut dyn DataIssueReporter>,
439440
) {
441+
let mut default_reporter = ();
442+
let reporter = reporter.unwrap_or(&mut default_reporter);
440443
let mut reader = osm4routing::Reader::new().merge_ways().read_tag(lrm_tag);
441444

442445
for (key, value) in required.iter() {
@@ -479,7 +482,7 @@ impl<'fbb> Builder<'fbb> {
479482

480483
// Sort the traversals
481484
for (srv_ref, edges) in traversals.into_iter() {
482-
let segments: Vec<_> = sort_edges(edges, &srv_ref)
485+
let segments: Vec<_> = sort_edges(edges, &srv_ref, reporter)
483486
.into_iter()
484487
.map(|(edge, reversed)| SegmentOfTraversal {
485488
segment_index: edges_map[&edge.id],

src/geometry_from_osm.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ fn main() {
4444
&cli_args.lrm_tag,
4545
required,
4646
to_reject,
47+
Some(&mut liblrs::LoggingDataIssueReporter),
4748
);
4849

4950
builder.save(

src/lib.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,46 @@ pub mod lrs_ext;
2121
#[deny(missing_docs)]
2222
pub mod builder;
2323

24+
pub trait DataIssueReporter {
25+
fn report_ignoring_traversal_edges(
26+
&mut self,
27+
traversal_ref: &str,
28+
ignored_count: usize,
29+
total_count: usize,
30+
first_node: i64,
31+
last_node: i64,
32+
);
33+
}
34+
35+
pub struct LoggingDataIssueReporter;
36+
37+
impl DataIssueReporter for LoggingDataIssueReporter {
38+
fn report_ignoring_traversal_edges(
39+
&mut self,
40+
traversal_ref: &str,
41+
ignored_count: usize,
42+
total_count: usize,
43+
first_node: i64,
44+
last_node: i64,
45+
) {
46+
println!(
47+
"[WARN] on traversal {traversal_ref}, ignoring {ignored_count} edges out of {total_count}. Sorted from {first_node} to {last_node}"
48+
);
49+
}
50+
}
51+
52+
impl DataIssueReporter for () {
53+
fn report_ignoring_traversal_edges(
54+
&mut self,
55+
_traversal_ref: &str,
56+
_ignored_count: usize,
57+
_total_count: usize,
58+
_first_node: i64,
59+
_last_node: i64,
60+
) {
61+
}
62+
}
63+
2464
#[test]
2565
fn read_and_write_lrs() {
2666
use builder::*;

src/lrs.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -711,7 +711,7 @@ mod tests {
711711
use approx::assert_relative_eq;
712712
use geo::line_string;
713713

714-
use crate::{curves::PlanarLineStringCurve, properties};
714+
use crate::curves::PlanarLineStringCurve;
715715

716716
use super::*;
717717

src/osm_helpers.rs

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
44
use osm4routing::Edge;
55

6+
use crate::DataIssueReporter;
7+
68
/// When sorting the edges, each candidate is tested to see if they match and if they need to be reversed.
79
#[derive(PartialEq, Eq, Debug)]
810
enum Candidate {
@@ -79,7 +81,11 @@ fn sort_iteration(
7981
/// The traversals are identified by a tag that is used on many ways.
8082
/// We try to build the longest continous chain of ways, but the is no guarantee to succeed.
8183
/// The ways might not share nodes or they might represent a tree.
82-
pub fn sort_edges(edges: Vec<Edge>, traversal_ref: &str) -> Vec<(Edge, bool)> {
84+
pub fn sort_edges(
85+
edges: Vec<Edge>,
86+
traversal_ref: &str,
87+
reporter: &mut dyn DataIssueReporter,
88+
) -> Vec<(Edge, bool)> {
8389
let (to_insert, sorted) = sort_iteration(edges, vec![]);
8490

8591
// Print some stats about edges that could not be matched
@@ -98,10 +104,7 @@ pub fn sort_edges(edges: Vec<Edge>, traversal_ref: &str) -> Vec<(Edge, bool)> {
98104
} else {
99105
last_edge.0.target
100106
};
101-
println!(
102-
"[WARN] on traversal {traversal_ref}, ignoring {ignored} edges out of {total}. Sorted from {} to {}",
103-
first.0, last.0
104-
);
107+
reporter.report_ignoring_traversal_edges(traversal_ref, ignored, total, first.0, last.0);
105108
}
106109

107110
sorted
@@ -170,7 +173,7 @@ pub mod tests {
170173
fn sort_edges_simple() {
171174
let e = edge(0, 1);
172175

173-
let sorted = sort_edges(vec![e.clone()], "");
176+
let sorted = sort_edges(vec![e.clone()], "", &mut crate::LoggingDataIssueReporter);
174177
assert_eq!(sorted[0].0, e);
175178
assert!(!sorted[0].1);
176179
}
@@ -180,7 +183,11 @@ pub mod tests {
180183
let e1 = edge(0, 1);
181184
let e2 = edge(1, 2);
182185

183-
let sorted = sort_edges(vec![e1.clone(), e2.clone()], "");
186+
let sorted = sort_edges(
187+
vec![e1.clone(), e2.clone()],
188+
"",
189+
&mut crate::LoggingDataIssueReporter,
190+
);
184191
assert_eq!(sorted[0].0, e1);
185192
assert_eq!(sorted[1].0, e2);
186193
assert!(!sorted[0].1);
@@ -192,7 +199,11 @@ pub mod tests {
192199
let e1 = edge(1, 0);
193200
let e2 = edge(1, 2);
194201

195-
let sorted = sort_edges(vec![e1.clone(), e2.clone()], "");
202+
let sorted = sort_edges(
203+
vec![e1.clone(), e2.clone()],
204+
"",
205+
&mut crate::LoggingDataIssueReporter,
206+
);
196207
assert_eq!(sorted[0].0, e1);
197208
assert_eq!(sorted[1].0, e2);
198209
assert!(sorted[0].1);

0 commit comments

Comments
 (0)