From 73c9bc022fb2918a4557f1a0641cdef4686c2146 Mon Sep 17 00:00:00 2001 From: Michael Moore Date: Sat, 14 Dec 2024 14:51:52 -0600 Subject: [PATCH 1/6] Update mod supported version number --- mod/stellaris_dashboard/descriptor.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mod/stellaris_dashboard/descriptor.mod b/mod/stellaris_dashboard/descriptor.mod index e8b55a6..d51e62d 100644 --- a/mod/stellaris_dashboard/descriptor.mod +++ b/mod/stellaris_dashboard/descriptor.mod @@ -5,5 +5,5 @@ tags={ "Gameplay" } picture="thumbnail.png" -supported_version="v3.12.*" +supported_version="v3.14.*" remote_file_id="1466534202" \ No newline at end of file From 4f77a97226804a51b3c351fc704b75a7dc33c171 Mon Sep 17 00:00:00 2001 From: Michael Moore Date: Sat, 14 Dec 2024 14:52:33 -0600 Subject: [PATCH 2/6] Fix values starting with nan misinterpreted in parser, fixes #164 --- .../parsing/rust_parser/src/parser.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/stellarisdashboard/parsing/rust_parser/src/parser.rs b/stellarisdashboard/parsing/rust_parser/src/parser.rs index fa30fda..608134f 100644 --- a/stellarisdashboard/parsing/rust_parser/src/parser.rs +++ b/stellarisdashboard/parsing/rust_parser/src/parser.rs @@ -7,7 +7,7 @@ use nom::branch::alt; use nom::bytes::complete::{tag, take_while, take_while1}; use nom::bytes::streaming::escaped; use nom::character::complete::{char, multispace0, multispace1, none_of, one_of}; -use nom::combinator::{map, map_res, recognize}; +use nom::combinator::{map, map_res, not, recognize}; use nom::error::context; use nom::IResult; use nom::multi::{separated_list0, separated_list1}; @@ -237,7 +237,10 @@ fn parse_int(input: &str) -> IResult<&str, i64> { fn parse_float(input: &str) -> IResult<&str, f64> { preceded( multispace0, - map_res(recognize(double), |s: &str| s.parse::()), + preceded( + not(tag("nan")), + map_res(recognize(double), |s: &str| s.parse::()), + ), )(input) } @@ -573,6 +576,15 @@ mod tests { parse_file(test_input.as_str()).expect("Should parse"); } + #[test] + fn test_nan_in_value() { + // from a bug report for a save that failed to parse + // narrowed down to this input + // `parse_float` was grabbing the initial "nan" + let test_input = "1=nano_shipyard"; + parse_file(test_input).expect("Should parse"); + } + #[test] fn test_skipped_key_in_mapping() { assert_eq!( From 974665ae8c4046d94e089cafc15b136a3d7035d8 Mon Sep 17 00:00:00 2001 From: Michael Moore Date: Sat, 14 Dec 2024 17:42:27 -0600 Subject: [PATCH 3/6] Add fallback logic so event ledger doesn't crash if a leader is somehow missing from the DB --- .../dashboard_app/templates/history_page.html | 120 +++++++++++------- 1 file changed, 73 insertions(+), 47 deletions(-) diff --git a/stellarisdashboard/dashboard_app/templates/history_page.html b/stellarisdashboard/dashboard_app/templates/history_page.html index c8fb96f..836209f 100644 --- a/stellarisdashboard/dashboard_app/templates/history_page.html +++ b/stellarisdashboard/dashboard_app/templates/history_page.html @@ -7,6 +7,14 @@ {% endif %} {% endblock %} +{% macro render_leader(event, fallback="an unknown leader") -%} + {% if "leader" in event %} + {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe }} + {% else %} + {{ fallback }} + {% endif %} +{%- endmacro %} + {% block body %} {% if not is_filtered_page %}
@@ -69,7 +77,7 @@

{{title[object] | safe}}

{% if event["is_active"] %}(A){% endif %} {{event["start_date"]}}{% if event["end_date"] != null %} - {{event["end_date"]}}{%endif%}: - {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe }} ruled the {{ links[event["country"]] | safe}} + {{ render_leader(event, "An unknown leader") }} ruled the {{ links[event["country"]] | safe}} {% if "planet" in event %} from the capital {{ links[event["planet"]] | safe }} in the {{ links[event["system"]] | safe }} system {% endif %}.
@@ -79,7 +87,7 @@

