Module:European and national party data
![]() | This module is rated as beta, and is ready for widespread use. It is still new and should be used with some caution to ensure the results are as expected. |
![]() | This module is subject to page protection. It is a highly visible module in use by a very large number of pages, or is substituted very frequently. Because vandalism or mistakes would affect many pages, and even trivial editing might cause substantial load on the servers, it is protected from editing. |
Usage
{{#invoke:European and national party data|main|<party_type>|<data_type>|<party>|<institution>|extra parameters}}
Parameters
Parameter | Description |
---|---|
1 | The type of party under consideration; can be either:
This parameter is mandatory. |
2 | The type of data requested and pulled from Wikidata, from the following list:
This parameter is mandatory. |
3 | The name of the entity, from the following list:
This parameter is optional when called from the page of the entity in question. The following acronyms are used for European parties:
In addition, the following European political alliances are covered:
In addition, four special parameters can be used instead of European parties (so not when
Notes:
|
4 | The name of the institution, from the following list:
Notes:
This parameter is mandatory when |
extra parameters | The following extra parameters can also be used, depending on the requested data_type :
These parameters are optional. |
Related templates
The module is directly implemented by three templates:
- Template:EUPP data, which presets
|party_type=european_entity
; - Template:Political party data, which presets
|party_type=national_party
; and - Template:EU institution seats, which only returns the number of seats of EU institutions (including all lower or upper houses combined).
Test cases
The module has two testcase pages:
- Module:European and national party data/testcases composition bar for the
seat composition bar
data type; and - Module:European and national party data/testcases for all other data types.
Updating the module
The module draws its data from two sources:
- Wikidata for all data points returned by the module; and
- commons:Data:Mapping of national parties members of European parties to lower and upper houses.tab which maps the national member parties of European political parties and also serves to link member states (and, therefore, national parties) to their lower and upper houses.
To update data returned by the module, go to the Wikidata page of the entity in question (the link is often provided as a comment in the infobox of the Wikipedia article), and edit the relevant property, preferably by adding a new value and marking it as preferred (instead of deleting outdated information).
Here are some relevant properties for the module:
- number of seats in assembly: P1410, with the following qualifiers:
- short name/acronym: P1813
- colour/sRGB color hex triplet: P465
- country: P17
- foundation date: P571
- individual members: P2124
- official name: P1448
- parliamentary group: P4100
- public funding: P12919
- official website: P856
Wherever possible, try and add:
- a
start time
(P580) qualifier (and a matchingend time
(P582) in the outdated entry) or apoint in time
(P585) qualifier, and - a reference, including the
reference URL
(P854),title
(P1476),retrieved
(P813), andpublisher
qualifiers (P123).
Updating Wikidata ensures that updated and sourced information is available not just to this Wiki, but to all versions of Wikipedia, as well as to other services drawing information from Wikidata.
Examples
Data type seats
Code | Result | Output |
---|---|---|
{{#invoke:European and national party data|main|european_entity|seats|EPP|EP}}
|
Error: {{EUPP seats}}: unknown institution: EUROPEAN_ENTITY (help) | number of seats of the European People's Party in the European Parliament |
{{#invoke:European and national party data|main|european_entity|seats|PES|EC|reference=yes}}
|
Error: {{EUPP seats}}: unknown institution: EUROPEAN_ENTITY (help) | number of seats of the Party of European Socialists in the European Commission, with reference |
{{#invoke:European and national party data|main|european_entity|seats|ind|EUCO}}
|
Error: {{EUPP seats}}: unknown institution: EUROPEAN_ENTITY (help) | number of seats of independent politicians in the European Council |
{{#invoke:European and national party data|main|european_entity|seats|ALDE|ms-lower-house}}
|
Error: {{EUPP seats}}: unknown institution: EUROPEAN_ENTITY (help) | number of seats of the Alliance of Liberals and Democrats for Europe in member states' lower houses |
{{#invoke:European and national party data|main|european_entity|seats|EGP|ms-upper-house|reference=yes}}
|
Error: {{EUPP seats}}: unknown institution: EUROPEAN_ENTITY (help) | number of seats of the European Green Party in member states' upper houses, without reference (see table above) |
{{#invoke:European and national party data|main|european_entity|seats|Q208242|EC}}
|
Error: {{EUPP seats}}: unknown institution: EUROPEAN_ENTITY (help) | number of seats of the European People's Party (called by its Wikidata qID) in the European Commission |
{{#invoke:European and national party data|main|european_entity|seats|Q208242|ms-upper-house}}
|
Error: {{EUPP seats}}: unknown institution: EUROPEAN_ENTITY (help) | number of seats of the European People's Party (called by its Wikidata qID) in member states' upper houses |
{{#invoke:European and national party data|main|national_party|seats|Q13564543|ms-lower-house|reference=yes}}
|
Error: {{EUPP seats}}: unknown institution: NATIONAL_PARTY (help) | number of seats of Austria's NEOS (called by its Wikidata qID) in the National Council, with reference |
{{#invoke:European and national party data|main|national_party|seats|Q138198|ms-upper-house}}
|
Error: {{EUPP seats}}: unknown institution: NATIONAL_PARTY (help) | number of seats of the Spanish Socialist Workers' Party (called by its Wikidata qID) in the Senate |
{{#invoke:European and national party data|main|national_party|seats|Q49768|EP}}
|
Error: {{EUPP seats}}: unknown institution: NATIONAL_PARTY (help) | number of seats of the Social Democratic Party of Germany (called by its Wikidata qID) in the European Parliament |
{{#invoke:European and national party data|main|european_entity|seats|all|EP}}
|
Error: {{EUPP seats}}: unknown institution: EUROPEAN_ENTITY (help) | number of seats of all European parties combined in the European Parliament |
{{#invoke:European and national party data|main|european_entity|seats|none|EP}}
|
Error: {{EUPP seats}}: unknown institution: EUROPEAN_ENTITY (help) | number of seats not occupied by European parties in the European Parliament |
Data type seat share
Code | Result | Output |
---|---|---|
{{#invoke:European and national party data|main|european_entity|seat share|EPP|EP|reference=yes}}
|
Error: {{EUPP seats}}: unknown institution: EUROPEAN_ENTITY (help) | share of seats of the European People's Party in the European Parliament, with reference |
{{#invoke:European and national party data|main|european_entity|seat share|ind|EUCO}}
|
Error: {{EUPP seats}}: unknown institution: EUROPEAN_ENTITY (help) | share of seats of independent politicians in the European Council |
{{#invoke:European and national party data|main|european_entity|seat share|ALDE|ms-lower-house}}
|
Error: {{EUPP seats}}: unknown institution: EUROPEAN_ENTITY (help) | share of seats of the Alliance of Liberals and Democrats for Europe in member states' lower houses |
{{#invoke:European and national party data|main|european_entity|seat share|Q208242|EC}}
|
Error: {{EUPP seats}}: unknown institution: EUROPEAN_ENTITY (help) | share of seats of the European People's Party (called by its Wikidata qID) in the European Commission |
{{#invoke:European and national party data|main|national_party|seat share|Q13564543|ms-lower-house}}
|
Error: {{EUPP seats}}: unknown institution: NATIONAL_PARTY (help) | share of seats of Austria's NEOS (called by its Wikidata qID) in the National Council |
{{#invoke:European and national party data|main|national_party|seat share|Q655611|ms-lower-house|constituency=61}}
|
Error: {{EUPP seats}}: unknown institution: NATIONAL_PARTY (help) | share of seats of Belgium's Écolo (called by its Wikidata qID) in the French-speaking seats of the Chamber of Representatives |
{{#invoke:European and national party data|main|national_party|seat share|Q49768|EP|reference=yes}}
|
Error: {{EUPP seats}}: unknown institution: NATIONAL_PARTY (help) | share of seats of the Social Democratic Party of Germany (called by its Wikidata qID) in the European Parliament, with reference |
{{#invoke:European and national party data|main|european_entity|seat share|all|EP}}
|
Error: {{EUPP seats}}: unknown institution: EUROPEAN_ENTITY (help) | share of seats of all European parties combined in the European Parliament |
Data type seat composition bar
Code | Result | Output |
---|---|---|
{{#invoke:European and national party data|main|european_entity|seat composition bar|EPP|EP|reference=yes}}
|
Error: {{EUPP seats}}: unknown institution: EUROPEAN_ENTITY (help) | composition bar of seats of the European People's Party in the European Parliament, with reference |
{{#invoke:European and national party data|main|european_entity|seat composition bar|ind|EUCO|percent=yes}}
|
Error: {{EUPP seats}}: unknown institution: EUROPEAN_ENTITY (help) | composition bar of seats of independent politicians in the European Council, with reference |
{{#invoke:European and national party data|main|european_entity|seat composition bar|ALDE|ms-lower-house}}
|
Error: {{EUPP seats}}: unknown institution: EUROPEAN_ENTITY (help) | composition bar of seats of the Alliance of Liberals and Democrats for Europe in member states' lower houses |
{{#invoke:European and national party data|main|european_entity|seat composition bar|Q208242|EC|percent=yes|reference=yes}}
|
Error: {{EUPP seats}}: unknown institution: EUROPEAN_ENTITY (help) | composition bar of seats of the European People's Party (called by its Wikidata qID) in the European Commission, with reference |
{{#invoke:European and national party data|main|national_party|seat composition bar|Q655611|ms-lower-house|constituency=61}}
|
Error: {{EUPP seats}}: unknown institution: NATIONAL_PARTY (help) | composition bar of seats of Belgium's Écolo (called by its Wikidata qID) in the French-speaking seats of the Chamber of Representatives |
{{#invoke:European and national party data|main|national_party|seat composition bar|Q49768|EP|width=80%|background-color=blue|border=green|bar-color=red}}
|
Error: {{EUPP seats}}: unknown institution: NATIONAL_PARTY (help) | composition bar of seats of the Social Democratic Party of Germany (called by its Wikidata qID) in the European Parliament, with special parameters |
{{#invoke:European and national party data|main|european_entity|seat composition bar|all|EP|width=80%|background-color=#FFFF00|border=#008080|bar-color=#A020F0}}
|
Error: {{EUPP seats}}: unknown institution: EUROPEAN_ENTITY (help) | composition bar of seats of all European parties combined in the European Parliament, with special parameters |
Other data types
Code | Result | Output |
---|---|---|
{{#invoke:European and national party data|main|european_entity|acronym|EPP}}
|
Error: {{EUPP seats}}: unknown institution: EUROPEAN_ENTITY (help) | acronym of the European People's Party |
{{#invoke:European and national party data|main|european_entity|color|PES}}
|
Error: {{EUPP seats}}: unknown institution: EUROPEAN_ENTITY (help) | colour of the Party of European Socialists |
{{#invoke:European and national party data|main|national_party|country|Q1315362}}
|
Error: {{EUPP seats}}: unknown institution: NATIONAL_PARTY (help) | country of Levice (called by its Wikidata qID) |
{{#invoke:European and national party data|main|european_entity|foundation date|PES}}
|
Error: {{EUPP seats}}: unknown institution: EUROPEAN_ENTITY (help) | foundation date of the Party of European Socialists |
{{#invoke:European and national party data|main|european_entity|individual members|EPP|reference=yes}}
|
Error: {{EUPP seats}}: unknown institution: EUROPEAN_ENTITY (help) | individual members of the European People's Party, with reference |
{{#invoke:European and national party data|main|european_entity|individual members date|EPP}}
|
Error: {{EUPP seats}}: unknown institution: EUROPEAN_ENTITY (help) | date of reference for individual members of the European People's Party |
{{#invoke:European and national party data|main|european_entity|individual members date|Volt}}
|
Error: {{EUPP seats}}: unknown institution: EUROPEAN_ENTITY (help) | date of reference for individual members of Volt (year only) |
{{#invoke:European and national party data|main|european_entity|individual members year|EPP}}
|
Error: {{EUPP seats}}: unknown institution: EUROPEAN_ENTITY (help) | year of reference for individual members of the European People's Party |
{{#invoke:European and national party data|main|european_entity|individual members year|Volt}}
|
Error: {{EUPP seats}}: unknown institution: EUROPEAN_ENTITY (help) | year of reference for individual members of Volt (year only) |
{{#invoke:European and national party data|main|european_entity|label|ALDE}}
|
Error: {{EUPP seats}}: unknown institution: EUROPEAN_ENTITY (help) | label of the Alliance of Liberals and Democrats for Europe |
{{#invoke:European and national party data|main|european_entity|official name|EGP}}
|
Error: {{EUPP seats}}: unknown institution: EUROPEAN_ENTITY (help) | official name of the European Green Party |
{{#invoke:European and national party data|main|european_entity|parliamentary group|EFA}}
|
Error: {{EUPP seats}}: unknown institution: EUROPEAN_ENTITY (help) | parliamentary group of the European Free Alliance |
{{#invoke:European and national party data|main|european_entity|public funding|EGP}}
|
Error: {{EUPP seats}}: unknown institution: EUROPEAN_ENTITY (help) | public funding of the European Green Party, with reference |
{{#invoke:European and national party data|main|national_party|website|Q667680}}
|
Error: {{EUPP seats}}: unknown institution: NATIONAL_PARTY (help) | website of the Netherlands' GroenLinks |
{{#invoke:European and national party data|main|national_party|official name|Q22748|verbose=yes}}
|
Error: {{EUPP seats}}: unknown institution: NATIONAL_PARTY (help) | official name of Germany Die PARTEI, showing verbose error message |
require ('strict');
local get_args = require ('Module:Arguments').getArgs; -- function to fetch frame and parent frame arguments
local cfg = mw.loadData ('Module:EUPP seats/config'); -- defines, configuration data, and i18n support
local namespace = mw.title.getCurrentTitle().namespace; -- used for categorization
--[[--------------------------< S U B S T I T U T E >----------------------------------------------------------
Substitutes $1, $2, etc in <message> with data from <data_t>. Returns plain-text substituted string when
<data_t> not nil; returns <message> else.
]]
local function substitute (message, data_t)
return data_t and mw.message.newRawMessage (message, data_t):plain() or message;
end
--[[--------------------------< M A K E _ E R R O R _ M S G >--------------------------------------------------
Assembles an error message from template name, message text, help link, and error category.
]]
local function make_error_msg (msg, template_name, nocat)
local category;
local category_link = ((0 == namespace) and not nocat) and substitute ('[[Category:$1]]', {cfg.settings_t.err_category}) or '';
return substitute ('<span style="color:#d33">Error: {{$1}}: $2 ([[:Template:$1|$3]])</span>$4',
{
template_name or cfg.settings_t.template_name, -- the template name without namespace
msg, -- the error message
cfg.settings_t.help, -- help wikilink display text
category_link -- link to error category (main namespace only)
})
end
--[[--------------------------< R O U N D >--------------------------------------------------------------------
return the rounded value of the arguments with two digits
]]
local function round (n)
return math.floor(100 * n + 0.5) / 100 -- round argument to two decimals
end
--[[--------------------------< S U M >------------------------------------------------------------------------
return the sum of seats for all parties of <institution> listed in <cfg.parties_t> (so not including lower and upper houses). <body_prop> is the wikidata
property:
P194: legislative body
P208: executive body
<frame> required to expand {{wikidata}} template
Note: P1410 is the property "number of seats in assembly", used to record an entity's seats in legislative or executive bodies
]]
local function sum (frame, institution, body_prop)
local sum = 0; -- init
local args_t = {[1]='property', [3]='P1410'}; -- init some of the {{wikidata}} parameters
args_t[body_prop] = cfg.institutions_t[institution];
for _, qid in pairs (cfg.parties_t) do -- loop through all parties in <cfg.parties_t>
args_t[2] = qid; -- set the last {{wikidata}} parameter
sum = sum + frame:expandTemplate ({title='wikidata', args = args_t}); -- expand and tally
end
return sum;
end
--[[--------------------------< G E T _ C O L O U R >----------------------------------------------------------
return the hex colour of a European party with '#' prefix
<frame> required to expand {{wikidata}} template
]]
local function get_colour (frame, party)
local args_t = {'property'}; -- build an arguments table for expandTemplate()
if party ~= "THISPARTY" then -- when not on a party page
if cfg.parties_t[party] then
table.insert (args_t, cfg.parties_t[party]); -- must name the party
elseif cfg.alliances_t[party] then
table.insert (args_t, cfg.alliances_t[party]); -- must name the alliance
end
end
table.insert (args_t, 'P465'); -- last argument is P465; sRGB color hex triplet property
local color = frame:expandTemplate ({title='wikidata', args = args_t}); -- get the color
if '' == color then -- if no color
color = 'BBB'; -- use a default color; some sort of gray
end
return '#' .. color; -- add the '#' prefix
end
--[[--------------------------< G E T _ R E F >---------------------------------------------------------------
return the reference for a seat claim relating to <institution> listed in <cfg.parties_t> or in <cfg.alliances_t> (so not including lower and upper houses)
<frame> required to expand {{wikidata}} template
]]
local function get_ref (frame, institution, party)
if institution == 'EP' or institution == 'COR' then
if party == "THISPARTY" then
return frame:expandTemplate ({title='wikidata', args = {'references', 'P1410', P194 = cfg.institutions_t[institution]}});
elseif cfg.parties_t[party] then
return frame:expandTemplate ({title='wikidata', args = {'references', cfg.parties_t[party], 'P1410', P194 = cfg.institutions_t[institution]}});
elseif cfg.alliances_t[party] then
return frame:expandTemplate ({title='wikidata', args = {'references', cfg.alliances_t[party], 'P1410', P194 = cfg.institutions_t[institution]}});
end
elseif institution == 'EP' or institution == 'COR' then
if party == "THISPARTY" then
return frame:expandTemplate ({title='wikidata', args = {'references', 'P1410', P208 = cfg.institutions_t[institution]}});
elseif parties_t[party] then
return frame:expandTemplate ({title='wikidata', args = {'references', cfg.parties_t[party], 'P1410', P208 = cfg.institutions_t[institution]}});
elseif alliances_t[party] then
return frame:expandTemplate ({title='wikidata', args = {'references', cfg.alliances_t[party], 'P1410', P208 = cfg.institutions_t[institution]}});
end
end
end
local function get_ref_qid (frame, institution_qid)
return frame:expandTemplate ({title='wikidata', args = {'references', 'P1410', P194 = institution_qid}});
end
--[[--------------------------< S I N G L E >------------------------------------------------------------------
return the number of seats occupied by one party in an <institution> listed in <cfg.parties_t> or in <cfg.alliances_t> (so not including lower and upper houses). <body_prop> is the wikidata property:
P194: legislative body
P208: executive body
<frame> required to expand {{wikidata}} template
Note: P1410 is the property "number of seats in assembly", used to record an entity's seats in legislative or executive bodies
]]
local function single (frame, institution, party, body_prop)
local args_t = {};
if party == "THISPARTY" then -- flag used when module is called from the page of a European party; less expensive
args_t = {'property', 'P1410'}; -- init some of the {{wikidata}} parameters with THISPARTY (only when called from the page of a European party)
elseif cfg.alliances_t[party] then
args_t = {'property', cfg.alliances_t[party], 'P1410'}; -- init some of the {{wikidata}} parameters
else
args_t = {'property', cfg.parties_t[party], 'P1410'}; -- init some of the {{wikidata}} parameters
end
args_t[body_prop] = cfg.institutions_t[institution];
local retval = frame:expandTemplate ({title='wikidata', args = args_t})
if '' == retval then -- {{wikidata}} returns empty string when <party> not known to <institution>
if party == "THISPARTY" then -- specific error message if the module was called with THISPARTY from the wrong page
return make_error_msg (cfg.error_messages_t.thisparty);
elseif not party then
return make_error_msg (substitute (cfg.error_messages_t.party_req_share));
else
return make_error_msg (substitute (cfg.error_messages_t.inst_unknown_party, {institution, party}));
end
end
return retval;
end
--[[--------------------------< S H A R E _ F C >--------------------------------------------------------------
return the share of a party's seats relative to the total size of a given institution listed in <cfg.parties_t> or <cfg.alliances_t> (so not including lower and upper houses)
<frame> required to expand {{wikidata}} template
Note: P1342 is the property "number of seats", used to record an institution's number of seats
]]
local function share_fc (frame, party_seats, institution)
return tonumber (party_seats) and round (100 * party_seats / frame:expandTemplate ({title='wikidata', args = {'property', cfg.institutions_t[institution], 'P1342'}})) or party_seats;
end
--[[--------------------------< S E A T S >--------------------------------------------------------------------
return a number of seats either for an institution or occupied by one or more parties, or by none of them, in an <institution> listed in <cfg.parties_t> or <cfg.alliances_t> (so not including lower and upper houses).
<frame> required to expand {{wikidata}} template
Note:
* P1410 is the property "number of seats in assembly", used to record an entity's seats in legislative or executive bodies
* P1342 is the property "number of seats", used to record an institution's number of seats
* P208 is the property "executive body"
* P194 is the property "legislative body"
]]
local function seats (frame, institution, party)
if not party then -- party not specified, returns seats of the institution
return frame:expandTemplate ({title='wikidata', args = {'property', cfg.institutions_t[institution], 'P1342'}});
elseif party == "IND" and institution == "EUCO" then -- special case of independent politicians on European Council
return frame:expandTemplate ({title='wikidata', args = {'property', cfg.misc_parties_t['IND'], 'P1410', P208 = cfg.institutions_t[institution]}});
elseif party == "NONE" then -- returns seats not occupied by European parties
local retval = frame:expandTemplate ({title='wikidata', args = {'property', cfg.institutions_t[institution], 'P1342'}}); -- get number of seats in the institution
if institution == "EUCO" then -- if EUCO, use P208 and separate case to account for independent politicians
local ind = frame:expandTemplate ({title='wikidata', args = {'property', cfg.misc_parties_t['IND'], 'P1410', P208 = cfg.institutions_t[institution]}});
return retval - (sum (frame, institution, cfg.body_prop_t[institution]) + ind);
else -- COR, EC, EP
return retval - sum (frame, institution, cfg.body_prop_t[institution]);
end
elseif party == "ALL" then -- returns seats occupied by all European parties combined
return sum (frame, institution, cfg.body_prop_t[institution]);
else -- returns the number of seats occupied by one party in one institution
return single (frame, institution, party, cfg.body_prop_t[institution]);
end
end
--[[--------------------------< S E A T S _ S H A R E >--------------------------------------------------------
return a share of seats occupied by one or more parties, or by none of them, in an <institution> listed in <cfg.parties_t> or <cfg.alliances_t> (so not including lower and upper houses).
<frame> required to expand {{wikidata}} template
Note:
* P1410 is the property "number of seats in assembly", used to record an entity's seats in legislative or executive bodies
* P1342 is the property "number of seats", used to record an institution's number of seats
* P208 is the property "executive body"
* P194 is the property "legislative body"
]]
local function seats_share (frame, institution, party)
if party == "IND" and institution == "EUCO" then -- special case of independent politicians on European Council
return share_fc (frame, frame:expandTemplate ({title='wikidata', args = {'property', cfg.misc_parties_t['IND'], 'P1410', P208 = cfg.institutions_t[institution]}}), institution);
elseif party == "NONE" then -- returns seats not occupied by European parties
local retval = frame:expandTemplate ({title='wikidata', args = {'property', cfg.institutions_t[institution], 'P1342'}});
if institution == "EUCO" then -- if EUCO, use P208 and separate case to account for independent politicians
local ind = frame:expandTemplate ({title='wikidata', args = {'property', cfg.misc_parties_t['IND'], 'P1410', P208 = cfg.institutions_t[institution]}})
return share_fc (frame, retval - (sum (frame, institution, cfg.body_prop_t[institution]) + ind), institution);
else -- for COR, EC, EP
return share_fc (frame, retval - sum (frame, institution, cfg.body_prop_t[institution]), institution);
end
elseif party == "ALL" then -- returns seats occupied by all European parties combined
return share_fc (frame, sum (frame, institution, cfg.body_prop_t[institution]), institution);
else -- returns the number of seats occupied by one party in one institution
return share_fc (frame, single (frame, institution, party, cfg.body_prop_t[institution]), institution);
end
end
--[[--------------------------< V A L I D A T E _ W I D T H >--------------------------------------------------
validates data format for width parameter (for composition bar()); returns boolean true when valid; nil else
]]
local function validate_width (width)
local patterns_t = {'^%d+$', '^%d+px$', '^%d+%%$', '^%d+em$'}; -- valid <width> patterns
for i, pattern in ipairs (patterns_t) do -- loop through the patterns in <patterns_t>
if width:match (pattern) then -- is there a match?
return true; -- yes, done
end
end
end
--[[--------------------------< V A L I D A T E _ I N S T I T U T I O N _ P A R T Y >--------------------------
validates data format for institution and party parameters, for main() and compositionbar() for institutions listed in <cfg.parties_t> or <cfg.alliances_t> (so not including lower and upper houses)
returns boolean true when valid; error message else
]]
local function validate_institution_party (institution, party, template_name)
if not institution then -- institution is required
return make_error_msg (cfg.error_messages_t.missing_inst, template_name);
elseif not cfg.institutions_t[institution] then
return make_error_msg (substitute (cfg.error_messages_t.unknown_inst, {institution}), template_name); -- if institution is present, it must be known
end
if party == "%" or party == "SHARE" then -- if party is missing and %/share is entered instead
return make_error_msg (cfg.error_messages_t.party_req_share, template_name);
end
if party and not cfg.parties_t[party] and not cfg.alliances_t[party] and not cfg.misc_parties_t[party] and not cfg.keywords_t[party] then -- party is optional; but if party is present, it must be known
return make_error_msg (substitute (cfg.error_messages_t.unknown_party, {party}), template_name);
end
if 'THISPARTY' == party then -- 'THISPARTY' parameter only to be used by templates on European party articles
local frame = mw.getCurrentFrame(); -- we need a copy of the frame for this test
if '' == frame:expandTemplate ({title='wikidata', args = {'property', 'P1410', cfg.institutions_t[institution]}}) then -- empty string when this article not an EU party article
return make_error_msg (cfg.error_messages_t.thisparty , template_name);
end
end
return true;
end
--[[--------------------------< S T R I P _ H O U S E _ T Y P E >----------------------------------------------
strips down parts of the house type (for calls relating to lower and upper houses)
]]
local function strip_house_type (house_type)
if house_type == "LOWER-HOUSE" or house_type == "LOWER" or house_type == "MS-LOWER-HOUSE"then -- three accepted formats for input
return "LOWER-HOUSE"; -- format actually used in the code
elseif house_type == "UPPER-HOUSE" or house_type == "UPPER" or house_type == "MS-UPPER-HOUSE" then -- three accepted formats for input
return "UPPER-HOUSE"; -- format actually used in the code
else
return house_type;
end
end
--[[--------------------------< V A L I D A T E _ P A R T Y _ H O U S E _ T Y P E >----------------------------
validates data format for party name (for main() and compositionbar() for calls relating to lower and upper houses).
returns boolean true when valid; error message else
]]
local function validate_party_house_type (house_type, european_party, template_name)
if european_party and not cfg.parties_t[european_party] and not cfg.alliances_t[european_party] and not cfg.keywords_lower_upper_t[european_party] then -- party is optional; but if party is present, it must be known
return make_error_msg (substitute (cfg.error_messages_t.unknown_party, {european_party}), template_name);
end
if 'THISPARTY' == european_party then -- 'THISPARTY' parameter only to be used by templates on European party articles
local this_page_qid = mw.wikibase.getEntityIdForCurrentPage(); -- looking up qID of the page from which the call is made
if cfg.rev_parties_t[this_page_qid] then
return true; -- true if the <this_page_qid> matches a European party in the config file
end
if cfg.rev_alliances_t[this_page_qid] then
return true; -- true if the <this_page_qid> matches a European party in the config file
end
return make_error_msg (cfg.error_messages_t.thisparty , template_name);
end
return true;
end
--[[--------------------------< G E T _ H O U S E _ S E A T S >------------------------------------------------
returns the number of seats in a given lower or upper house (identified by a row in the master table) from
wikidata. When <house_type> not recognized or when <ms_data_t> does not have 'that' house, returns 0
]]
local function get_house_seats (frame, row, house_type)
local house_qid;
if house_type == "LOWER-HOUSE" then
house_qid = cfg.ms_data_t[row].lower_house_qid; -- get the lower house qid
elseif house_type == "UPPER-HOUSE" then
house_qid = cfg.ms_data_t[row].upper_house_qid; -- get the upper house qid
end
return house_qid and frame:expandTemplate ({title='wikidata', args = {'property', house_qid, 'P1342'}}) or 0; -- house_qid is nil when no upper or lower house
end
--[[--------------------------< S U M _ H O U S E _ S E A T S >------------------------------------------------
returns the total number of seats of all lower or upper houses in all member states.
]]
local function sum_house_seats (frame, house_type)
local sum_seats = 0; -- init sum of seats of European party's member parties in house_type
for row, _ in ipairs (cfg.ms_data_t) do -- for all member states
sum_seats = sum_seats + get_house_seats (frame, row, house_type); -- increase sum_seats
end
return sum_seats;
end
--[[--------------------------< G E T _ N A T I O N A L _ P A R T Y _ S E A T S >------------------------------
returns the number of seats occupied by a given party (identified by a given row in the master table) in the
lower or upper house of its member state from wikidata. When <house_type> not recognized or when <tab_data_t>
does not have 'that' house, returns 0
]]
local function get_national_party_seats (frame, row, house_type)
local house_qid = "";
local national_party_qid = cfg.tab_data_t[row].national_party_qid;
if house_type == "LOWER-HOUSE" then
house_qid = cfg.tab_data_t[row].lower_house_qid;
elseif house_type == "UPPER-HOUSE" then
house_qid = cfg.tab_data_t[row].upper_house_qid;
end
return house_qid and frame:expandTemplate ({title='wikidata', args = {'property', national_party_qid, 'P1410', P194 = house_qid}}) or 0;
end
--[[--------------------------< S U M _ N A T I O N A L _ P A R T Y _ S E A T S >------------------------------
returns the sum of seats occupied by all national parties members of a given European party in the lower or upper house of its member state.
]]
local function sum_national_party_seats (frame, european_party, house_type)
local sum_seats = 0; -- init sum of seats of European party's member parties in house_type
if not european_party then -- if no European party is listed, then returns the total number of seats of all lower or upper houses
sum_seats = sum_house_seats(frame, house_type);
else
for row, _ in ipairs (cfg.tab_data_t) do
if european_party == "ALL" then -- sum for all rows
sum_seats = sum_seats + get_national_party_seats (frame, row, house_type); -- increase sum_seats
elseif european_party == "THISPARTY" then -- if called from the page of a European party
local thisparty_qid = mw.wikibase.getEntityIdForCurrentPage(); -- get party qiD
local thisparty_name = cfg.rev_parties_t[thisparty_qid] or cfg.rev_alliances_t[thisparty_qid]; -- use party name or when no party use alliance name
if thisparty_name == cfg.tab_data_t[row]['european_party'] then
sum_seats = sum_seats + get_national_party_seats (frame, row, house_type); -- increase sum_seats
end
else
if european_party == cfg.tab_data_t[row]['european_party'] then
sum_seats = sum_seats + get_national_party_seats (frame, row, house_type); -- increase sum_seats
end
end
end
end
return sum_seats;
end
--[[--------------------------< M A I N >----------------------------------------------------------------------
implements {{EUPP seats}}
carries out input error detection, reporting, and function dispatching
]]
local function main (frame)
local args_t = get_args (frame); -- get arguments; empty string or whitespace positional parameters set to nil
local institution = args_t[1] and args_t[1]:upper(); -- force to upper case
local party = args_t[2] and args_t[2]:upper();
local share = args_t[3] and args_t[3]:upper();
--[=[ harmonise institution name (in case of lower/upper house) ]=]
institution = strip_house_type (institution); -- "ms-lower-house" and "lower" are turned to "lower-house" (same for upper house)
--[=[ data validation for institution and party ]=]
local is_valid = false;
if institution == "LOWER-HOUSE" or institution == "UPPER-HOUSE" then
is_valid = validate_party_house_type (institution, party, 'EUPP seats');
else
is_valid = validate_institution_party (institution, party, 'EUPP seats');
end
if true ~= is_valid then -- boolean true when valid; error message else
return is_valid; -- yep, abandon with error message
end
--[=[ function dispatching ]=]
if institution == "LOWER-HOUSE" or institution == "UPPER-HOUSE" then
if not share then
return sum_national_party_seats (frame, party, institution) -- return number of seats by calling sum_national_party_seats()
elseif share == "%" or share == "SHARE" then
return round (100 * sum_national_party_seats (frame, party, institution) / sum_house_seats (frame, institution)); -- return share of seats by calling seats_share()
else
return make_error_msg (substitute (cfg.error_messages_t.unknown_param, {share}));
end
else
if not share then
return seats (frame, institution, party); -- return number of seats by calling seats()
elseif share == "%" or share == "SHARE" then
return seats_share (frame, institution, party); -- return share of seats by calling seats_share()
else
return make_error_msg (substitute (cfg.error_messages_t.unknown_param, {share}));
end
end
end
--[[--------------------------< C O M P O S I T I O N _ B A R >------------------------------------------------
this function does whatever it is that {{composition bar}} does
implements {{EUPP composition bar}}
{{EUPP composition bar|<institution>|<party>|width=<width>|percent=yes|reference=yes|bar-color=<color>|background-color=<color>|border=<color>}}
]]
local function composition_bar (frame)
local args_t = get_args (frame); -- get arguments; empty string or whitespace positional parameters set to nil
local institution = args_t[1] and args_t[1]:upper(); -- force to upper case
local party = args_t[2] and args_t[2]:upper();
local width = args_t.width; -- must be a number, or number with unit suffix: 'px', '%', 'em'; whitespace not allowed
local percentage = args_t.percent and args_t.percent:lower(); --
percentage = 'yes' == percentage; -- make a boolean
local reference = args_t.reference and args_t.reference:lower();
reference = 'yes' == reference; -- make a boolean
local background_color = args_t['background-color'];
local border = args_t.border;
--[=[ harmonise institution name (in case of lower/upper house) ]=]
institution = strip_house_type (institution); -- "ms-lower-house" and "lower" are turned to "lower-house" (same for upper house)
--[=[ data validation for institution, party and width ]=]
local is_valid = false;
if institution == "LOWER-HOUSE" or institution == "UPPER-HOUSE" then
is_valid = validate_party_house_type (institution, party, 'EUPP composition bar');
else
is_valid = validate_institution_party (institution, party, 'EUPP composition bar');
end
if true ~= is_valid then -- boolean true when valid; error message else
return is_valid; -- yep, abandon with error message
end
if width and not validate_width (width) then
return make_error_msg (substitute (cfg.error_messages_t.parameter_invalid, {width}), 'EUPP composition bar'); -- yep, abandon with error message
end
--[=[ prepare arguments for composition bar ]=]
if institution == "LOWER-HOUSE" or institution == "UPPER-HOUSE" then
local sum_house_seats = sum_house_seats(frame, institution); -- get total seats of lower or upper houses
local sum_national_party_seats = sum_national_party_seats(frame, party, institution) -- get sum of seats occupied by members of a European party
local color = args_t['bar-color'] or get_colour (frame, party); -- get color associated with <party>; |bar-color= overrides wikidata
local comp_bar_args_t = {
sum_national_party_seats,
sum_house_seats,
color,
width=width,
per=percentage,
['background-color'] = background_color,
border = border,
}
return frame:expandTemplate ({title='Composition bar', args = comp_bar_args_t});
else
local inst_seats = seats (frame, institution); -- get total seats in <institution>
local party_seats = seats (frame, institution, party); -- get total seats in <institution> occupied by <party>
local color = args_t['bar-color'] or get_colour (frame, party); -- get color associated with <party>; |bar-color= overrides wikidata
local comp_bar_args_t = {
party_seats,
inst_seats,
color,
width=width,
per=percentage,
['background-color'] = background_color,
border = border,
}
return frame:expandTemplate ({title='Composition bar', args = comp_bar_args_t}) .. ((reference and get_ref (frame, institution, party)) or '');
end
end
--[[--------------------------< N A T I O N A L _ P A R T Y _ C O M P O S I T I O N _ B A R >------------------------------------------------
this function does whatever it is that {{composition bar}} does
implements {{EUPP national party}}
{{EUPP national party|<ms-lower/upper-house>|constituency=<constituency>|width=<width>|percent=yes|reference=yes|bar-color=<color>|background-color=<color>|border=<color>}}
]]
local function national_party_composition_bar (frame)
local args_t = get_args (frame); -- get arguments; empty string or whitespace positional parameters set to nil
local house_type = args_t[1] and args_t[1]:upper(); -- force to upper case
local house_qid = "";
local house_seats = 0;
local constituency = args_t['constituency']; -- argument overriding the house's number of seats
local party = "THISPARTY";
local thisparty_qid = mw.wikibase.getEntityIdForCurrentPage();
local width = args_t.width; -- must be a number, or number with unit suffix: 'px', '%', 'em'; whitespace not allowed
local percentage = args_t.percent and args_t.percent:lower(); --
percentage = 'yes' == percentage; -- make a boolean
local reference = args_t.reference and args_t.reference:lower();
reference = 'yes' == reference; -- make a boolean
local background_color = args_t['background-color'];
local border = args_t.border;
--[=[ harmonise institution name (in case of lower/upper house) ]=]
house_type = strip_house_type (house_type); -- "ms-lower-house" and "lower" are turned to "lower-house" (same for upper house)
--[=[ data validation for qid, house_type, and width ]=]
if thisparty_qid == '' then
return make_error_msg (cfg.error_messages_t.no_qid, 'EUPP national party'); -- yep, abandon with error message
end
if house_type ~= "LOWER-HOUSE" and house_type ~= "UPPER-HOUSE" and house_type ~= "EP" then
return make_error_msg (substitute (cfg.error_messages_t.unknown_house_type, {house_type}), 'EUPP national party'); -- yep, abandon with error message
end
if width and not validate_width (width) then
return make_error_msg (substitute (cfg.error_messages_t.parameter_invalid, {width}), 'EUPP national party'); -- yep, abandon with error message
end
--[=[ get house_qid from party qid and house_seats ]=]
if house_type == "EP" then
house_qid = "Q8889";
else
for row, _ in ipairs (cfg.tab_data_t) do
if thisparty_qid == cfg.tab_data_t[row]['national_party_qid'] then
if house_type == "LOWER-HOUSE" then
house_qid = cfg.tab_data_t[row]['lower_house_qid']; -- get house_qid from lower_house_qid column
elseif house_type == "UPPER-HOUSE" then
house_qid = cfg.tab_data_t[row]['upper_house_qid']; -- get house_qid from upper_house_qid column
else
return make_error_msg (substitute (cfg.error_messages_t.unknown_house_type, {house_type}), 'EUPP national party'); -- yep, abandon with error message
end
end
end
end
if house_qid == "" then
return make_error_msg (substitute (cfg.error_messages_t.not_a_member_party, {thisparty_qid}), 'EUPP national party'); -- yep, abandon with error message
end
if constituency then
house_seats = constituency;
else
house_seats = house_qid and frame:expandTemplate ({title='wikidata', args = {'property', house_qid, 'P1342'}}) or 0; -- get total seats of lower or upper houses
end
--[=[ prepare arguments for composition bar ]=]
local national_party_seats = house_qid and frame:expandTemplate ({title='wikidata', args = {'property', thisparty_qid, 'P1410', P194 = house_qid}}) or 0;
local color = args_t['bar-color'] or get_colour (frame, party); -- get color associated with <party>; |bar-color= overrides wikidata
local comp_bar_args_t = {
national_party_seats,
house_seats,
color,
width=width,
per=percentage,
['background-color'] = background_color,
border = border,
}
local national_party_seats_data = frame:expandTemplate ({title='wikidata', args = {'property', thisparty_qid, 'P1410', P194 = house_qid}});
if national_party_seats_data == "" then
return make_error_msg (substitute (cfg.error_messages_t.no_data, {thisparty_qid}), 'EUPP national party');
else
return frame:expandTemplate ({title='Composition bar', args = comp_bar_args_t}) .. ((reference and get_ref_qid (frame, house_qid)) or '');
end
end
--[[--------------------------< T E S T >----------------------------------------------------------------------
]]
local function test (frame) -- to test calls and functions, for verification purposes
local args_t = get_args (frame); -- get arguments; empty string or whitespace positional parameters set to nil
--local institution = args_t[1] and args_t[1]:upper(); -- force to upper case
--local party = args_t[2] and args_t[2]:upper();
-- local share = args_t[3] and args_t[3]:upper();
local this_page_qid = mw.wikibase.getEntityIdForCurrentPage();
return this_page_qid;
--institution = strip_house_type (institution); -- here, testing strip_house_type
--return institution;
end
--[[--------------------------< T E S T _ W I K I D A T A _ E N T R I E S >----------------------------------------------------------------------
]]
local function test_wikidata_entries (frame) -- to test calls and functions, for verification purposes
local wikidata_error = "Wikidata entries error(s):";
for row, _ in ipairs (cfg.tab_data_t) do
local national_party_qid = cfg.tab_data_t[row].national_party_qid;
local national_party_name = "";
if not cfg.tab_data_t[row].national_party then
national_party_name = cfg.tab_data_t[row].national_party_english;
else
national_party_name = cfg.tab_data_t[row].national_party;
end
local lower_house_qid = cfg.tab_data_t[row].lower_house_qid;
local lower_house_name = cfg.tab_data_t[row].lower_house;
local upper_house_qid = cfg.tab_data_t[row].upper_house_qid;
local upper_house_name = cfg.tab_data_t[row].upper_house;
local retval_lower = frame:expandTemplate ({title='wikidata', args = {'property', national_party_qid, 'P1410', P194 = lower_house_qid}})
local retval_upper = frame:expandTemplate ({title='wikidata', args = {'property', national_party_qid, 'P1410', P194 = upper_house_qid}})
if '' == retval_lower then
wikidata_error = wikidata_error .. " [https://www.wikidata.org/wiki/" .. national_party_qid .. " " .. national_party_name .. "] (" .. lower_house_name .. ")";
end
if '' == retval_upper then
wikidata_error = wikidata_error .. " [https://www.wikidata.org/wiki/" .. national_party_qid .. " " .. national_party_name .. "] (" .. upper_house_name .. ")";
end
end
if wikidata_error == "Wikidata entries error(s):" then
wikidata_error = "Wikidata entries: all good!";
end
return wikidata_error;
end
--[[--------------------------< E X P O R T S >----------------------------------------------------------------
]]
return {
main = main,
composition_bar = composition_bar,
test = test,
test_wikidata_entries = test_wikidata_entries,
national_party_composition_bar = national_party_composition_bar,
}