mirror of
https://github.com/CatalaLang/catala.git
synced 2024-11-09 22:16:10 +03:00
Documented legifrance_catala
This commit is contained in:
parent
ca6fd2173f
commit
9e6c1cc9ee
@ -152,9 +152,6 @@ let get_article_expiration_date (json : article) : Unix.tm =
|
||||
|> Yojson.Basic.Util.to_int |> api_timestamp_to_localtime
|
||||
with Yojson.Basic.Util.Type_error (msg, obj) -> raise_article_parsing_error json msg obj
|
||||
|
||||
let date_compare (d1 : Unix.tm) (d2 : Unix.tm) : int =
|
||||
int_of_float (fst (Unix.mktime d1)) - int_of_float (fst (Unix.mktime d2))
|
||||
|
||||
let get_article_new_version (json : article) : string =
|
||||
let expiration_date = get_article_expiration_date json in
|
||||
let get_version_date_debut (version : Yojson.Basic.t) : Unix.tm =
|
||||
@ -168,9 +165,9 @@ let get_article_new_version (json : article) : string =
|
||||
|> Yojson.Basic.Util.member "articleVersions"
|
||||
|> Yojson.Basic.Util.to_list
|
||||
|> List.filter (fun version ->
|
||||
date_compare expiration_date (get_version_date_debut version) <= 0)
|
||||
Date.date_compare expiration_date (get_version_date_debut version) <= 0)
|
||||
|> List.sort (fun version1 version2 ->
|
||||
date_compare (get_version_date_debut version1) (get_version_date_debut version2))
|
||||
Date.date_compare (get_version_date_debut version1) (get_version_date_debut version2))
|
||||
|> List.hd |> Yojson.Basic.Util.member "id" |> Yojson.Basic.Util.to_string
|
||||
with Yojson.Basic.Util.Type_error (msg, obj) -> raise_article_parsing_error json msg obj
|
||||
|
||||
|
59
src/legifrance_catala/cli.ml
Normal file
59
src/legifrance_catala/cli.ml
Normal file
@ -0,0 +1,59 @@
|
||||
(* This file is part of the Catala compiler, a specification language for tax and social benefits
|
||||
computation rules. Copyright (C) 2020 Inria, contributor: Denis Merigoux
|
||||
<denis.merigoux@inria.fr>
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
in compliance with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License
|
||||
is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
or implied. See the License for the specific language governing permissions and limitations under
|
||||
the License. *)
|
||||
|
||||
(** Command line arguments specification of [legifrance_catala] *)
|
||||
|
||||
open Cmdliner
|
||||
|
||||
let file =
|
||||
Arg.(
|
||||
required
|
||||
& pos 0 (some string) None
|
||||
& info [] ~docv:"FILE"
|
||||
~doc:"Name of the Catala master file you want to get LegiFrance information on")
|
||||
|
||||
let client_id =
|
||||
Arg.(
|
||||
required
|
||||
& pos 1 (some string) None
|
||||
& info [] ~docv:"CLIENT_ID" ~doc:"LegiFrance Oauth cliend id")
|
||||
|
||||
let client_secret =
|
||||
Arg.(
|
||||
required
|
||||
& pos 2 (some string) None
|
||||
& info [] ~docv:"CLIENT_SECRET" ~doc:"LegiFrance Oauth cliend secret")
|
||||
|
||||
let debug = Arg.(value & flag & info [ "d"; "debug" ] ~doc:"Prints debug information")
|
||||
|
||||
(** Arguments : [file debug cliend_id client_secret] *)
|
||||
let catala_legifrance_t f = Term.(const f $ file $ debug $ client_id $ client_secret)
|
||||
|
||||
let info =
|
||||
let doc = "LegiFrance interaction tool for Catala" in
|
||||
let man =
|
||||
[
|
||||
`S Manpage.s_authors;
|
||||
`P "Denis Merigoux <denis.merigoux@inria.fr>";
|
||||
`S Manpage.s_bugs;
|
||||
`P "Please file bug reports at https://gitlab.inria.fr/verifisc/catala/issues";
|
||||
]
|
||||
in
|
||||
let exits = Term.default_exits @ [ Term.exit_info ~doc:"on error" 1 ] in
|
||||
Term.info "legifrance_catala"
|
||||
~version:
|
||||
( match Build_info.V1.version () with
|
||||
| None -> "n/a"
|
||||
| Some v -> Build_info.V1.Version.to_string v )
|
||||
~doc ~exits ~man
|
52
src/legifrance_catala/date.ml
Normal file
52
src/legifrance_catala/date.ml
Normal file
@ -0,0 +1,52 @@
|
||||
(* This file is part of the Catala compiler, a specification language for tax and social benefits
|
||||
computation rules. Copyright (C) 2020 Inria, contributor: Denis Merigoux
|
||||
<denis.merigoux@inria.fr>
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
in compliance with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License
|
||||
is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
or implied. See the License for the specific language governing permissions and limitations under
|
||||
the License. *)
|
||||
|
||||
(** Helper functions to interact with {!Unix.tm} dates *)
|
||||
|
||||
(** Parses a date formatted as [DD/MM/YYYY] into an {!Unix.tm}*)
|
||||
let parse_expiration_date (expiration_date : string) : Unix.tm =
|
||||
try
|
||||
let extract_article_title = Re.Pcre.regexp "([0-9]{2})\\/([0-9]{2})\\/([0-9]{4})" in
|
||||
let get_substring =
|
||||
Re.Pcre.get_substring (Re.Pcre.exec ~rex:extract_article_title expiration_date)
|
||||
in
|
||||
snd
|
||||
(Unix.mktime
|
||||
{
|
||||
Unix.tm_mday = int_of_string (get_substring 1);
|
||||
Unix.tm_mon = int_of_string (get_substring 2);
|
||||
Unix.tm_year = int_of_string (get_substring 3) - 1900;
|
||||
Unix.tm_sec = 0;
|
||||
Unix.tm_min = 0;
|
||||
Unix.tm_hour = 0;
|
||||
Unix.tm_wday = 0;
|
||||
Unix.tm_yday = 0;
|
||||
Unix.tm_isdst = false;
|
||||
})
|
||||
with _ ->
|
||||
Catala.Cli.error_print
|
||||
(Printf.sprintf "Error while parsing expiration date argument (%s)" expiration_date);
|
||||
exit 0
|
||||
|
||||
(** Prints an [Unix.tm] under the ISO formatting [YYYY-MM-DD] *)
|
||||
let print_tm (d : Unix.tm) : string =
|
||||
if d.Unix.tm_year + 1900 = 2999 then "undefined date"
|
||||
else Printf.sprintf "%d-%02d-%02d" (1900 + d.Unix.tm_year) (1 + d.Unix.tm_mon) d.Unix.tm_mday
|
||||
|
||||
(** Returns true if [d] is set in the year [2999] *)
|
||||
let is_infinity (d : Unix.tm) : bool = d.Unix.tm_year + 1900 = 2999
|
||||
|
||||
(** [date_compare d1 d2] compares the timestamps of [d1] and [d2]*)
|
||||
let date_compare (d1 : Unix.tm) (d2 : Unix.tm) : int =
|
||||
int_of_float (fst (Unix.mktime d1)) - int_of_float (fst (Unix.mktime d2))
|
35
src/legifrance_catala/diff.mli
Normal file
35
src/legifrance_catala/diff.mli
Normal file
@ -0,0 +1,35 @@
|
||||
(* This file is part of the Catala compiler, a specification language for tax and social benefits
|
||||
computation rules. Copyright (C) 2020 Inria, contributor: Denis Merigoux
|
||||
<denis.merigoux@inria.fr>
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
in compliance with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License
|
||||
is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
or implied. See the License for the specific language governing permissions and limitations under
|
||||
the License. *)
|
||||
|
||||
(** Simple and inefficient diff algorithm based on longest common subsequences *)
|
||||
|
||||
(** The diff algorithm works on comparable items *)
|
||||
module type Comparable = sig
|
||||
type t
|
||||
|
||||
val compare : t -> t -> int
|
||||
end
|
||||
|
||||
(** Functor that produces a [Diff] module given a comparable type *)
|
||||
module Make : functor (X : Comparable) -> sig
|
||||
type item = X.t
|
||||
|
||||
type diff = Deleted of item list | Added of item list | Equal of item list
|
||||
|
||||
type t = diff list
|
||||
|
||||
val get_diff : item array -> item array -> t
|
||||
(** This is the main function : [get_diff a1 a2] compares two arrays of items and outputs a list
|
||||
of chunks tagged with [Deteted], [Added] or [Removed] *)
|
||||
end
|
@ -12,82 +12,11 @@
|
||||
or implied. See the License for the specific language governing permissions and limitations under
|
||||
the License. *)
|
||||
|
||||
open Cmdliner
|
||||
|
||||
let file =
|
||||
Arg.(
|
||||
required
|
||||
& pos 0 (some string) None
|
||||
& info [] ~docv:"FILE"
|
||||
~doc:"Name of the Catala master file you want to get LegiFrance information on")
|
||||
|
||||
let client_id =
|
||||
Arg.(
|
||||
required
|
||||
& pos 1 (some string) None
|
||||
& info [] ~docv:"CLIENT_ID" ~doc:"LegiFrance Oauth cliend id")
|
||||
|
||||
let client_secret =
|
||||
Arg.(
|
||||
required
|
||||
& pos 2 (some string) None
|
||||
& info [] ~docv:"CLIENT_SECRET" ~doc:"LegiFrance Oauth cliend secret")
|
||||
|
||||
let debug = Arg.(value & flag & info [ "d"; "debug" ] ~doc:"Prints debug information")
|
||||
|
||||
let catala_legifrance_t f = Term.(const f $ file $ debug $ client_id $ client_secret)
|
||||
|
||||
let info =
|
||||
let doc = "LegiFrance interaction tool for Catala" in
|
||||
let man =
|
||||
[
|
||||
`S Manpage.s_authors;
|
||||
`P "Denis Merigoux <denis.merigoux@inria.fr>";
|
||||
`S Manpage.s_bugs;
|
||||
`P "Please file bug reports at https://gitlab.inria.fr/verifisc/catala/issues";
|
||||
]
|
||||
in
|
||||
let exits = Term.default_exits @ [ Term.exit_info ~doc:"on error" 1 ] in
|
||||
Term.info "legifrance_catala"
|
||||
~version:
|
||||
( match Build_info.V1.version () with
|
||||
| None -> "n/a"
|
||||
| Some v -> Build_info.V1.Version.to_string v )
|
||||
~doc ~exits ~man
|
||||
|
||||
let parse_expiration_date (expiration_date : string) : Unix.tm =
|
||||
try
|
||||
let extract_article_title = Re.Pcre.regexp "([0-9]{2})\\/([0-9]{2})\\/([0-9]{4})" in
|
||||
let get_substring =
|
||||
Re.Pcre.get_substring (Re.Pcre.exec ~rex:extract_article_title expiration_date)
|
||||
in
|
||||
snd
|
||||
(Unix.mktime
|
||||
{
|
||||
Unix.tm_mday = int_of_string (get_substring 1);
|
||||
Unix.tm_mon = int_of_string (get_substring 2);
|
||||
Unix.tm_year = int_of_string (get_substring 3) - 1900;
|
||||
Unix.tm_sec = 0;
|
||||
Unix.tm_min = 0;
|
||||
Unix.tm_hour = 0;
|
||||
Unix.tm_wday = 0;
|
||||
Unix.tm_yday = 0;
|
||||
Unix.tm_isdst = false;
|
||||
})
|
||||
with _ ->
|
||||
Catala.Cli.error_print
|
||||
(Printf.sprintf "Error while parsing expiration date argument (%s)" expiration_date);
|
||||
exit 0
|
||||
|
||||
let print_tm (d : Unix.tm) : string =
|
||||
if d.Unix.tm_year + 1900 = 2999 then "undefined date"
|
||||
else Printf.sprintf "%d-%02d-%02d" (1900 + d.Unix.tm_year) (1 + d.Unix.tm_mon) d.Unix.tm_mday
|
||||
|
||||
let is_infinity (d : Unix.tm) : bool = d.Unix.tm_year + 1900 = 2999
|
||||
(** Main logic for interacting with LegiFrance when traversing Catala source files *)
|
||||
|
||||
type new_article_version = NotAvailable | Available of string
|
||||
|
||||
(* Returns the ID of the future version of the article if any *)
|
||||
(** Returns the ID of the future version of the article if any *)
|
||||
let check_article_expiration (article_catala : Catala.Ast.law_article)
|
||||
(access_token : Api.access_token) : new_article_version option =
|
||||
match article_catala.Catala.Ast.law_article_id with
|
||||
@ -100,18 +29,18 @@ let check_article_expiration (article_catala : Catala.Ast.law_article)
|
||||
(Catala.Pos.unmark article_catala.Catala.Ast.law_article_name)
|
||||
(Catala.Pos.to_string
|
||||
(Catala.Pos.get_position article_catala.Catala.Ast.law_article_name))
|
||||
(print_tm api_article_expiration_date)
|
||||
(Date.print_tm api_article_expiration_date)
|
||||
( match article_catala.Catala.Ast.law_article_expiration_date with
|
||||
| None -> ""
|
||||
| Some source_exp_date -> ", " ^ source_exp_date ^ " according to source code" )
|
||||
in
|
||||
let new_version_available = not (is_infinity api_article_expiration_date) in
|
||||
let new_version_available = not (Date.is_infinity api_article_expiration_date) in
|
||||
let source_code_expiration =
|
||||
match article_catala.Catala.Ast.law_article_expiration_date with
|
||||
| None -> false
|
||||
| Some source_exp_date ->
|
||||
let source_exp_date = parse_expiration_date source_exp_date in
|
||||
not (is_infinity source_exp_date)
|
||||
let source_exp_date = Date.parse_expiration_date source_exp_date in
|
||||
not (Date.is_infinity source_exp_date)
|
||||
in
|
||||
if new_version_available || source_code_expiration then begin
|
||||
Catala.Cli.warning_print msg;
|
||||
@ -133,9 +62,13 @@ type article_text_acc = {
|
||||
new_version : string option;
|
||||
current_version : string option;
|
||||
}
|
||||
(** Accumulator type when traversing the Catala source files *)
|
||||
|
||||
module Diff = Diff.Make (String)
|
||||
(** Diff algorithm for a list of words *)
|
||||
|
||||
(** [compare_article_to_version token text version] retrieves the text of the article whose
|
||||
LegiFrance ID is [version] and produces a diff with the expected [text]*)
|
||||
let compare_article_to_version (access_token : Api.access_token) (text : string) (version : string)
|
||||
: Diff.t option =
|
||||
let new_article = Api.retrieve_article access_token version in
|
||||
@ -149,6 +82,8 @@ let compare_article_to_version (access_token : Api.access_token) (text : string)
|
||||
in
|
||||
if not all_equal then Some diff else None
|
||||
|
||||
(** Compares [article_text_acc.current_version] and [article_text_acc.new_version] by accessing
|
||||
LegiFrance and display differences if any *)
|
||||
let compare_to_versions (article_text_acc : article_text_acc) (access_token : Api.access_token) :
|
||||
unit =
|
||||
let print_diff msg diff =
|
||||
@ -194,6 +129,8 @@ let compare_to_versions (article_text_acc : article_text_acc) (access_token : Ap
|
||||
diff )
|
||||
| None -> ()
|
||||
|
||||
(** Fill an [@@Include ...@@] tag inside the Catala source file with the legislative contents
|
||||
retrieved from LegiFrance *)
|
||||
let include_legislative_text (id : string Catala.Pos.marked) (access_token : Api.access_token) :
|
||||
unit =
|
||||
let excerpt = Api.retrieve_law_excerpt access_token (Catala.Pos.unmark id) in
|
||||
@ -227,6 +164,13 @@ let include_legislative_text (id : string Catala.Pos.marked) (access_token : Api
|
||||
close_in ic;
|
||||
close_out oc
|
||||
|
||||
(** Parses the Catala master source file and checks each article:
|
||||
|
||||
- if the article has a LegiFrance ID, checks the text of the article in the source code vs the
|
||||
text from LegiFrance;
|
||||
- if the article has an expiration date, display the difference between the current version of
|
||||
the article and the next one on LegiFrance;
|
||||
- fill each [@@Include ...@@] tag with the contents retrieved from LegiFrance *)
|
||||
let driver (file : string) (debug : bool) (client_id : string) (client_secret : string) =
|
||||
if debug then Catala.Cli.debug_flag := true;
|
||||
let access_token = Api.get_token client_id client_secret in
|
||||
@ -271,4 +215,5 @@ let driver (file : string) (debug : bool) (client_id : string) (client_secret :
|
||||
compare_to_versions article_text_acc access_token;
|
||||
exit 0
|
||||
|
||||
let main () = Cmdliner.Term.exit @@ Cmdliner.Term.eval (catala_legifrance_t driver, info)
|
||||
(** Hook for the executable *)
|
||||
let main () = Cmdliner.Term.exit @@ Cmdliner.Term.eval (Cli.catala_legifrance_t driver, Cli.info)
|
||||
|
Loading…
Reference in New Issue
Block a user