-
Notifications
You must be signed in to change notification settings - Fork 31
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge remote-tracking branch 'origin/master' into netex-validation/po…
…lling-of-results
- Loading branch information
Showing
17 changed files
with
795 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
defmodule Transport.IRVE.DataFrame do | ||
@moduledoc """ | ||
Tooling supporting the parsing of an IRVE static file into `Explorer.DataFrame` | ||
""" | ||
|
||
@doc """ | ||
Helper function to convert TableSchema types into DataFrame ones. | ||
There is no attempt to make this generic at this point, it is focusing solely | ||
on the static IRVE use. | ||
iex> Transport.IRVE.DataFrame.remap_schema_type(:geopoint) | ||
:string | ||
iex> Transport.IRVE.DataFrame.remap_schema_type(:number) | ||
{:u, 16} | ||
iex> Transport.IRVE.DataFrame.remap_schema_type(:literally_anything) | ||
:literally_anything | ||
""" | ||
def remap_schema_type(input_type) do | ||
case input_type do | ||
:geopoint -> :string | ||
:number -> {:u, 16} | ||
type -> type | ||
end | ||
end | ||
|
||
@doc """ | ||
Parse an in-memory binary of CSV content into a typed `Explorer.DataFrame` for IRVE use. | ||
Current behaviour is that the embedded static IRVE schema enforces the field type, for fields | ||
that are known. | ||
For instance, a `string` field in the input schema will be considered as a `string` in the `DataFrame`: | ||
iex> Transport.IRVE.DataFrame.dataframe_from_csv_body!("id_pdc_itinerance\\nABC123") | ||
#Explorer.DataFrame< | ||
Polars[1 x 1] | ||
id_pdc_itinerance string ["ABC123"] | ||
> | ||
Even if it contains something that would be considered a float (the schema type spec wins): | ||
iex> Transport.IRVE.DataFrame.dataframe_from_csv_body!("id_pdc_itinerance\\n22.0") | ||
#Explorer.DataFrame< | ||
Polars[1 x 1] | ||
id_pdc_itinerance string ["22.0"] | ||
> | ||
An `integer` field will be mapped to a `integer` (here, signed 64-bits): | ||
iex> Transport.IRVE.DataFrame.dataframe_from_csv_body!("nbre_pdc\\n123") | ||
#Explorer.DataFrame< | ||
Polars[1 x 1] | ||
nbre_pdc s64 [123] | ||
> | ||
A `boolean` field in the schema, similary, will correctly result into a `boolean` `DataFrame` field: | ||
iex> Transport.IRVE.DataFrame.dataframe_from_csv_body!("reservation\\nfalse") | ||
#Explorer.DataFrame< | ||
Polars[1 x 1] | ||
reservation boolean [false] | ||
> | ||
And dates are also handled correctly: | ||
iex> Transport.IRVE.DataFrame.dataframe_from_csv_body!("date_mise_en_service\\n2024-10-02") | ||
#Explorer.DataFrame< | ||
Polars[1 x 1] | ||
date_mise_en_service date [2024-10-02] | ||
> | ||
Other, unknown columns, are at this point kept, and types are inferred: | ||
iex> Transport.IRVE.DataFrame.dataframe_from_csv_body!("foo,bar\\n123,14.0") | ||
#Explorer.DataFrame< | ||
Polars[1 x 2] | ||
foo s64 [123] | ||
bar f64 [14.0] | ||
> | ||
Congratulations for reading this far. | ||
""" | ||
def dataframe_from_csv_body!(body, schema \\ Transport.IRVE.StaticIRVESchema.schema_content()) do | ||
dtypes = | ||
schema | ||
|> Map.fetch!("fields") | ||
|> Enum.map(fn %{"name" => name, "type" => type} -> | ||
{ | ||
String.to_atom(name), | ||
String.to_atom(type) | ||
|> Transport.IRVE.DataFrame.remap_schema_type() | ||
} | ||
end) | ||
|
||
Explorer.DataFrame.load_csv!(body, dtypes: dtypes) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
defmodule Transport.IRVE.StaticIRVESchema do | ||
@moduledoc """ | ||
A module providing programmatic access to the static IRVE schema, | ||
as stored in the source code. | ||
""" | ||
|
||
@doc """ | ||
Read & decode the content of the IRVE static schema. | ||
NOTE: this is not cached at the moment. | ||
""" | ||
def schema_content do | ||
__DIR__ | ||
|> Path.join("../../../shared/meta/schema-irve-statique.json") | ||
|> Path.expand() | ||
|> File.read!() | ||
|> Jason.decode!() | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -449,4 +449,61 @@ defmodule DB.Factory do | |
"schema" => %{"name" => Keyword.get(opts, :schema_name), "version" => Keyword.get(opts, :schema_version)} | ||
} | ||
end | ||
|
||
defmodule IRVE do | ||
@moduledoc """ | ||
Factory part relevant to IRVE. | ||
""" | ||
|
||
@doc """ | ||
Generate a row following the IRVE static schema. | ||
See: | ||
- https://schema.data.gouv.fr/etalab/schema-irve-statique/ | ||
""" | ||
def generate_row do | ||
%{ | ||
"nom_amenageur" => "Métropole de Nulle Part", | ||
"siren_amenageur" => "123456782", | ||
"contact_amenageur" => "[email protected]", | ||
"nom_operateur" => "Opérateur de Charge", | ||
"contact_operateur" => "[email protected]", | ||
"telephone_operateur" => "0199456782", | ||
"nom_enseigne" => "Réseau de recharge", | ||
"id_station_itinerance" => "FRPAN99P12345678", | ||
"id_station_local" => "station_001", | ||
"nom_station" => "Ma Station", | ||
"implantation_station" => "Lieu de ma station", | ||
"adresse_station" => "26 rue des écluses, 17430 Champdolent", | ||
"code_insee_commune" => "17085", | ||
"coordonneesXY" => "[-0.799141,45.91914]", | ||
"nbre_pdc" => 1, | ||
"id_pdc_itinerance" => "FRPAN99E12345678", | ||
"id_pdc_local" => "pdc_001", | ||
"puissance_nominale" => 22, | ||
"prise_type_ef" => false, | ||
"prise_type_2" => true, | ||
"prise_type_combo_ccs" => false, | ||
"prise_type_chademo" => false, | ||
"prise_type_autre" => false, | ||
"gratuit" => false, | ||
"paiement_acte" => true, | ||
"paiement_cb" => true, | ||
"paiement_autre" => true, | ||
"tarification" => "2,50€ / 30min puis 0,025€ / minute", | ||
"condition_acces" => "Accès libre", | ||
"reservation" => false, | ||
"horaires" => "24/7", | ||
"accessibilite_pmr" => "Accessible mais non réservé PMR", | ||
"restriction_gabarit" => "Hauteur maximale 2.30m", | ||
"station_deux_roues" => false, | ||
"raccordement" => "Direct", | ||
"num_pdl" => "12345678912345", | ||
"date_mise_en_service" => "2024-10-02", | ||
"observations" => "Station située au niveau -1 du parking", | ||
"date_maj" => "2024-10-17", | ||
"cable_t2_attache" => false | ||
} | ||
end | ||
end | ||
end |
65 changes: 65 additions & 0 deletions
65
apps/transport/test/transport/irve/irve_data_frame_test.exs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
defmodule Transport.IRVE.DataFrameTest do | ||
use ExUnit.Case, async: true | ||
doctest Transport.IRVE.DataFrame | ||
|
||
test "schema content" do | ||
data = | ||
Transport.IRVE.StaticIRVESchema.schema_content() | ||
|> Map.fetch!("fields") | ||
|> Enum.at(0) | ||
|> Map.take(["name", "type"]) | ||
|
||
assert data == %{"name" => "nom_amenageur", "type" => "string"} | ||
end | ||
|
||
test "dataframe roundtrip (encode + decode)" do | ||
body = [DB.Factory.IRVE.generate_row()] |> CSV.encode(headers: true) |> Enum.join() | ||
df = Transport.IRVE.DataFrame.dataframe_from_csv_body!(body) | ||
maps = Explorer.DataFrame.to_rows(df) | ||
|
||
assert maps == [ | ||
%{ | ||
"nom_amenageur" => "Métropole de Nulle Part", | ||
"siren_amenageur" => "123456782", | ||
"contact_amenageur" => "[email protected]", | ||
"nom_operateur" => "Opérateur de Charge", | ||
"contact_operateur" => "[email protected]", | ||
"telephone_operateur" => "0199456782", | ||
"nom_enseigne" => "Réseau de recharge", | ||
"id_station_itinerance" => "FRPAN99P12345678", | ||
"id_station_local" => "station_001", | ||
"nom_station" => "Ma Station", | ||
"implantation_station" => "Lieu de ma station", | ||
"adresse_station" => "26 rue des écluses, 17430 Champdolent", | ||
"code_insee_commune" => "17085", | ||
"coordonneesXY" => "[-0.799141,45.91914]", | ||
"nbre_pdc" => 1, | ||
"id_pdc_itinerance" => "FRPAN99E12345678", | ||
"id_pdc_local" => "pdc_001", | ||
"puissance_nominale" => 22, | ||
"prise_type_ef" => false, | ||
"prise_type_2" => true, | ||
"prise_type_combo_ccs" => false, | ||
"prise_type_chademo" => false, | ||
"prise_type_autre" => false, | ||
"gratuit" => false, | ||
"paiement_acte" => true, | ||
"paiement_cb" => true, | ||
"paiement_autre" => true, | ||
"tarification" => "2,50€ / 30min puis 0,025€ / minute", | ||
"condition_acces" => "Accès libre", | ||
"reservation" => false, | ||
"horaires" => "24/7", | ||
"accessibilite_pmr" => "Accessible mais non réservé PMR", | ||
"restriction_gabarit" => "Hauteur maximale 2.30m", | ||
"station_deux_roues" => false, | ||
"raccordement" => "Direct", | ||
"num_pdl" => "12345678912345", | ||
"date_mise_en_service" => ~D[2024-10-02], | ||
"observations" => "Station située au niveau -1 du parking", | ||
"date_maj" => ~D[2024-10-17], | ||
"cable_t2_attache" => false | ||
} | ||
] | ||
end | ||
end |
Oops, something went wrong.