{{title[object] | safe}}

{{event["start_date"]}}: - {% if "leader" in event %} Under the rule of {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}, the + {% if "leader" in event %} Under the rule of {{ render_leader(event) }}, the {% else %} The {% endif %} {{ links[event["country"]] | safe }} relocated their capital to the {{ event["planet"].planetclass }} {{ links[event["planet"]] | safe }} @@ -94,7 +102,7 @@

{{title[object] | safe}}

The {{ links[event["country"]] | safe }} colonized the {{ event["planet"].planetclass }} {{ links[event["planet"]] | safe }} in the {{ links[event["system"]] | safe }} system - {% if "leader" in event%} under the governorship of {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}{% endif %}. + {% if "leader" in event%} under the governorship of {{ render_leader(event) }}{% endif %}.
@@ -160,7 +168,8 @@

{{title[object] | safe}}

{{event["start_date"]}}: - {{event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe }} was promoted to rank {{event["description"]}}. + {{ render_leader(event, "An unknown leader") }} + was promoted to rank {{event["description"]}}.
@@ -169,7 +178,8 @@

{{title[object] | safe}}

{% if event["is_active"] %}(A){% endif %} {{event["start_date"]}}{% if event["end_date"] != null %} - {{event["end_date"]}}{%endif%}: - {{ links[event["leader"]] | safe }} served as {{event["description"]}} on the council of the {{ links[event["country"]] | safe}}. + {{ render_leader(event, "An unknown leader") }} + served as {{event["description"]}} on the council of the {{ links[event["country"]] | safe}}.
@@ -178,7 +188,7 @@

{{title[object] | safe}}

{% if event["is_active"] %}(A){% endif %} {{event["start_date"]}}{% if event["end_date"] != null %} - {{event["end_date"]}}{%endif%}: - {% if "leader" in event %}Under the rule of {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}, the {% else %}The {% endif %} + {% if "leader" in event %}Under the rule of {{ render_leader(event) }}, the {% else %}The {% endif %} {{ links[event["country"]] | safe}} prepared a new agenda "{{event["description"]}}".
@@ -188,7 +198,7 @@

{{title[object] | safe}}

{{event["start_date"]}}: - {% if "leader" in event %}Under the rule of {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}, the {% else %}The {% endif %} + {% if "leader" in event %}Under the rule of {{ render_leader(event) }}, the {% else %}The {% endif %} {{ links[event["country"]] | safe}} launched the agenda "{{event["description"]}}".
@@ -207,7 +217,7 @@

{{title[object] | safe}}

{% if event["is_active"] %}(A){% endif %} {{event["start_date"]}}{% if event["end_date"] != null %} - {{event["end_date"]}}{%endif%}: - {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe }} + {{ render_leader(event, "An unknown leader") }} governed the {{event["description"]}} sector from the planet {{ links[event["planet"]] | safe }} in the {{ links[event["system"]] | safe }} system. @@ -219,7 +229,7 @@

{{title[object] | safe}}

{% if event["is_active"] %}(A){% endif %} {{event["start_date"]}}{% if event["end_date"] != null %} - {{event["end_date"]}}{%endif%}: - {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe }} + {{ render_leader(event, "An unknown leader") }} governed the planet {{ links[event["planet"]] | safe }} in the {{ links[event["system"]] | safe }} system. @@ -230,7 +240,7 @@

{{title[object] | safe}}

{% if event["is_active"] %}(A){% endif %} {{event["start_date"]}}{% if event["end_date"] != null %} - {{event["end_date"]}}{%endif%}: - {% if "leader" in event %}{{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}{% else %}The {{ links[event["country"]] | safe}}{% endif %} + {% if "leader" in event %}{{ render_leader(event) }}{% else %}The {{ links[event["country"]] | safe}}{% endif %} enacted the "{{event["description"]}}" edict.
@@ -240,7 +250,7 @@

{{title[object] | safe}}

{{event["start_date"]}}: - {% if "leader" in event %}Under the rule of {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}, the {% else %}The {% endif %} + {% if "leader" in event %}Under the rule of {{ render_leader(event) }}, the {% else %}The {% endif %} {{ links[event["country"]] | safe}} enacted a new policy on {{event["description"]}}.
@@ -250,7 +260,7 @@

{{title[object] | safe}}

{{event["start_date"]}}: - {% if "leader" in event %}Under the rule of {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}, the {% else %}The {% endif %} + {% if "leader" in event %}Under the rule of {{ render_leader(event) }}, the {% else %}The {% endif %} {{ links[event["country"]] | safe}} changed their policy on {{event["description"]}}.
@@ -261,7 +271,7 @@

{{title[object] | safe}}

{{event["start_date"]}}: {% if "leader" in event %} - {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe }} ascended the {{ links[event["country"]] | safe }} with "{{event["description"]}}". + {{ render_leader(event) }} ascended the {{ links[event["country"]] | safe }} with "{{event["description"]}}". {% else %} The {{ links[event["country"]] | safe }} ascended with "{{event["description"]}}". {% endif %} @@ -274,7 +284,7 @@

{{title[object] | safe}}

{{event["start_date"]}}: {% if "leader" in event %} - {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe }} reformed the {{ links[event["country"]] | safe }} government: + {{ render_leader(event) }} reformed the {{ links[event["country"]] | safe }} government: {% else %} Government reforms in the {{ links[event["country"]] | safe}}: {% endif %} @@ -287,7 +297,7 @@

{{title[object] | safe}}

{{event["start_date"]}}: - {% if "leader" in event %} Under the rule of {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}, the + {% if "leader" in event %} Under the rule of {{ render_leader(event) }}, the {% else %} The {% endif %} {{ links[event["country"]] | safe }} adopted the "{{ event["description"]}}" tradition. @@ -299,7 +309,8 @@

{{title[object] | safe}}

{% if event["is_active"] %}(A){% endif %} {{event["start_date"]}}{% if event["end_date"] != null %} - {{event["end_date"]}}{%endif%}: - {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe }} was leader of the "{{ event["faction"].rendered_name}}" faction. + {{ render_leader(event, "An unknown leader") }} + was leader of the "{{ event["faction"].rendered_name}}" faction.
@@ -308,7 +319,8 @@

{{title[object] | safe}}

{{event["start_date"]}}: - {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe }} gained the "{{ event["description"] }}" trait. + {{ render_leader(event, "An unknown leader") }} + gained the "{{ event["description"] }}" trait.
@@ -317,7 +329,8 @@

{{title[object] | safe}}

{{event["start_date"]}}: - {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe }} lost the "{{ event["description"] }}" trait. + {{ render_leader(event, "An unknown leader") }} + lost the "{{ event["description"] }}" trait.
@@ -326,7 +339,7 @@

{{title[object] | safe}}

{{event["start_date"]}}: - {% if "leader" in event %} Under the rule of {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}, the + {% if "leader" in event %} Under the rule of {{ render_leader(event) }}, the {% else %} The {% endif %} {{ links[event["country"]] | safe }} established first contact with the {{ links[event["target_country"]] | safe }}. @@ -338,7 +351,7 @@

{{title[object] | safe}}

{% if event["is_active"] %}(A){% endif %} {{event["start_date"]}}{% if event["end_date"] != null %} - {{event["end_date"]}}{%endif%}: - {% if "leader" in event %} Under the rule of {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}, the + {% if "leader" in event %} Under the rule of {{ render_leader(event) }}, the {% else %} The {% endif %} {{ links[event["country"]] | safe }} declared rivalry against the {{ links[event["target_country"]] | safe }}. @@ -351,7 +364,7 @@

{{title[object] | safe}}

{% if event["is_active"] %}(A){% endif %} {{event["start_date"]}}{% if event["end_date"] != null %} - {{event["end_date"]}}{%endif%}: - {% if "leader" in event %} Under the rule of {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}, the + {% if "leader" in event %} Under the rule of {{ render_leader(event) }}, the {% else %} The {% endif %} {{ links[event["country"]] | safe }} received a rivalry declaration from the {{ links[event["target_country"]] | safe }}. @@ -364,7 +377,7 @@

{{title[object] | safe}}

{% if event["is_active"] %}(A){% endif %} {{event["start_date"]}}{% if event["end_date"] != null %} - {{event["end_date"]}}{%endif%}: - {% if "leader" in event %} Under the rule of {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}, the + {% if "leader" in event %} Under the rule of {{ render_leader(event) }}, the {% else %} The {% endif %} {{ links[event["country"]] | safe }} revoked border access to the {{ links[event["target_country"]] | safe }}. @@ -395,7 +408,7 @@

{{title[object] | safe}}

{% if event["is_active"] %}(A){% endif %} {{event["start_date"]}}{% if event["end_date"] != null %} - {{event["end_date"]}}{%endif%}: - {% if "leader" in event %} Under the rule of {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}, the + {% if "leader" in event %} Under the rule of {{ render_leader(event) }}, the {% else %} The {% endif %} {{ links[event["country"]] | safe }} entered a defensive pact with the {{ links[event["target_country"]] | safe }}. @@ -408,7 +421,7 @@

{{title[object] | safe}}

{% if event["is_active"] %}(A){% endif %} {{event["start_date"]}}{% if event["end_date"] != null %} - {{event["end_date"]}}{%endif%}: - {% if "leader" in event %} Under the rule of {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}, the + {% if "leader" in event %} Under the rule of {{ render_leader(event) }}, the {% else %} The {% endif %} {{ links[event["country"]] | safe }} entered a research agreement with the {{ links[event["target_country"]] | safe }}. @@ -421,7 +434,7 @@

{{title[object] | safe}}

{% if event["is_active"] %}(A){% endif %} {{event["start_date"]}}{% if event["end_date"] != null %} - {{event["end_date"]}}{%endif%}: - {% if "leader" in event %} Under the rule of {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}, the + {% if "leader" in event %} Under the rule of {{ render_leader(event) }}, the {% else %} The {% endif %} {{ links[event["country"]] | safe }} entered a commercial pact with the {{ links[event["target_country"]] | safe }}. @@ -434,7 +447,7 @@

{{title[object] | safe}}

{% if event["is_active"] %}(A){% endif %} {{event["start_date"]}}{% if event["end_date"] != null %} - {{event["end_date"]}}{%endif%}: - {% if "leader" in event %} Under the rule of {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}, the + {% if "leader" in event %} Under the rule of {{ render_leader(event) }}, the {% else %} The {% endif %} {{ links[event["country"]] | safe }} entered a migration treaty with the {{ links[event["target_country"]] | safe }}. @@ -447,7 +460,7 @@

{{title[object] | safe}}

{% if event["is_active"] %}(A){% endif %} {{event["start_date"]}}{% if event["end_date"] != null %} - {{event["end_date"]}}{%endif%}: - {% if "leader" in event %} Under the rule of {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}, the + {% if "leader" in event %} Under the rule of {{ render_leader(event) }}, the {% else %} The {% endif %} {{ links[event["country"]] | safe }} entered a non-aggression pact with the {{ links[event["target_country"]] | safe }}. @@ -459,7 +472,7 @@

{{title[object] | safe}}

{% if event["is_active"] %}(A){% endif %} {{event["start_date"]}}{% if event["end_date"] != null %} - {{event["end_date"]}}{%endif%}: - {% if "leader" in event %} Under the rule of {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}, the + {% if "leader" in event %} Under the rule of {{ render_leader(event) }}, the {% else %} The {% endif %} {{ links[event["country"]] | safe }} and {{ links[event["target_country"]] | safe }} are now allied in the "{{ event["description"] }}" federation. @@ -471,7 +484,9 @@

{{title[object] | safe}}

{{event["start_date"]}}{% if event["end_date"] != null %} - {{event["end_date"]}}{%endif%}: - The {{ links[event["country"]] | safe }} sent {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe }} to increase their diplomatic weight in the galactic community. + The {{ links[event["country"]] | safe }} sent + {{ render_leader(event) }} + to increase their diplomatic weight in the galactic community.
@@ -480,7 +495,9 @@

{{title[object] | safe}}

{{event["start_date"]}}{% if event["end_date"] != null %} - {{event["end_date"]}}{%endif%}: - The {{ links[event["country"]] | safe }} sent {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe }} to improve the cohesion of the {{ event["description"] }}. + The {{ links[event["country"]] | safe }} sent + {{ render_leader(event) }} + to improve the cohesion of the {{ event["description"] }}.
@@ -489,7 +506,9 @@

{{title[object] | safe}}

{% if event["is_active"] %}(A){% endif %} {{event["start_date"]}}{% if event["end_date"] != null %} - {{event["end_date"]}}{%endif%}: - The {{ links[event["country"]] | safe }} sent {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe }} to improve relations with the {{ links[event["target_country"]] | safe }}. + The {{ links[event["country"]] | safe }} sent + {{ render_leader(event) }} + to improve relations with the {{ links[event["target_country"]] | safe }}.
@@ -498,7 +517,9 @@

{{title[object] | safe}}

{% if event["is_active"] %}(A){% endif %} {{event["start_date"]}}{% if event["end_date"] != null %} - {{event["end_date"]}}{%endif%}: - The {{ links[event["country"]] | safe }} sent {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe }} to harm relations with the {{ links[event["target_country"]] | safe }}. + The {{ links[event["country"]] | safe }} sent + {{ render_leader(event) }} + to harm relations with the {{ links[event["target_country"]] | safe }}.
@@ -507,7 +528,7 @@

{{title[object] | safe}}

{% if event["is_active"] %}(A){% endif %} {{event["start_date"]}}{% if event["end_date"] != null %} - {{event["end_date"]}}{%endif%}: - {% if "leader" in event %} Under the rule of {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}, the + {% if "leader" in event %} Under the rule of {{ render_leader(event) }}, the {% else %} The {% endif %} {{ links[event["country"]] | safe }} joined the Galactic Community. @@ -519,7 +540,7 @@

{{title[object] | safe}}

{% if event["is_active"] %}(A){% endif %} {{event["start_date"]}}{% if event["end_date"] != null %} - {{event["end_date"]}}{%endif%}: - {% if "leader" in event %} Under the rule of {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}, the + {% if "leader" in event %} Under the rule of {{ render_leader(event) }}, the {% else %} The {% endif %} {{ links[event["country"]] | safe }} joined the Galactic Council. @@ -531,7 +552,7 @@

{{title[object] | safe}}

{% if event["is_active"] %}(A){% endif %} {{event["start_date"]}}{% if event["end_date"] != null %} - {{event["end_date"]}}{%endif%}: - {% if "leader" in event %} Under the rule of {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}, the + {% if "leader" in event %} Under the rule of {{ render_leader(event) }}, the {% else %} The {% endif %} {{ links[event["country"]] | safe }} left the Galactic Community. @@ -543,7 +564,7 @@

{{title[object] | safe}}

{% if event["is_active"] %}(A){% endif %} {{event["start_date"]}}{% if event["end_date"] != null %} - {{event["end_date"]}}{%endif%}: - {% if "leader" in event %} Under the rule of {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}, the + {% if "leader" in event %} Under the rule of {{ render_leader(event) }}, the {% else %} The {% endif %} {{ links[event["country"]] | safe }} left the Galactic Council. @@ -555,8 +576,10 @@

{{title[object] | safe}}

{{event["start_date"]}}: - Finished construction of {{ event["description"] }} in the {{ links[event["system"]] | safe }} system{% if "leader" in event %}, - under the governorship of {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}{% endif %}. + Finished construction of {{ event["description"] }} in the {{ links[event["system"]] | safe }} system + {% if "leader" in event %}, + under the governorship of {{ render_leader(event) }} + {% endif %}.
@@ -565,7 +588,8 @@

{{title[object] | safe}}

{{event["start_date"]}}: - The {{ links[event["country"]] | safe }} hired {{ event["leader"].leader_class }} {{ links[event["leader"]] | safe}}. + The {{ links[event["country"]] | safe }} hired + {{ render_leader(event) }}.
@@ -574,7 +598,7 @@

{{title[object] | safe}}

{{event["start_date"]}}: - {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}} + {{ render_leader(event, "An unknown leader") }} left the service of the {{ links[event["country"]] | safe }}.
@@ -584,7 +608,7 @@

{{title[object] | safe}}

{{event["start_date"]}}: - {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}} + {{ render_leader(event, "An unknown leader") }} changed their ethic to {{ event["description"] }}.
@@ -595,7 +619,7 @@

{{title[object] | safe}}

{{event["start_date"]}}: - {% if "leader" in event %} Under the rule of {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}, the + {% if "leader" in event %} Under the rule of {{ render_leader(event) }}, the {% else %} The {% endif %} {{ links[event["country"]] | safe }} created the {{ event["description"] }} sector{% if "planet" in event %} @@ -619,7 +643,7 @@

{{title[object] | safe}}

{{event["start_date"]}}: - {% if "leader" in event %} Under the rule of {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}, the + {% if "leader" in event %} Under the rule of {{ render_leader(event) }}, the {% else %} The {% endif %} {{ links[event["country"]] | safe }} entered the {{ links[event["war"]] | safe }} war{{ event["description"] }}{% if event["target_country"] %} {{ links[event["target_country"]] | safe}}{% endif %}. @@ -632,7 +656,7 @@

{{title[object] | safe}}

{{event["start_date"]}}: - {% if "leader" in event %} Under the rule of {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}, the + {% if "leader" in event %} Under the rule of {{ render_leader(event) }}, the {% else %} The {% endif %} {{ links[event["country"]] | safe }} made peace in the {{ links[event["war"]] | safe }} conflict. @@ -653,7 +677,7 @@

{{title[object] | safe}}

{% if event["is_active"] %}(A){% endif %} {{event["start_date"]}}{% if event["end_date"] != null %} - {{event["end_date"]}}{%endif%}: - {% if "leader" in event %} under the governorship of {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}, the {% endif %}{{ links[event["country"]] | safe }} + {% if "leader" in event %} under the governorship of {{ render_leader(event) }}, the {% endif %}{{ links[event["country"]] | safe }} terraformed the planet {{ links[event["planet"]] | safe }} in the {{ links[event["system"]] | safe }} system {{ event["description"] }}. @@ -674,7 +698,8 @@

{{title[object] | safe}}

{{event["start_date"]}}: - {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe }} died or retired. + {{ render_leader(event, "An unknown leader") }} + died or retired.
@@ -683,7 +708,8 @@

{{title[object] | safe}}

{% if event["is_active"] %}(A){% endif %} {{event["start_date"]}}{% if event["end_date"] != null %} - {{event["end_date"]}}{%endif%}: - {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe }} commanded the + {{ render_leader(event, "An unknown leader") }} + {% if event["fleat"].is_civilian_fleet %} commanded {% else %} led {% endif %} the {% if event["fleet"].is_civilian_fleet %} science ship {% else %} fleet {% endif %} "{{ event["fleet"].rendered_name }}". From 7a5e99e7c9dfbc028fbc7af0e3b08a931ffdbfd3 Mon Sep 17 00:00:00 2001 From: Michael Moore Date: Sat, 14 Dec 2024 19:10:31 -0600 Subject: [PATCH 4/6] Fix memory leak from shared_description cache, fixes #163 --- stellarisdashboard/parsing/timeline.py | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/stellarisdashboard/parsing/timeline.py b/stellarisdashboard/parsing/timeline.py index 4468961..0f112df 100644 --- a/stellarisdashboard/parsing/timeline.py +++ b/stellarisdashboard/parsing/timeline.py @@ -21,6 +21,17 @@ def dump_name(name: dict): return json.dumps(name, sort_keys=True) +@cache +def _get_or_add_shared_description(session, text: str) -> datamodel.SharedDescription: + matching_description = ( + session.query(datamodel.SharedDescription) + .filter_by(text=text) + .one_or_none() + ) + if matching_description is None: + matching_description = datamodel.SharedDescription(text=text) + session.add(matching_description) + return matching_description @dataclasses.dataclass class BasicGameInfo: @@ -72,6 +83,7 @@ def process_gamestate(self, game_id: str, gamestate_dict: Dict[str, Any]): ) if config.CONFIG.debug_mode or isinstance(e, KeyboardInterrupt): raise e + _get_or_add_shared_description.cache_clear() def _check_if_gamestate_exists(self, db_game): existing_dates = {gs.date for gs in db_game.game_states} @@ -251,17 +263,8 @@ def data(self) -> Any: def extract_data_from_gamestate(self, dependencies: Dict[str, Any]): pass - @cache def _get_or_add_shared_description(self, text: str) -> datamodel.SharedDescription: - matching_description = ( - self._session.query(datamodel.SharedDescription) - .filter_by(text=text) - .one_or_none() - ) - if matching_description is None: - matching_description = datamodel.SharedDescription(text=text) - self._session.add(matching_description) - return matching_description + _get_or_add_shared_description(self._session, text) class SystemProcessor(AbstractGamestateDataProcessor): From 4c1133578de40ddb361a7dbce225d4503ef788be Mon Sep 17 00:00:00 2001 From: Michael Moore Date: Sat, 14 Dec 2024 20:01:14 -0600 Subject: [PATCH 5/6] use a more naive cache for shared_descriptions to fix issues with sqlalchemy --- stellarisdashboard/parsing/timeline.py | 28 +++++++++++++------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/stellarisdashboard/parsing/timeline.py b/stellarisdashboard/parsing/timeline.py index 0f112df..3a03955 100644 --- a/stellarisdashboard/parsing/timeline.py +++ b/stellarisdashboard/parsing/timeline.py @@ -2,7 +2,6 @@ import collections import dataclasses import datetime -from functools import cache import itertools import json import logging @@ -21,17 +20,7 @@ def dump_name(name: dict): return json.dumps(name, sort_keys=True) -@cache -def _get_or_add_shared_description(session, text: str) -> datamodel.SharedDescription: - matching_description = ( - session.query(datamodel.SharedDescription) - .filter_by(text=text) - .one_or_none() - ) - if matching_description is None: - matching_description = datamodel.SharedDescription(text=text) - session.add(matching_description) - return matching_description +_shared_description_cache: dict[str, datamodel.SharedDescription] = {} @dataclasses.dataclass class BasicGameInfo: @@ -83,7 +72,7 @@ def process_gamestate(self, game_id: str, gamestate_dict: Dict[str, Any]): ) if config.CONFIG.debug_mode or isinstance(e, KeyboardInterrupt): raise e - _get_or_add_shared_description.cache_clear() + _shared_description_cache.clear() def _check_if_gamestate_exists(self, db_game): existing_dates = {gs.date for gs in db_game.game_states} @@ -264,7 +253,18 @@ def extract_data_from_gamestate(self, dependencies: Dict[str, Any]): pass def _get_or_add_shared_description(self, text: str) -> datamodel.SharedDescription: - _get_or_add_shared_description(self._session, text) + if text in _shared_description_cache: + return _shared_description_cache[text] + matching_description = ( + self._session.query(datamodel.SharedDescription) + .filter_by(text=text) + .one_or_none() + ) + if matching_description is None: + matching_description = datamodel.SharedDescription(text=text) + self._session.add(matching_description) + _shared_description_cache[text] = matching_description + return matching_description class SystemProcessor(AbstractGamestateDataProcessor): From e1d4bad7570aa03f8ce13fd45c20cffb34b4542e Mon Sep 17 00:00:00 2001 From: Michael Moore Date: Sat, 14 Dec 2024 20:54:45 -0600 Subject: [PATCH 6/6] Add comment about _shared_description_cache --- stellarisdashboard/parsing/timeline.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/stellarisdashboard/parsing/timeline.py b/stellarisdashboard/parsing/timeline.py index 3a03955..fc9fc56 100644 --- a/stellarisdashboard/parsing/timeline.py +++ b/stellarisdashboard/parsing/timeline.py @@ -20,6 +20,9 @@ def dump_name(name: dict): return json.dumps(name, sort_keys=True) +# this is a naive cache for shared_descriptions, which helps to cut down on DB queries while processing +# it needs to be cleared between processing saves (at the end of TimelineExtractor.process_gamestate) +# the built-in @cache decorator was leaking memory, hanging on to references of processor instances _shared_description_cache: dict[str, datamodel.SharedDescription] = {} @dataclasses.dataclass @@ -72,6 +75,8 @@ def process_gamestate(self, game_id: str, gamestate_dict: Dict[str, Any]): ) if config.CONFIG.debug_mode or isinstance(e, KeyboardInterrupt): raise e + + # needs to be cleared between processing saves, see more notes at declaration _shared_description_cache.clear() def _check_if_gamestate_exists(self, db_game):