Wikipedia talk:Lua/Archive 11

Page contents not supported in other languages.
From Wikipedia, the free encyclopedia

Template:Image array in Spanish

Is there a way to get Template:Image array made for spanish wikipedia?Kaidros (talk) 00:09, 27 January 2022 (UTC)

In what way does it need to be made for spanish wikipedia? Just copying Template:Image array and Module:Image array to es:Template:Image array and es:Module:Image array should work, as the template does not appear to contain any translatable content. * Pppery * it has begun... 00:19, 27 January 2022 (UTC)
Thank youKaidros (talk) 02:29, 27 January 2022 (UTC)

List of Marvel Cinematic Universe films is currently getting four "Lua error: not enough memory" errors at the bottom of the article. Can someone with knowledge of Lua help investigate where the error is? I feel it might have something to do with the transclusions happening on the article, possibly from Marvel Cinematic Universe: Phase Four. Thanks. - Favre1fan93 (talk) 04:01, 14 February 2022 (UTC)

A clue is that previewing an edit to the article without changing anything shows Lua memory usage of 52,428,798/52,428,800 bytes, while previewing after deleting the 12 lines with #section wikitext shows 13,761,835/52,428,800 bytes. I don't think the #section would be contributing to the increase from 13MB to 52MB—something in the included wikitext is doing that. Another clue is that there is a massive amount of Wikidata use and I can't see a reason for it—that might be in the included wikitext.
Previewing an edit after replacing the article content with the #section lines, as shown below, gives Lua memory usage 37,592,486/52,428,800 bytes.
{{#section:Marvel Cinematic Universe: Phase One|BoxOffice}}
{{#section:Marvel Cinematic Universe: Phase One|Films}}
{{#section:Marvel Cinematic Universe: Phase One|Response}}
{{#section:Marvel Cinematic Universe: Phase Two|BoxOffice}}
{{#section:Marvel Cinematic Universe: Phase Two|Films}}
{{#section:Marvel Cinematic Universe: Phase Three|BoxOffice}}
{{#section:Marvel Cinematic Universe: Phase Three|Films}}
{{#section:Marvel Cinematic Universe: Phase Three|Response}}
{{#section:Marvel Cinematic Universe: Phase Two|Response}}
{{#section:Marvel Cinematic Universe: Phase Four|BoxOffice}}
{{#section:Marvel Cinematic Universe: Phase Four|Films}}
{{#section:Marvel Cinematic Universe: Phase Four|Response}}
That's all I have time for now. Johnuniq (talk) 06:20, 14 February 2022 (UTC)
@Johnuniq: It likely could be the "Reception" section, pulling from {{#section:Marvel Cinematic Universe: Phase One|Response}} {{#section:Marvel Cinematic Universe: Phase Two|Response}} {{#section:Marvel Cinematic Universe: Phase Three|Response}} {{#section:Marvel Cinematic Universe: Phase Four|Response}}, all of which use Wikidata pulls to retrieve their Rotten Tomatoes scores and cite elements. - Favre1fan93 (talk) 12:52, 14 February 2022 (UTC)
Yes, that was my conclusion. The section called by {{#section:Marvel Cinematic Universe: Phase One|Response}} uses 15MB in preview at Marvel Cinematic Universe: Phase One. The expensive memory part seems to be {{RT data|edit}}, which adds 2-3MB for each call. This adds the edit wikidata icon to each reference, which isn't necesssary. The important {{RT data|table}} and {{RT data|access date}} calls are relatively cheap. —  Jts1882 | talk  14:44, 14 February 2022 (UTC)
I've given up on Wikidata—it's fragile and templates trying to use it are prone to break (although admittedly I haven't seen such breakage for a while), and it uses too many resources, and it has no effective method of monitoring or fixing vandalism. I would raise the issue at a noticeboard at Wikidata and ask if there is a low-cost method of achieving what is being done with {{RT data}}—it's something that needs to be fixed with a redesign. Or, perhaps just remove usage of that template. Johnuniq (talk) 01:53, 15 February 2022 (UTC)
I placed {{RT data|edit}} in <noinclude>...</noinclude>.[1] Labeled section transclusion apparently doesn't honor noinclude inside <ref>...</ref> so I changed it to #tag:ref in Marvel Cinematic Universe: Phase Three#Critical and public response.[2] That worked. List of Marvel Cinematic Universe films now renders fully with Lua memory usage 34,818,590/52,428,800 bytes. I think the list can do without Wikidata links but I haven't changed to #tag:ref in Phase One and Two so they still transclude the links. PrimeHunter (talk) 03:27, 15 February 2022 (UTC)
Good result, thanks. Johnuniq (talk) 04:08, 15 February 2022 (UTC)
Thank you all. PrimeHunter if you don't get to the #tag:ref changes on the Phase One, Two, and Four articles, I can take care of those. - Favre1fan93 (talk) 04:26, 15 February 2022 (UTC)
The #tag:ref code is unknown to many editors and may confuse some tools and source searches so I wonder whether there is a better solution. PrimeHunter (talk) 04:44, 15 February 2022 (UTC)
Should the edit wikidata icon and link be included in the reference list? What is the purpose? It doesn't help verify the information. —  Jts1882 | talk  07:52, 15 February 2022 (UTC)
@Jts1882: because the data is coming from Wikidata, and isn't coded directly on the article, it was added in the event an editor was trying to update the score on the article, and realized that they couldn't do it here, that it had to be done at Wikidata. If that isn't foreseen as an issue of someone unfamiliar with Wikidata not knowing that editing can occur there, then the edit icon can be removed and that probably solves this whole thing. - Favre1fan93 (talk) 17:31, 15 February 2022 (UTC)
I decided to move the Wikidata edit icons outside the references, which is friendlier for the section transclusion and noinclude tags. An example can be seen with my edit at the Phase One article here. That should solve the original issues, as well as the issue PrimeHunter came across switching to the #tag:ref code. - Favre1fan93 (talk) 20:33, 16 February 2022 (UTC)
I made an change to Module:EditAtWikidata, which is responsible for the RT edit link. On the revision prior to the noinclusion of {{RT data|edit}}, Special:Diff/1071924802, the Lua memory usage would drop by half from 31 million to 14 million bytes. Edit request pending at Module talk:EditAtWikidata#Performance change. Snævar (talk) 22:58, 17 February 2022 (UTC)

Tables

I am trying to understand tables in Lua. Please look at my simple example. I am expecting j to be the table {b,2} and I was expecting j[1] to be b. But the output is empty. — Martin (MSGJ · talk) 14:52, 23 February 2022 (UTC)

You need to set the letters as strings. So surround them with " or '. I'm also a bit surprised that the code ran without an error. Gonnym (talk) 15:03, 23 February 2022 (UTC)
The b you mentioned is an undefined variable, and it is nil. Lua does not raise errors for undefined vars. Please note the difference between variable name and string. --SolidBlock (talk) 15:10, 23 February 2022 (UTC)
Which is why it is always a good idea to require('Module:No globals').
Trappist the monk (talk) 15:38, 23 February 2022 (UTC)
Thanks everyone! It was actually Trappist's comment that led me to solve the real problem I was having [3] — Martin (MSGJ · talk) 17:04, 23 February 2022 (UTC)
Bear in mind that since the numbers are in quotes ("1", "2", ...), they are strings and will sort like strings so "10" is before "2". Johnuniq (talk) 23:35, 23 February 2022 (UTC)

Accessing template parameters

I have used the following code to access the first unnamed parameter from a template while also allowing direct use of #invoke

local pframe = frame:getParent()
local input = frame.args[1] or pframe.args[1]

Is this a good way to do it? — Martin (MSGJ · talk) 11:36, 24 February 2022 (UTC)

Consider Module:Arguments.
Trappist the monk (talk) 13:31, 24 February 2022 (UTC)
Some of us can't get our heads around Module:Arguments which complicates simple work. Using Arguments works, after you decode the documentation, but your method is fine for most cases. See what function dumphtml does to get two arguments at Module:Dump#L-134. Johnuniq (talk) 23:35, 24 February 2022 (UTC)
Yes that looks straightforward, thanks! — Martin (MSGJ · talk) 13:04, 25 February 2022 (UTC)

Regex help

Could someone help with the regex for the following? I want to scrape the names of the articles from the wikicode, and ignore piped links, i.e.

  • [[Bukhtishu|Bukhtishu family]] -> Bukhtishu
  • [[Ja'far al-Sadiq]] -> Ja'far al-Sadiq

I settled on string.match(article,'%[%[(.+)%|') or string.match(article,'%[%[(.+)%]%]') which seems to work but I think there is probably a more efficient way. Thanks — Martin (MSGJ · talk) 11:44, 24 February 2022 (UTC)

Maybe string.match(article,'%[%[(.+)%|?.+%]%]')? Not sure if .- would be better.—  Jts1882 | talk  13:24, 24 February 2022 (UTC)
I think I tried that one. The first capture was being too greedy and including the | as well. — Martin (MSGJ · talk) 14:54, 24 February 2022 (UTC)
The greediness was why I wondered if (.-) would work. What about ([^|]+) for anything but the pipe? —  Jts1882 | talk  17:08, 24 February 2022 (UTC)
You could try a regexp like %[%[[^%]]-([^%|%]]*)%]%]. With a [[piped|link]], [^%]]- matches and discards "piped|", then ([^%|%]]*) captures "link". If it's [[unpiped]], [^%]]- comes back empty and ([^%|%]]*) captures "unpiped". It isn't clever enough to handle piped text containing vertical bars such as C|T Group, nor File: links with captions etc. Certes (talk) 01:05, 25 February 2022 (UTC)

Automatic watchlist generator

The original request

Is it possible to create a module that automatically generates a list of pages from those listed in User:WP 1.0 bot/Tables/Project/India (for example, one list for Good Low-importance; another for Featured Mid-importance etc.), so that we can then use Special:RelatedChanges to track the changes. Similarly, another page where the list of the accompanying talk pages is generated for the same reason. Thanks! ---CX Zoom(he/him) (let's talk|contribs) 13:56, 25 February 2022 (UTC)

Alternatively, a module that takes in pages of a category, for example Category:FA-Class India articles of Mid-importance. Puts them all into a template like the one I created at User:CX Zoom/TestPage5 & thus, creates a related category dependent on the first one. See the template's usage & documentation at User:CX Zoom/TestPage8. This template automatically strips the talk part from the title of the page(s) if any. ---CX Zoom(he/him) (let's talk|contribs) 06:32, 26 February 2022 (UTC)

You already have categories like Category:FA-Class India articles of Mid-importance, etc. — Martin (MSGJ · talk) 07:20, 26 February 2022 (UTC)

These categories only consist of the talk pages of the various articles. Not the content pages. As such, it's possible to track changes happening in those categorised talk pages but it's not possible to track changes in the actual content pages using Special:RelatedChanges. I want to have something to do just that. ---CX Zoom(he/him) (let's talk|contribs) 08:27, 26 February 2022 (UTC)

I realise that I probably wasn't able to make my request clear, and I don't want to waste everyone's time. My request here is superceded by the request below. Thanks! ---CX Zoom(he/him) (let's talk|contribs) 08:38, 26 February 2022 (UTC)

Categories such as Category:FA-Class India articles of Mid-importance only consist of the talk pages of the various articles. Not the content pages. As such, it's possible to track changes happening in those talk pages but it's not possible to track changes in the actual content pages using Special:RelatedChanges. I want to have something to do just that. For example, Talk:Sholay is a member of this category. When I use Special:RelatedChanges for this category, recent edits on Talk:Sholay show up, but it's not possible to track changes happening in Sholay without going to those articles one by one. ---CX Zoom(he/him) (let's talk|contribs) 08:44, 26 February 2022 (UTC)

You are in the wrong forum. You would use JavaScript for that, not Lua. Snævar (talk) 18:03, 27 February 2022 (UTC)

Is there any module to create Wikipedia tables from Wikidata items?

Example: I want to create a table of books that has columns title, author, genre, description, date, all taken from Wikidata items. I would specify the type of statements (columns) only once, and specify the IDs of the specific books I want to be included on the table. It would create the table automatically, and I wouldn't need to mess with the Wikipedia table template.Iara Ai (talk) 19:42, 12 January 2022 (UTC)

I'm only just getting my head around the possibilities here. Are you aware of Category:Wikidata_tracking_categories? — Charles Stewart (talk) 23:47, 12 January 2022 (UTC)
@Iara Ai: please see Module:Wikidata table — Martin (MSGJ · talk) 11:33, 24 February 2022 (UTC)
@Iara Ai You could always write your own. I've no previous Lua coding experience but with the help of asking at this page, I managed to create Module:Wdtablerow/listed buildings to use in this article Listed buildings at the University of Leeds. Nthep (talk) 15:53, 24 February 2022 (UTC)
I think we should work together to create one module for this, so all editors can benefit from added features — Martin (MSGJ · talk) 10:50, 25 February 2022 (UTC)
a good idea. Nthep (talk) 13:48, 25 February 2022 (UTC)
@Nthep: @MSGJ: yes I was just doing some research just in case something already existed. If nobody takes the lead for this, I'll look into making a module when time allows. Thanks for the reference.Iara Ai (talk) 17:30, 2 March 2022 (UTC)
You clearly didn't read our comments, because there are two already available! (I think one is bespoke for a particular purpose.) — Martin (MSGJ · talk) 20:58, 2 March 2022 (UTC)

Sorting with accents

Another question. I am using table.sort on Template:French cheeses and I was surprised to see that Époisses is sorted last. I would have expected it come after "E". Is that normal? — Martin (MSGJ · talk) 11:32, 24 February 2022 (UTC)

I assume it sorts on ASCII codes or other encoding. In ASCII, É is 201 so will come after all alphanumerics. —  Jts1882 | talk  13:32, 24 February 2022 (UTC)
Yes, you're right. And all the lower case letters are sorted before the uppercase letters. So "z" comes before "A". Arghh! — Martin (MSGJ · talk) 10:32, 2 March 2022 (UTC)
Wikitext uses UTF-8 encoding and É is two bytes, hex C3 89. The C3 means É will sort after all ASCII characters. There are ugly workarounds that work (most of the time) for simple cases such as European accented letters, but they are horrific. Johnuniq (talk) 23:28, 24 February 2022 (UTC)
One workaround is to define a table of special characters and where they should be sorted, e.g. function p.preprocessSortName () at Module:Goalscorers (line 469). —  Jts1882 | talk  11:04, 2 March 2022 (UTC)
In theory, a standard module implementing e.g. azify("Déjà") → "deja" might help. In practice, there are differing opinions on where to sort letters such as ä, even within one language. Certes (talk) 11:52, 2 March 2022 (UTC)

No_globals issue solving

Over at Module talk:BaseConvert § convert with 'Module:No globals' error?, I have reported an issue (re 'No globals'), and a /sandbox solution. A tech check would be welcome, before pushing it live. -DePiep (talk) 05:18, 12 April 2022 (UTC)

Solved. -DePiep (talk) 06:32, 13 April 2022 (UTC)

Error output on a module that should otherwise work

On my creative-venture wiki on Miraheze, I've recently set up a module called "Find", based on the "find" function at WP's Module:String. Minutes ago, I test-ran it through Special:ExpandTemplates with this sample code (and a couple of variants thereof):

{{#invoke:Find|find|This is a test.|test}}

On WP itself, this should give out "11" as the result. So far, however, these tests over on Miraheze output the error message "Lua error in Module:Find at line 35: attempt to call field '_getParameters' (a nil value)." (Although "_getParameters" isn't referenced anywhere else in this case.)

Sorry, only pinging here because 1) I'm pretty much inexperienced with Scribunto/Lua (being used so much to the old-school style of things with ParserFunctions) and 2) a bit of urgent help is needed. Can someone more qualified troubleshoot this module code and tell me what I missed?

--[[
find

This function allows one to search for a target string or pattern within another
string.

Usage:
{{#invoke:String|find|source_str|target_string|start_index|plain_flag}}
OR
{{#invoke:String|find|source=source_str|target=target_str|start=start_index|plain=plain_flag}}

Parameters
    source: The string to search
    target: The string or pattern to find within source
    start: The index within the source string to start the search, defaults to 1
    plain: Boolean flag indicating that target should be understood as plain
        text and not as a Lua style regular expression, defaults to true

If invoked using named parameters, Mediawiki will automatically remove any leading or
trailing whitespace from the parameter.  In some circumstances this is desirable, in
other cases one may want to preserve the whitespace.

This function returns the first index >= "start" where "target" can be found
within "source".  Indices are 1-based.  If "target" is not found, then this
function returns 0.  If either "source" or "target" are missing / empty, this
function also returns 0.

This function should be safe for UTF-8 strings.
]]
--[[From w:Module:String#L-324]]
--[[This is a partial stand-in for the {{#rmatch:}} function offered by mwe:RegexFunctions, currently disabled on Miraheze per phab:T8866]]
local str = {}

function str.find( frame )
	local new_args = str._getParameters( frame.args, {'source', 'target', 'start', 'plain' } )
	local source_str = new_args['source'] or ''
	local pattern = new_args['target'] or ''
	local start_pos = tonumber(new_args['start']) or 1
	local plain = new_args['plain'] or true

	if source_str == '' or pattern == '' then
		return 0
	end

	plain = str._getBoolean( plain )

	local start = mw.ustring.find( source_str, pattern, start_pos, plain )
	if start == nil then
		start = 0
	end

	return start
end

return str

--Slgrandson (How's my egg-throwing coleslaw?) 12:23, 17 April 2022 (UTC)

str._getParameters() must be defined in you module somewhere or you will get that error. At Module:String, that function is defined at line 524 et seq. Copy that into you module and see if that fixes your problem.
Trappist the monk (talk) 12:30, 17 April 2022 (UTC)
Along with "_getBoolean"--which managed to do the trick. Thanks a dozen! --Slgrandson (How's my egg-throwing coleslaw?) 12:57, 17 April 2022 (UTC)

How do i find specific Module pages?

I was wondering if there was a way to find the module page to templates if they dont link to them directly? i wanted to improve Plantilla:Ficha de comida (spanish wiki) by translating some of the english (Template:Infobox food) but i cant seem to find the module page for it.Kaidros (talk) 04:58, 20 April 2022 (UTC)

One useful method is to preview an edit to a page where you replace the contents with a very simple example of using the template. At the bottom, you can view templates used on the previewed page. That includes what modules were called. It's probably es:Module:Ficha. Johnuniq (talk) 05:27, 20 April 2022 (UTC)

How to use a string read as tablename?

I have read a variable as string, say 'tFoo'. Now I want that name to be used as a table id: table.insert( 'tFoo', 'someValue1' ). This produces an error (like "error input variable 1: table expected, got string"). How can I use that string as table-name in there? (note: the table name is known beforehand, from a limited list of five, so is declared as local tFoo = {}). In code, essense lines:

local someFunction()
local tFoo = {}
local sInput
   sInput = 'tFoo'
   table.insert( 'tFoo', 'someValue1' ) -- triggers error
   return table.concat( 'tFoo', ";" )
end

DePiep (talk) 06:20, 22 April 2022 (UTC)

local function someFunction()
	local tFoo = {}
	local sInput
	sInput = 'tFoo'
	table.insert( tFoo, 'someValue1' )
	return table.concat( tFoo, ";" )
end
Johnuniq (talk) 07:23, 22 April 2022 (UTC)
Hmm, I just read this again. Are you saying you want the name of the table to be determined when the program runs? You can't do that in Scribunto's Lua. You would need to have a series of if...elseif...end tests to work out which table to use. If you describe the problem a bit more I can provide an example. Johnuniq (talk) 07:26, 22 April 2022 (UTC)
Actually, line 5 should be using the input / replies unchanged OK
   table.insert( sInput, 'someValue1' ) -- triggers error
-DePiep (talk) 07:38, 23 April 2022 (UTC)

As Johnuniq said, but to avoid if...elseif...end tests use a table of all five tables like in

function p.test()
   local tfoo1 = {1,2,3}
   local tfoo2 = {4,5,6}

   local all_tables = {}
   all_tables["tFoo1"] = tfoo1
   all_tables["tFoo2"] = tfoo2

   local sInput = 'tFoo2'
   local operate_on = all_tables[sInput] or {}
   
   table.insert(operate_on , 'someValue1' )

   return table.concat(operate_on, "; " )
end

This returns "4; 5; 6; someValue1". I introduced "operate_on" for the case your sInput does not match any of the tables, but you probably do not need it. Ponor (talk) 08:41, 22 April 2022 (UTC)

if i understood the question (and the documentation) correctly, this can be achieved with _G['tFoo'], so the first example should work like so:

local someFunction()
tFoo = {} -- _G[something] only works for globals
local sInput
   sInput = 'tFoo'
-- should work, i did not try: _G[sInput] is the global variable tFoo.
   table.insert( _G[sInput], 'someValue1' ) 
   return table.concat( _G[sInput], ";" )
end

in general it is not a good practice to use globals. if you want a string-indexed table of tables, per the example above, i will only suggest to construct it in a more concise way than the example: one-time variables like the inside tables in the example are just noise. i think it's more readable and maintainable, like so:

function p.test()
   local all_tables = { -- if this is required in multiple places, make it module local rather than function local.
      ["1st table name"] = {1,2,3},
      ["2nd table name"] = {4,5,6},
   }
-- ....

peace - קיפודנחש (aka kipod) (talk) 02:37, 23 April 2022 (UTC)

Using _G is interesting but it is simply a particular case of Ponor's example where _G is used instead of all_tables. Johnuniq (talk) 03:31, 23 April 2022 (UTC)
@Johnuniq and Ponor: Thanks both. "determined when the program runs" explains it, and the workaround will gently solve it. I prefer not to use _G or more abstracts, as it is too exotic for me (now). btw, it is to handle this set. -DePiep (talk) 06:02, 23 April 2022 (UTC)

Recap

Recap; confusion/mistakes fixed:
Original post by DePiep: I have read a variable as string, say 'tFoo'. Now I want that name to be used as a table id: table.insert( 'tFoo', 'someValue1' ). This produces an error (like "error input variable 1: table expected, got string"). How can I use that string as table-name in there? (note: the table name is known beforehand, from a limited list of five, so is declared as local tFoo = {}).
local function someFunction()
	local tFoo = {}
	local sInput
	sInput = 'tFoo'
	table.insert( sInput, 'someValue1' )
	return table.concat( sInput, "; " )
end
Note by Johnuniq: read the name of the table to be determined when the program runs? You can't do that in Scribunto's Lua.
Workaround by Ponor (shortened here):
function p.test()
   local tfoo1 = {1,2,3}
   local tfoo2 = {4,5,6}

   local all_tables = {}
   all_tables["tFoo1"] = tfoo1
   all_tables["tFoo2"] = tfoo2

   local sInput = 'tFoo2'
   table.insert( all_tables[sInput] , 'someValue1' )

   return table.concat( all_tables[sInput] , "; " )
end
User: קיפודנחש‎ notes about availability of _G.
DePiep (talk) 06:25, 24 April 2022 (UTC)

Authority control not recognising accented letters as letters

Please see Template talk:Authority control/Archive 13#TLS identifier format. We need some regex that will recognise accented letters are being letters. Thanks — Martin (MSGJ · talk) 15:18, 7 March 2022 (UTC)

Consider changing line 823 to
local idlen = mw.ustring.len (id)
Count unicode characters, not bytes.
Trappist the monk (talk) 15:44, 7 March 2022 (UTC)

Lua Pattern matching help

From the following module call, {{#invoke:WikidataIB|getValue|qid=Q60165516|P131|qual=DATES|fwd=ALL|osd=no|noicon=yes|linked=false}}

Prakasam district (1970–2022), Guntur district (–1970), Bapatla district (2022–)

I would like to extract as given below.

Bapatla district (2022–) Prakasam district (1970–2022),


In general the following matches are required.

1)start has a value, with end value of 2022
2)a start value of 2022 and no end value
3)start has no value, but end value of 2022
3)Start has no value and end has no value

I can get these cases individually as shown below.

case 1

{{#invoke:String|match|{{#invoke:WikidataIB|getValue|qid=Q60165516|P131|qual=DATES|fwd=ALL|osd=no|noicon=yes|linked=false }}|(%S+ district %(.-2022%))|plain=false}}

Prakasam district (1970–2022)

case 2

with a different qid

{{#invoke:String|match|{{#invoke:WikidataIB|getValue|qid=Q60165583|P131|qual=DATES|fwd=ALL|osd=no|noicon=yes|linked=false }}|(%S+ district %(2022.-%))|plain=false}}

Bapatla district (2022–)

Case 3

{{#invoke:String|match|{{#invoke:WikidataIB|getValue|qid=Q60165583|P131|qual=DATES|fwd=ALL|osd=no|noicon=yes|linked=false }}|(%S+ district %(.-2022%))|plain=false}}

Prakasam district (–2022)

Case 4

with a different qid

{{#invoke:String|match|{{#invoke:WikidataIB|getValue|qid=Q11104042|P131|qual=DATES|fwd=ALL|osd=no|noicon=yes|linked=false }}|(%S+ district)|plain=false}}

Prakasam district

Can you help by giving simple mediawiki template calls to WikidataIB or a complete script to get these values with links and a comma separator, even if the district name has upto three words separate by space? Arjunaraoc (talk) 06:09, 16 April 2022 (UTC)

After some research I found {{wikidata}} to be a more powerful way to access data from wikidata and used the current parameter to get currently valid data item. Arjunaraoc (talk) 10:32, 2 May 2022 (UTC)

Lua object coding (like mw.html)

I'd like to start programming by object, like building mw.html. Can anyone mention some live modules with good, basic examples? (And more complicated ones maybe). -DePiep (talk) 11:16, 8 May 2022 (UTC)

Lua error with Taxonbar?

Can anyone see what the issue is with this taxonbar for Gea eff (Q4281852)? When I type {{Taxonbar|from=Q4281852}}, I see:

Lua error: bad argument #1 to 'getEntityIdForTitle' (string expected, got nil).

Backtrace:

  1. [C]: in function "error"
  2. libraryUtil.lua:11: in function "checkType"
  3. mw.wikibase.lua:144: ?
  4. (tail call): ?
  5. Module:Taxonbar:475: in function "chunk"
  6. mw.lua:525: ?
  7. [C]: ?

Thanks! Not sure if I should be asking here or Template talk:Taxonbar so I'm asking both places but will respond in both places when the issue is solved. Umimmak (talk) 04:58, 25 February 2022 (UTC)

I don't know why it occurs, but the problem is that the following gives nil
mw.wikibase.getSitelink('Q4281852')
and that makes Module:ResolveEntityId#L-12 crash with the error shown. Johnuniq (talk) 07:01, 25 February 2022 (UTC)
@Umimmak: Now that I've had a chance to look at d:Q4281852, the problem is obvious. That item has no entry for enwiki in the "Wikipedia" section near the bottom. Therefore the title at enwiki is nil, and the confusing error results. Module:ResolveEntityId should handle that more gracefully, or at least give an error indicating what the problem is. Hmm, I see Module talk:ResolveEntityId mentions errors in hundreds of articles. The error has temporarily gone away because a recent edit at Module:ResolveEntityId was reverted. Johnuniq (talk) 08:30, 25 February 2022 (UTC)
(edit conflict)@Johnuniq: hrm… this didn’t use to be an issue. I’m not sure why there needs to be a Wikipedia article for me to get information from Wikidata; I’ve definitely found it useful to have access to the taxonbar when I’m working on an article in a sandbox or draftspace. … but at least it’s working now? Umimmak (talk) 08:31, 25 February 2022 (UTC)
I was reporting the situation from the point of the module: the "obvious" in my comment was referring to how the code in Module:ResolveEntityId would obviously give that error given that there is no enwiki article for that item. However, the code with that problem has been reverted, so yes, it's working now. I'm sure that if the module is updated again there will be some fix. Johnuniq (talk) 08:36, 25 February 2022 (UTC)

This was caused by a recent edit to Module:ResolveEntityId which I have just reverted — Martin (MSGJ · talk) 08:37, 25 February 2022 (UTC)

@Johnuniq, Umimmak, and MSGJ: I think I resolved the issue at Module:ResolveEntityId/sandbox. Please test out {{taxonbar/sandbox}} and let me know. --Ahecht (TALK
PAGE
) 00:16, 26 February 2022 (UTC)
@Ahecht: There is no wikipedia article (yet) for Gea africana and {{Taxonbar/sandbox|from=Q2158509}} yields:
Looks good to me. Umimmak (talk) 00:23, 26 February 2022 (UTC)

Code for regex support

As I type, I'm planning to add real regex support for my creative-venture wiki's "Find" module, an example being:

{{#invoke:Find|regex|test|^[rstlne]}} → 1

How does one deal with the final part Lua-wise? (Again, keep in mind I have little experience with Scribunto/Lua.) --Slgrandson (How's my egg-throwing coleslaw?) 13:54, 13 May 2022 (UTC)

Lua does not do regex. Lua does patterns. There is a lot of similarity but common regex stuff like | is not supported. You might look at Module:String for finding something in a string using lua patterns.
Trappist the monk (talk) 14:04, 13 May 2022 (UTC)
iiuc, they are talking about their own wiki.
@Slgrandson: i think you should ask this on mw: - there must be a way to add a library to scribuntu. personally, i would look for the sources of the "ustring" library, which adds unicode support to scribuntu, and follow their example (TBH, i did not verify, but i assume this lib is written in C).
you may want to expand this lib instead of creating a new one, e.g. add mw.ustring.regex() function(s) (once you add "true" regex, you may be tempted to add "rmatch(), rgsub() etc.), and have your module simply pipe this functionality so it's usable by templates.
you may also look at doing it purely in lua - i imagine this will be very inefficient, but maybe you don't care about performance - see e.g https://gist.github.com/luiseduardohd/10668729
as a side, "real regex" is not as cut and dried as one might imagine, and some tools and libraries discriminate between, e.g., "perl regex", "pure regex", and whatnot. i remember JS regex was missing some features for a long time, specifically "negative lookbehind", which gave the few who really needed it no end of pain - this one was rectified a while ago).
peace. קיפודנחש (aka kipod) (talk) 16:12, 13 May 2022 (UTC)
Incidentally: in my regex, the parameters test and ^[rstlne] return "t" not "1" -- as I expected.
My thoughts: the requested Lua Module:regex could translate (=string change) Regex-code into pattern-code, by replacing regex escape "\" with pattern escaper "%" (first and foremost). Also it c/should check for unsupported code, (eg, "|" for or cannot be patternalised) and return an error. -DePiep (talk) 18:10, 13 May 2022 (UTC)
The question needs clarification regarding what "real regex" means. If something like Perl compatible regex is envisaged, forget it—it's not going to happen. If content with Lua's regex, see Module:String. Regarding Scribunto's ustring library, it is entirely written in Lua, including regex handling—an amazing accomplishment. Johnuniq (talk) 23:39, 13 May 2022 (UTC)
Source code: https://github.com/wikimedia/mediawiki-extensions-Scribunto/tree/master/includes/engines/LuaCommon/lualib/ustring. Although, on actual Wikipedia, the PHP version of Ustring (source code: https://github.com/wikimedia/mediawiki-extensions-Scribunto/blob/8b707a45a540ebdc7348a97904ffd65ad7bd02ad/includes/engines/LuaCommon/UstringLibrary.php) for performance reasons. Nor is real regex hopeless as Johnuniq describes it, given the pure-Lua implementation that Kipod linked above.
Way back in 2016, a since-banned user said that namely that someone will write Module:RegEx as an argument that the developers denying modules programmers a real regex library was counterproductive; <sarcasm>perhaps it's time to validate that hypothetical and repeat the circumstances that lead to the installation of Scribunto in the first place</sarcasm>. * Pppery * it has begun... 00:14, 14 May 2022 (UTC)

My point was that it should be pretty straightforward for a non-wikimedia wiki to add "true" regex support. I stand corrected regarding ustring implementation, but this only makes it even easier: use the php implementation, and figure out how to hook one or few more functions, which can be implemented as a shim piping inbuilt php regex. For wikimedia wikis, we should limit ourselves to lua pattern matching, and jot this down as "regex envy" which won't be satisfied. Peace - קיפודנחש (aka kipod) (talk) 14:52, 14 May 2022 (UTC)

Could Lua be used to make these templates more efficient?

And perhaps combine them without making the combined template too bulky? Please see the discussion here. Thanks for any help! ···日本穣 · 投稿 · Talk to Nihonjoe · Join WP Japan! 17:29, 27 June 2022 (UTC)

Anyone? ···日本穣 · 投稿 · Talk to Nihonjoe · Join WP Japan! 19:49, 1 July 2022 (UTC)

Changing flag icon formats from .svg.png and .png to .svg

Is there anyway to change formats of flag icons from .png and .svg.png to .svg if possible? Any specific code or module? Let me know. FireDragonValo (talk) 19:12, 13 May 2022 (UTC)

@FireDragonValo: What are you trying to fix? A file cannot be simply converted between formats using Lua modules. NguoiDungKhongDinhDanh 20:12, 13 May 2022 (UTC)
There are online converters though (e.g.); perhaps not a Lua module, but a script could semi-automate that (as in adding a 'convert to svg' link next to png images on the page, and maybe even kick-start the upload process, pre-filling the upload form with the details of the converted img). — Guarapiranga  00:47, 29 July 2022 (UTC)
@Guarapiranga Have you actually tried those converters? They do a terrible job, and you end up with something that looks like it was drawn by a 3-year-old. --Ahecht (TALK
PAGE
) 13:35, 29 July 2022 (UTC)
😄
I did use one; only once, and can't remember which. — Guarapiranga  22:49, 30 July 2022 (UTC)

Loops, variables and tables

I have a number of variables, let's say: v1, v2, v3 ... v10, which I want to perform the same set of operations on relating to a wikitable and then add each to a table. Now I could write

function p.main(frame)
    local t={}
    ''operations''
    table.insert(t, v1)
    table.insert(t, v2)
    table.insert(t, v3)
    .
    .
    .
    table.insert(t, v10)

Is there a way of using a function that will take the variable root name v, add an integer and pass that back so in a for...next loop I can use to replace all the table.insert lines?

for N=1,10,1 do
    table.insert(t,vN)
end

Nthep (talk) 15:38, 20 June 2022 (UTC)

If it has global scope then the variable can be addressed as _G['v'..N], but should you be using an array v[1] ... v[10] instead of variables v1 ... v10? Certes (talk) 17:55, 20 June 2022 (UTC)
We should see the example you are working on as better procedures might be suggested. However, something like the following would answer the question.
local t = {}
for i, v in ipairs({v1, v2, v3, v4}) do
    v = operate(i, v)
    table.insert(t, v)
end
Johnuniq (talk) 23:24, 20 June 2022 (UTC)
Thanks. I don't have an example as yet but what I am considering is to create a template to create tables similar to the squad lists at 1936–37 Challenge Cup#Final but with a couple more fields dealing with numbers. TBH it is probably solvable using #switch etc but i find LUA easier to understand than expression syntax. What complicates it are things to do with the numbers are also the position names which differ depending on where in the world you are. So my thought was to take each position associate it with 2 names and 2 numbers and create a table row on that. So each row would have 5 parameters, position, home player, home number, away player and away number, then just loop through the required number of rows. Nthep (talk) 08:43, 21 June 2022 (UTC)
When you're ready, consider posting sample input and wanted output, keeping it very simple and short. Then there could be ideas on how to achieve that. Johnuniq (talk) 09:02, 21 June 2022 (UTC)
That sounds like a case where you want to be using tables, not numbered variables. If I were doing it, I would have the input be something like {{template_name|pos_1=|hplayer_1=|hnumber_1=|aplayer_1=|anumber1=|position_2=|...}} and then read that into a table:
local t = {}
for k, v in pairs(frame:getParent().args) do
    row = k:sub(k:find("_")+1, nil)
    column = k:sub(1,k:find("_")-1)
    if (t[row]) then
        t[row][column] = v
    else
        t[row] = {[column] = v}
    end
end
You would probably want a little more data validation than that, but in essence that will create a table containing numbered rows and named columns with the input. You can then use for i, v in ipairs(t) do to iterate over the rows in your table and call out each column by name, e.g. t[1].hplayer. --Ahecht (TALK
PAGE
) 13:57, 21 June 2022 (UTC)
Thanks but I can't get this to work. You can see what I'm trying to achieve at Module:Rugby league match squad/sandbox. User:Nthep/sandbox10 is the page I'm calling it from. Nthep (talk) 22:04, 5 July 2022 (UTC)

Regardless of the specific question asked, I'd like to comment that having a set of variables named v1, v2, v3...v11 is usually not a good practice (this was very common when the leading programming language was fortran 4, thankfully those days are gone). Variables ideally have meaningful names, which indicate what do their values mean. Typically, vX like in the example all mean the same thing (and should better have more meaningful name than "v"), maybe at different data points. If this is the case, it's usually preferable to have one var, of type "table" to hold the values, indexed by some identification of the data point - can be 1,2,3 or 'china', 'russia', 'usa', or whatever.

Peace - קיפודנחש (aka kipod) (talk) 18:29, 31 July 2022 (UTC)

Mnemonic, we used to call'em back in the day. — Guarapiranga  01:13, 1 August 2022 (UTC)

Lua error / running scripts expired - Norodom Sihamoni page

Hello Team, may I please seek team's technical expertise and assistance. King Norodom Sihamoni's wikipedia page is experiencing this error in the references section, with error messages, "The time allocated for running scripts has expired. The time allocated for running scripts has expired. The time allocated for running scripts has expired.The time allocated for running scripts has expired", "The time allocated for running scripts has expired", " Lua error in Module:Citation/CS1/Date_validation at line 946: attempt to index field 'inv_local_long' (a nil value)." On the wikipedia app, the references appear fine, but on desktop version, it appears all strange. I have no idea how to fix it as Im not a technical person :( May I please seek support on this issue so this error is all remedied or will it be auto-remedied? Thanks team. Contributorthewise (talk) 13:22, 1 August 2022 (UTC)

Update 13:23 - oh wow, looks like it all fixed ? Not sure who did the fix - but thank you so much!! — Preceding unsigned comment added by Contributorthewise (talkcontribs) 13:24, 1 August 2022 (UTC)

Extension of Graph:Chart for step function?

I didn't find a possiblity to create a true step function plot with the Template:Graph:Chart.

It is only possible to mimic it by a line plot with steep increases, but that graph has (almost) vertical lines that look "non-mathematican":

Or with his complex workaround:

{{Graph:Chart | width=400 | height=150 | xAxisTitle=X | yAxisTitle=Y | type=line | x=1,1.99,2,2.99,3,3.99,4,4.99,5,5.99 | y1=10,10 | y2=,,12,12 | y3=,,,,6,6 | y4=,,,,,,14,14 | y5=,,,,,,,,,2,2 | colors=SteelBlue,CornflowerBlue,CornflowerBlue,CornflowerBlue,CornflowerBlue | yAxisMin=0 }}

Myosci (talk) 08:35, 13 August 2022 (UTC)

well, you don't have to twist the values (1.99 instead of 2). it's legit to repeat x values for line graph.

{{Graph:Chart
 | width=400 | height=150
 | xAxisTitle=X
 | yAxisTitle=Y
 | type=line
 | x=1.00001,2,2,3,3,4,4,5,5,6
 | y=10,10,12,12,6,6,14,14,2,2
 | yAxisMin=0
 | colors=SteelBlue,CornflowerBlue,CornflowerBlue,CornflowerBlue,CornflowerBlue
}}

note that i did use one "perverted" x value, for the first data point (1.00001). the reason for this is that the X axis legends behave a bit differently when all values are integers (see below). if any of the data points has non-integer X value, this perversion is not required.

same graph with all integer x values

peace - קיפודנחש (aka kipod) (talk) 00:01, 14 August 2022 (UTC)

Chinese date conversion

Does Lua have a library that allow for conversion of dates such that one can enter 2024-01-01 (Gregorian New Year) and receive 2024-02-10 (Chinese New Year)? This is a moveable date based on the lunar cycle. -- GreenC 16:10, 24 August 2022 (UTC)

did you look at mw.language:formatDate ?
peace קיפודנחש (aka kipod) (talk) 16:28, 24 August 2022 (UTC)
I presume that you meant to link to mw.language:formatDate rather than formatNum. formatDate uses the same formatting (and so likely is the same code as) the #time parser function.
Trappist the monk (talk) 16:36, 24 August 2022 (UTC)
If the #time parser function doesn't have Chinese date conversions (it doesn't) then I doubt that MediaWiki has a separate Lua implementation of such a library. You might search module space; mayhaps someone has written something that will suit or that can be adapted. You might start with this search.
Trappist the monk (talk) 16:36, 24 August 2022 (UTC)
You might also pose this question at zh:Wikipedia talk:Lua.
Trappist the monk (talk) 16:39, 24 August 2022 (UTC)
I don't think there is such a library at Wikipedia. The navbox at the bottom of {{age}} attempts to show all relevant functions but it's not there. On the other hand, I seem to recall a template like this being deleted as unused. Searching finds Template:New Year's Eve (created February 2015, deleted January 2021). The creator is no longer active. I have no idea what this does, but the wikitext for the template was
{{ctime:x|{{{1|{{#time:Y|+8hours}}}}}|1|0}}<noinclude>[[Category:Chinese Traditional Festival]]<templatedata>
{
	"description": "To get the date of New Year's Eve",
	"params": {
		"1": {
			"aliases": [
				"y"
			],
			"label": "year",
			"description": "The year number",
			"type": "number"
		}
	}
}
</templatedata></noinclude>
Johnuniq (talk) 23:57, 24 August 2022 (UTC)

So I decided to upgrade WP:USRANK, and again bit more than I could chew (who remembers this adventure a year ago?). I thought it would be interesting to bring out data scripters had already documented inside the {{infobox user script}} on their scripts' help page (like skins and browsers compatibility, status of development, etc.). So I endeavoured to revamp and overhaul the module:user scripts table (which was the outcome from last year's debacle) in its sandbox. It started to work (preview this version against my sandbox, for instance), until... I flew too high, and MW's Lua memory constraints melted my wings. If you care to look at the code, you'll see I'm fumbling in the dark side of Lua; I'm sure there must be smarter ways of declaring the variables and writing the subroutines. Are there? Cheers. Guarapiranga  05:57, 16 June 2022 (UTC)

Using a Module:Wikidata function in Lua

I would like to know how to translate the following line into a Lua command (feel free to refer me to a better method to get the correct data, if this module is inefficient):

{{#invoke:Wikidata|ViewSomething|labels|en|value}}

Animal lover |666| 10:51, 19 September 2022 (UTC)

Does this do what you want?
local something_viewed = frame:callParserFunction ({name = '#invoke', args = {'Wikidata', 'ViewSomething', 'labels', 'en', 'value'}})
If you are going to use more than this one function there may be better ways of implementing this.
Trappist the monk (talk) 16:39, 19 September 2022 (UTC)
I only need to use it once, which I assign to a variable, if blank replace with a different value, and make a single use of this variable. In fact, the bigger context is:{{{name|{{#if:{{#invoke:Wikidata|ViewSomething|labels|en|value}}|{{#invoke:Wikidata|ViewSomething|labels|en|value}}|{{PAGENAMEBASE}}}}}}}. Animal lover |666| 19:20, 19 September 2022 (UTC)
@Animal lover 666 and Trappist the monk: Using callParserFunction to invoke a Lua module is inefficient, use require('Module:Wikidata').ViewSomething(frame) instead. However, ViewSomething is essentially just doing mw.wikibase.getEntity().labels.en.value, which is much slower than the proper way to get the label: mw.wikibase.getLabel(). See the mw.wikibase docs for more useful Lua functions. Dexxor (talk) 06:43, 20 September 2022 (UTC)

Generating unique IDs

Here is the requirement: some template needs to assign ID attribute (e.g., in order to use mw-customtoggle-<unique-suffix>). Now, this template might appear multiple times in a page, and each one should have a unique ID (for practical reasons, and in order to have valid HTML). Is there a sane way to ensure that consecutive calls (from different invocations) to the same code will return different results? for obvious reasons, having multiple elements with same ID is not only "invalid html", but also dysfunctional. Did anyone encounter similar challenge before? i hope someone can show me i am stupid, and there's safe and simple way to do it. thanks, peace - קיפודנחש (aka kipod) (talk) 17:45, 18 February 2022 (UTC)

Use math.random( m, n ) to get pseudorandom number and modify it for the id. —  Jts1882 | talk  18:00, 18 February 2022 (UTC)
thanks for the advice, but unfortunately, it's not really good: the issue revolves around seeding, Math.random() reseeds on every call, which practically means it's not "pseudo random". if i could guarantee that each call will be executed in a different timeslice, it would work, but even then, the "pseudo random" is just a screen of smoke, and i could just as well use directly os.clock() modulo something.
by reseeding every time, random loses its randomness. calling mw.math.random directly also does not work - when not seeded, it always begins at the same spot. to see what i mean, visit User:קיפודנחש/sandbox: i created a tiny Module:Testrand to demonstrate how consecutive calls to math._random() can return the same value (when the clock did not tick between calls). this happens because each call re-seeds, using the clock, plus some slow moving counters.
admittedly, the parser is (currently) slow enough, such that on consecutive invocations the clock is "guaranteed" to move, but this approach is short-sighted.
allow me bore you with "old-timer" story (personal experience, but i searched and found a link which discusses it): somewhere in the 1980s and 90s, there was a popular development tool called Borland Pascal. now, this product was meant to run on ms-dos, IOW, with no operating system whatsoever for anything other than file access.
the lack of OS created a need for a "delay" library function (e.g., when you wanted to operate some hardware, like UART and such).
BP implemented "delay" in a very naïve and straightforward way, which was reasonable then and would be crazy now: they ran some loop with junk code (or maybe even empty) N number of times, based on the parameter. to translate the parameter of delay() in MS to the number of times the loop should run, a factor is needed, which depends on the speed of the machine.
so, as part of the initialization of the library, a "delay calibration" code was run: the loop was executed large number of times (~64K iirc), the RT clock was sampled before and after to determine the time it took, and divide 64K by the time to get the "delay factor" (so "delay" would execute the loop ms*factor times).
when computers became fast enough, the "delay calibration loop" started executing faster than the clock resolution, and started throwing "divide by zero" exception.
this happens only once, but unfortunately, this one time is during initialization, which basically meant that any program written in BP would fail to start on faster computers (at least, "fail to start reliably" - if you get lucky, your loop straddles a tick...). the sad part is the fact that it did not matter if you ever used or wanted to use "delay()" - vast majority of programs never did, and programmers who did not deal with hardware were typically not even aware of this !@#$% delay, but the "sudden death" affected everyone anyway.
luckily for me, i worked at a large enough company at the time, and we had access to the library source, which allowed me to patch the library (i could not simply remove the calibration, since i needed "delay" to work, as my thing did interface with hardware).
this story is only 12% relevant, but i enjoyed telling it, and i hope some of you enjoyed reading it. won't be surprised if some had first-hand acquaintance with it...
the moral of the story is, do not rely on clock ticks between calls your program makes - some day someone will build a machine fast enough, and you'll find the clock did not tick between the first and 2nd call. under the surface this means that math.random is deeply flawed, as my sandbox demonstrates (BTW, this can be easily fixed: keep a module-wise local variable and ensure that seeding only happens once per invocation).
going back to "random" (not in module math, but in scribuntu: mw.math.random): if it was possible to seed it once per wiki page parsing, such that consecutive calls continue to develop it without seeding, i was fine with going this route, even though there is no guarantee that N consecutve calls will return N distinct value for any N > 1.
however, scribuntu creates a fresh "sandbox" for each invocation, which means random should be seeded per each invocation, which only works when the servers are slow enough, or when mw code is inefficient enough to ensure at least one tick between invocations.
peace - קיפודנחש (aka kipod) (talk) 20:24, 18 February 2022 (UTC)
By design, different calls with the same parameters are supposed to be totally independent of each other so, for example, one section can be parsed without regard for what is in other sections. I think there should be some restricted method of defining page-global variables (for example, to say "use mdy date formats on this page"), but without that I don't think there is any way of guaranteeing different results with the same parameters. Johnuniq (talk) 22:33, 18 February 2022 (UTC)

Module:Random uses both os.time and os.clock to set the random seed on each invocation. os.clock returns the number of seconds of CPU time used so far to build the page, with a precision in microseconds. my test indicates this technique is reliable in generating unique IDs within the same page and will be until CPUs are at least 20x faster than they are now. Thparkth (talk) 21:01, 20 September 2022 (UTC)

Get list/array of pages in a category

Is it possible to somehow retrieve a list of pages in a category with Lua?

I am trying to create a dynamic/automatic list for WikiProject participants - currently a userbox exists that adds a user page into a WikiProject participants category. I want to get all the pages within this category and then use Lua to render a list DominusVilicus (talk) 11:52, 17 October 2022 (UTC)

Alas, no.
Trappist the monk (talk) 11:57, 17 October 2022 (UTC)
You can, perhaps, use awb with the no-limits plugin to get all of the pages in a category and copy/paste that list into a sandbox page that lua can then read...
Trappist the monk (talk) 11:59, 17 October 2022 (UTC)
So, WP:AWB can read that list (pages in category; optional: category depth; also in AWB: sort & filter eg mainspace pages only, or "all into talkpage").
Then one can save that AWB-list eg "in wiki markup" = [[]]-bracketed in a flat file. A full c/p into an enwiki /sandbox page can give the access as requested. HTH. DePiep (talk) 08:11, 23 October 2022 (UTC)

Split string in Lua

I am trying to parse an article's wikicode to extract a table and split it into columns. Some columns are separated with a double vertical bar "||" and other times it is a new line followed by a single bar "\n|". I have given up using mw.text.split because I don't think it can handle both possibilities. So any help would be appreciated, thanks — Martin (MSGJ · talk) 11:39, 30 October 2022 (UTC)

I can imagine that parsing a wikitable gets pretty ugly. Have you tried replacing double pipes with some sort of single character that you are unlikely to find in a wikitable and split on that?
wikitable_content_string = wikitable_content_string:gsub ('||', '║')
Trappist the monk (talk) 11:57, 30 October 2022 (UTC)
Replace "||" with "\n|". Then all columns will begin the same. —  Jts1882 | talk  13:19, 30 October 2022 (UTC)
Thanks guys. For some reason I couldn't get the ║ to work properly. But Jts solution works perfectly! — Martin (MSGJ · talk) 16:18, 31 October 2022 (UTC)

Lua requests

WP:Lua requests ("requests for Lua-based templates or tasks", according to WP:Lua) redirects here. Is the intention for such requests to be posted on this page? Andy Mabbett (Pigsonthewing); Talk to Andy; Andy's edits 21:18, 5 November 2022 (UTC)

Yes. I believe the "requests" page was merged to here a long time ago. Johnuniq (talk) 23:09, 5 November 2022 (UTC)
Thank you; I've set out my idea in a new section below. Andy Mabbett (Pigsonthewing); Talk to Andy; Andy's edits 16:35, 6 November 2022 (UTC)

Directly invoking a module

An editor has suggested at Template talk:Time signature#Su that that template should invoke Module:Su directly instead of going through the template {{Su}} to reduce the post-expand include size (PEIS) of pages where {{Time signature}} is used extensively, specifically List of musical works in unusual time signatures. This seems a good idea to me, so I tried {{#invoke:su|main|a=c|p='''{{{1}}}'''|b='''{{{2}}}'''|lh=0.85em}}}}, but I can't get it to work. Is this a viable way to reduce post-expand size? Can this be done? Can somebody help doing it? -- Michael Bednarek (talk) 13:15, 2 November 2022 (UTC)

The post-expand size is based on the output of the template/module. I don't think this should be different if the template is a simple invocation of the module. A quick look at the module suggests it only handles parent frame parameters, so calling main() won't work. Not sure if it would work calling _main with the appropriate parameters. —  Jts1882 | talk  13:33, 2 November 2022 (UTC)
Directly invoking modules is a valid way to reduce the post-expand include size, although I personally don't like it. That said, the module has to support that method of calling, as as Jts1882 says it doesn't right now. * Pppery * it has begun... 13:40, 2 November 2022 (UTC)
I've added an entry point for direct invocation to the sandbox. Try {{#invoke:su/sandbox|invoke_main|a=c|p='''{{{1}}}'''|b='''{{{2}}}'''|lh=0.85em}}}}. —  Jts1882 | talk  13:47, 2 November 2022 (UTC)
Thank you very much. I used Module:Su/sandbox at Template:Time signature/sandbox and Template:Time signature/testcases shows that it works. I leave it to others to decide whether this should be implemented. -- Michael Bednarek (talk) 01:39, 3 November 2022 (UTC)
Does it reduce the post expand include size? If it does then I can make the change. If not I don't see the need. —  Jts1882 | talk  10:23, 3 November 2022 (UTC)
It does, by a little bit. The current live template {{Time signature}} has an PEIS of 1588 bytes, reduced for the sandbox version to 1270. The article mentioned above has 761 invocations of {{Time signature}} and a further 145 of {{Music|time|x|y}} which can be converted to {{Time signature}}. {{Music|time|x|y}} uses 2638 bytes, so some savings can be had there, even with the current template/module. If there are no downsides, implementing the sandboxes seems like a good idea to me. -- Michael Bednarek (talk) 12:08, 3 November 2022 (UTC)
Only for a while. List of musical works in unusual time signatures slammed into the post-expand include size limit in June 2022 and again in October 2022. If the article continues to grow (seems likely that it will), what will you do when it once again slams into the limit? It's time to recognize that the problem is not going away. These kinds of technical hacks are not solutions to the underlying problem – there are only so many hacks that can be applied before there are no more hacks available. Editors need to exercise editorial control and take the hard decisions about the article's future.
Trappist the monk (talk) 13:40, 3 November 2022 (UTC)
Ignoring the {{music|time}} to {{time signature}} (or assuming they have already been all done) then just directly calling Su results in a reduction of the PEIS by 288 KB, which is a decent amount. The remaining 145 {{music|time}} also would save 152 KB, for a total of 440 KB saved. Seems good (for now), but if I continue contributing too much that might change. Wilh3lmTalk 16:49, 6 November 2022 (UTC)
Update: the {{music|time}} templates have all been replaced with {{time signature}}. The PEIS is currently 1,905,012 bytes, leaving 192,140 bytes remaining. Some redundant template calls could be culled too.Wilh3lmTalk 17:15, 6 November 2022 (UTC)
Update 2: There are currently 868 time signature templates and I am planning on reducing redundant time signatures, but also continuing to contribute which probably will make the article larger. aaaaaa Wilh3lmTalk 23:28, 8 November 2022 (UTC)
I did a test with {{Time signature/sandbox}}, which directly invokes module Su rather than using the template. The PEIS of List of musical works in unusual time signatures was reduced from 1,808,279 bytes to 1,528,834 bytes. With the other changes, this would leave considerable room for expansion of the list article. Should I make the change to the module? —  Jts1882 | talk  10:19, 9 November 2022 (UTC)
I think that's a worthwhile step, and no downside has been mentioned. -- Michael Bednarek (talk) 13:30, 9 November 2022 (UTC)
 Done Module:Su updated with separate entry point for direct use of invoke and {{Time signature}} modified to use invoke rather than use template {{Su}}. —  Jts1882 | talk  15:28, 9 November 2022 (UTC)

Template proposal: coder needed

I have in mind a template that will produce a "one page" calender for any given year. I have set out details, and the 14 possible permutations, on User:Pigsonthewing/Calendars.

Would anyone like to code this, in Lua? The key requirement will be to programmatically determine, or fetch from Wikidata, the weekday on which 1 January falls in that year, and whether or not the year is a leap year; maybe there is some existing code that can be reused for this?

It might make a good student project. Andy Mabbett (Pigsonthewing); Talk to Andy; Andy's edits 16:34, 6 November 2022 (UTC)

Not sure that wikidata is needed. The {{#time}} parser function can tell you if this year is a leap year:
{{#time:L|2022}} → 0
{{#time:L|2024}} → 1
and can tell you the day on which January 1 occurs:
{{#time:l|2022-01-01}} → Saturday
If you know that, then the rest is figuring out how to format the table.
What are the template's parameters? Presumably the template will accept |year= with an override of the year portion of the article title with a final fallback to the current year. Are there any others? What do they do?
Trappist the monk (talk) 17:07, 6 November 2022 (UTC)
In that case, It probably doesn't need Lua, either. I'll see what I can do with template code. User:Pigsonthewing/Calendars has suggestions for other parameters, which would be to control styling. Andy Mabbett (Pigsonthewing); Talk to Andy; Andy's edits 17:35, 6 November 2022 (UTC)
Does {{Calendar}} do what you need? Certes (talk) 19:01, 6 November 2022 (UTC)
Just because I was curious: Module:Sandbox/trappist the monk/calendar and my sandbox.
Trappist the monk (talk) 20:59, 6 November 2022 (UTC)
That does what I wanted with the content; thank you. It renders {{One page calendar (starts Monday)}} redundant, so would you like to move and reuse that, and rename your module accordingly? It might also be sensible to include optional parameters for the caption and title. Andy Mabbett (Pigsonthewing); Talk to Andy; Andy's edits 12:25, 7 November 2022 (UTC)
My sandbox (permalink). Supports these parameters:
|year= – the year for which this calendar is to be rendered; defaults to current year
|table-style= – css style string suitable for use in an html style="" attribute; applies to the whole table; do not use quotes; defaults to empty string
|caption= – a caption that replaces the default caption; default caption automatically inserts day name on which 1 January occurs; this is not possible for custom captions
|lang-tag= – mostly useful for debugging; takes a MediaWiki-supported language tag in which this calendar is to be rendered; defaults to wiki's own language; caveat lector: mw:Help:Extension:ParserFunctions##time indicates that day names are 'rarely internationalized.' To use this module on wikis that do not have internationalized day names, will likely require some sort of custom code.
You choose the template name (there will be only one).
Trappist the monk (talk) 16:22, 7 November 2022 (UTC)
Thank you. Now at {{One page calendar}} and Module:One page calendar. Andy Mabbett (Pigsonthewing); Talk to Andy; Andy's edits 15:48, 11 November 2022 (UTC)

Lua pattern

Can anyone help me match the following pattern in Lua?

[a-z]+(\-[a-z]+)*(_res\-[0-9a-f]{8}(\-[0-9a-f]{4}){3}\-[0-9a-f]{12})?

I got as far as replacing escape character with % and removed finite quantifiers as follows:

[a-z]+(%-[a-z]+)*(_res%-[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]%-[0-9a-f][0-9a-f][0-9a-f][0-9a-f]%-[0-9a-f][0-9a-f][0-9a-f][0-9a-f]%-[0-9a-f][0-9a-f][0-9a-f][0-9a-f]%-[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f])?

But I still have the brackets with quantifiers e.g. (%-[a-z]+)* and I don't know how to deal with that — Martin (MSGJ · talk) 11:01, 12 November 2022 (UTC)

I don't think that what you want to do is directly possible. There are some simplifications: [a-z]%l and [0-9a-f]%x. You might try breaking up the target string into appropriate pieces. You can iterate (%-%l+) with string.gmatch() to create a sequence of captures, etc.
Trappist the monk (talk) 13:19, 12 November 2022 (UTC)
Are you sure that your regex does what you want it to do? If I understand (I'm not saying that I do) then this test string should be matched by your regex:
xyz-uvw-rst_res-12345678-1111-2222-3333-012345543210
and you want captures:
  • -uvw
  • -rst
and
  • _res-12345678-1111-2222-3333-012345543210
  • -1111
  • -2222
  • -3333
When I give your regex and my test string to regex101.com, it gives me:
  • -rst
  • _res-12345678-1111-2222-3333-012345543210
  • -3333
What is it that you really want from this? Do you have real-life examples of what you want (real life examples are much more better than contrived test strings)
Trappist the monk (talk) 14:36, 12 November 2022 (UTC)
Because I was curious, I've hacked a simple module that I think does what I think you want: Module:Sandbox/trappist the monk/MSGJ regex. Use the debug console to run the code:
=p.main() returns:
table#1 {
    "-uvw",
    "-rst",
    "_res-12345678-1111-2222-3333-012345543210",
    "-1111",
    "-2222",
    "-3333",
}
=p.main ('xyz-uvw-rst') returns:
table#1 {
    "-uvw",
    "-rst",
}
Trappist the monk (talk) 16:02, 12 November 2022 (UTC)

Not wanting any captures, just true/false if a string matches the pattern. Thanks, will check your code when back on PC — Martin (MSGJ · talk) 16:33, 12 November 2022 (UTC)

ok, for true/false I've added is_valid(). Works the same way as main(). Returns true when <target> has valid format; false else.
Trappist the monk (talk) 19:02, 12 November 2022 (UTC)
Many thanks for your code which seems to be working well. I suspect a lot of people are grateful for your curiosity — Martin (MSGJ · talk) 22:19, 15 November 2022 (UTC)

What does this do?

I'm trying to understand how the following line of code works as I haven't seen anything constructed like this before:

local lccnType = parts[1] ~= 'sh' and 'names' or 'subjects'

Is this valid and what does it do? Thanks — Martin (MSGJ · talk) 13:02, 2 December 2022 (UTC)

Is valid. Its a shorthand way of writing
local lccnType
if parts[1] ~= 'sh' then
    lccnType = 'names'
else
    lccnType = 'subjects'
end
Trappist the monk (talk) 13:13, 2 December 2022 (UTC)
Wow! Would never have guessed that. So true and "names" = "names" then — Martin (MSGJ · talk) 13:38, 2 December 2022 (UTC)
If you're familiar with the ?: operator from C, Perl, etc., you could think of this as local lccnType = (parts[1] ~= 'sh') ? 'names' : 'subjects'. Certes (talk) 13:23, 2 December 2022 (UTC)
Can I write a = b==1 and false
In this case anything "and" false has to be false, so a is always false, irrespective of the value of b? — Martin (MSGJ · talk) 23:00, 8 December 2022 (UTC)
Yes, a will always be false. The b==1 and has no effect. (Variants such as a = b() and false could have side-effects or return nil, but we try not to employ coders who write that sort of thing!) Certes (talk) 23:18, 8 December 2022 (UTC)
(edit conflict)
You can, but why would you want to? That simplifies to a=false regardless of the result from b==1. Is there some reason that you think that and false is necessary to set a to its proper value? Or, is false in your example some sort of 'final result' of some other boolean operation so that sometimes the assignment looks like a = b==1 and true?
Trappist the monk (talk) 23:27, 8 December 2022 (UTC)
Was just trying to follow the example above to its logical conclusion! But I guess it only works with strings and not booleans. If I want a to be false if b==1 and a to be true if b~=1 then a = b==1 and false or true will not work — Martin (MSGJ · talk) 11:48, 9 December 2022 (UTC)
As mentioned in Ternary conditional operator#Lua, that doesn't work because the and...or mechanism has a limitation. It relies on the third operand being short-circuited when the left operand (condition) is true. That requires the middle operand to be truthy. It breaks if the middle operand evaluates to false or nil, because the "or" is then evaluated and the right operand returned instead. You could write b~=1 and true or false, or (much more legibly) b~=1. Certes (talk) 12:17, 9 December 2022 (UTC)
short essay, not mandatory reading
so, this is a very common pattern in several languages, and lua is a prime example.
one of the easy ways to explain it (or rather, "what is it good for") is with comparison to the "switch" statement available in other languages (but not lua).
to demonstrate, let's look at some silly java example, taken from here:
        String monthString;
        switch (month) {
            case 1:  monthString = "January";
                     break;
            case 2:  monthString = "February";
                     break;
            case 3:  monthString = "March";
                     break;
            case 4:  monthString = "April";
                     break;
            case 5:  monthString = "May";
                     break;
            case 6:  monthString = "June";
                     break;
            case 7:  monthString = "July";
                     break;
            case 8:  monthString = "August";
                     break;
            case 9:  monthString = "September";
                     break;
            case 10: monthString = "October";
                     break;
            case 11: monthString = "November";
                     break;
            case 12: monthString = "December";
                     break;
            default: monthString = "Invalid month";
                     break;
        }
using the "boolean pattern", the lua code becomes:
        local monthString = 
            month == 1 and "January" or
            month ==  2 and "February" or
            month ==  3 and "March" or
            month ==  4 and "April" or
            month ==  5 and "May" or
            month ==  6 and "June" or
            month ==  7 and "July" or
            month ==  8 and "August" or
            month ==  9 and "September" or
            month ==  10 and "October" or
            month ==  11 and "November" or
            month ==  12 and "December" or
            "Invalid month"
this is a made-up sample, and neither is an impressive implementation. to make it more real, let's look at some real code (copied from Module:Pages with authority control identifiers):
current code:
function p.autoDetect( frame )
	if currentTitle.namespace == 14 then --cat space
		local wpfaultyID = mw.ustring.match(title, 'Articles with faulty ([%w%.%- ]+) identifiers')
		local wpID       = mw.ustring.match(title, 'Articles with ([%w%.%- ]+) identifiers')
		if wpfaultyID then return wpfaulty( frame, wpfaultyID )     --must be before wpID check, in case they both match
		elseif wpID       then return wp( frame, wpID )             --to keep the regex simple
		else   return '[[Category:Pages with authority control identifiers unknown category]]'
		end
	end
	return ''
end
alternative using boolean shortcur:
function p.autoDetect( frame )
	local wpfaultyID = mw.ustring.match(title, 'Articles with faulty ([%w%.%- ]+) identifiers')
	local wpID       = mw.ustring.match(title, 'Articles with ([%w%.%- ]+) identifiers')
	return currentTitle.namespace ~= 14 and ''
		or wpfaultyID and wpfaulty( frame, wpfaultyID )
		or wpID and wp( frame, wpID )
        or '[[Category:Pages with authority control identifiers unknown category]]'
end
it's not 100% clear cut which expression is clearer and easier to read (and/or debug), but the latter form is more in "lua spirit" than the former, and personally, i prefer it.
peace - קיפודנחש (aka kipod) (talk) 18:39, 10 December 2022 (UTC)
one small caveat, though: this patterns works fine when all expressions after the "and" evaluate to true.
when some may evaluate to false, it behaves like a "switch" statement omitting the "break" in some of the cases, which considered undesired, and usually produces some compiler or linter warning. if this is the case, probably "traditional" if will do better.
peace. קיפודנחש (aka kipod) (talk) 19:50, 10 December 2022 (UTC)
Yes – and it's not obvious at a glance that wpfaulty(...) always returns a true value. If it returns false or nil, the idiom quietly breaks. Certes (talk) 20:01, 10 December 2022 (UTC)
nitpick: actually, it is obvious at a glance.
one small thing that may be confusing is a (yet one more) difference between javascript and lua: in js, empty string and 0 evaluate to "false". in lua, both evaluate to true.
my "caveat" comment was meant for using this pattern in general. in this case, it's kosher, as neither wpfaulty() nor wp() can return false.
peace. קיפודנחש (aka kipod) (talk) 01:08, 14 December 2022 (UTC)

Module:Authority control

Can someone fix the script error at the bottom of AbbVie (and many more in Category:Pages with script errors)? I think it's related to the recent changes by User:MSGJ who may be offline right now? Frietjes (talk) 17:22, 9 December 2022 (UTC)

Checking now. If it takes more than 10 mins I will roll back changes — Martin (MSGJ · talk) 18:28, 9 December 2022 (UTC)

The error was caused by the following line:

mw.ustring.gsub(conf.link,'%$1',valid_value)

In this case the valid_value had a %2 in it, i.e.

mw.ustring.gsub('https://www.worldcat.org/identities/$1/','%$1','nc-abbvie%20inc')

Somehow it thought the %2 was a capture and it gave an error. Is it possible treat the string as literal or do I need to replace '%' with '%%' first? — Martin (MSGJ · talk) 22:59, 10 December 2022 (UTC)

You have to escape % in valid_value with valid_value:gsub('%%', '%%%%'). I would try to avoid that because second-guessing regex patterns or replacements leads to spiralling confusion. Instead, I would try to require that valid_value be defined on the assumption that it will be used in a Lua replacement and so, in this case, should be 'nc-abbvie%%20inc'. Johnuniq (talk) 00:56, 11 December 2022 (UTC)
Thanks @Johnuniq. I agree that would be simpler but unfortunately I have no control over the value because it comes from Wikidata and may be used by many other tools/templates. Is there any possible downside to making the substitution you suggested, and are there any other character combinations that I need to look out for? — Martin (MSGJ · talk) 07:32, 11 December 2022 (UTC)
Wikidata, ugh! I believe no other adjustments are needed and the gsub I gave above is all you need. It's fast. Johnuniq (talk) 08:59, 11 December 2022 (UTC)
It's working a treat. Thanks for your help! — Martin (MSGJ · talk) 09:54, 14 December 2022 (UTC)

Module:Political party

How can i write this for Bengali letters?

Here on enwiki, module always returns '1' (Module:Political party/1) if the input is not A-Z letters. For bnwiki i need same thing but in that case if the input is not অ - য় letters. I tried this but doesn't always work, e.g. fails here because input was ''প্রযোজ্য নয়''. আফতাবুজ্জামান (talk) 23:25, 13 December 2022 (UTC)

You might try rewriting the function to look like this:
local function getFirstLetter(party)
	local index = mw.ustring.sub(party, 1, 1)
	-- Set index for non-A-Z starts
	if mw.ustring.match (index, '[^অ-য়]') then
		return '১'
	end
	return string.upper(index)
end
That should return when index is not a character in the range অ-য়. Does Bengali have upper and lower case letters? If not then return string.upper(index) changes to return index.
Trappist the monk (talk) 00:38, 14 December 2022 (UTC)
@Trappist the monk, it works. Thank you. আফতাবুজ্জামান (talk) 00:56, 14 December 2022 (UTC)
just curious: shouldn't the original code work as is (almost) simply by replacing string.match with mw.ustring.match ?
theoretically, this should work, i think. if this is the case, i think it's preferable, as it should work in any language, instead of having to adjust it for every language separately. the documentation says:
  • %a: represents all characters with General Category "Letter".
assuming this is the case, it will be nice if the original on enwiki (here) will do this change - it should not affect the functionality here, and will work as is for projects in other languages.
peace. קיפודנחש (aka kipod) (talk) 01:26, 14 December 2022 (UTC)
OP provided a specific character range. I don't read Bengali so I don't know if that range contains all of the Bengali 'letter' characters. The Bengali (Unicode block) encompases U+0980–U+09FE. The OP's range is U+0985–U+09AF (plus an additional combining character U+09BC attached to U+09AF). The combining character is apparently not a letter so in the debug console:
=mw.ustring.match ('য়','%a') returns (U+09AF)
=mw.ustring.match ('য়','%A') returns (U+09BC)
Not clear to me that a generic %A will work reliably.
Trappist the monk (talk) 01:57, 14 December 2022 (UTC)
Thats another problem. For some reason mediawiki doesn't support য় (U+09DF), ঢ় (U+09DD), ড় (U+09DC). After your save, mediawiki decomposes it. Long time ago, i even accidentally broke content translation on bnwiki (phab:T152956) when i submitted translation for ContentTranslation (at that time i didn't knew that mediawiki decompose these latter). আফতাবুজ্জামান (talk) 02:25, 14 December 2022 (UTC)
Anyway, in this case we are fine. If any name start with য়, i will add that to and it will work. আফতাবুজ্জামান (talk) 02:34, 14 December 2022 (UTC)

The Template: Series overview which uses this module recently looks so bad in mobile view. It is no longer scrollable from left to right like a normal wikitable but it just go out of bounds of the screen. Can someone take a look at it and fix it? I raised concern on its talk page, but there's no respond. Lulusword (talk) 06:03, 27 December 2022 (UTC)

@User:Alex 21 would you look into this please? — Martin (MSGJ · talk) 07:07, 27 December 2022 (UTC)
I'll take a look as soon as possible. (No promises on how soon, my real world job is extremely demanding during the festive season.) -- Alex_21 TALK 21:53, 27 December 2022 (UTC)
@Lulusword Can you please an example page where this happens, and perhaps a screenshot of what you're seeing? Thank you. -- Alex_21 TALK 08:35, 29 December 2022 (UTC)
@Alex 21: Here are some screenshots from the template page itself. The second image is the worst offender in my opinion.

Lulusword (talk) 09:03, 29 December 2022 (UTC)

These are screenshots from mainspace. The first example is from List of Running Man episodes while the second one is from Star Trek: The Next Generation. Lulusword (talk) 09:31, 29 December 2022 (UTC)

PAGESIZE

Is there an equivalent function in Lua to the magic word PAGESIZE? — Martin (MSGJ · talk) 18:38, 10 February 2023 (UTC)

Here are two options:
local page_size=frame:preprocess ('{{PAGESIZE:<page name>')
local page_size=frame:callParserFunction ({name = 'PAGESIZE', args = {'<page name>'}})
Trappist the monk (talk) 19:06, 10 February 2023 (UTC)
And I think here is the another option:
  • local pagesize = mw.title.new(pagename):getContent():len()
It will get recorded as a transclusion and is expensive but the PAGESIZE parser function is also expensive. I have not tested this to compare the sizes yet.
  • local pagesize=tonumber(mw.getCurrentFrame():callParserFunction{name='PAGESIZE', args={pagename, 'R'}})
If you go the parser function route you will likely want to use the |R since you will likely be wanting to use tonumber(pagesize) on it and do not want to push it through something more complex like:
  • mw.getContentLanguage():parseFormattedNumber(pagesize)
Of course if you want a string and the numeric formatting of PAGESIZE then you can try:
  • local pagesize = mw.getContentLanguage():formatNum(mw.title.new(pagename):getContent():len())
Uzume (talk) 22:06, 10 February 2023 (UTC)
mw.title.new() is not expensive when given a page title; it is expensive when given a page ID. See mw:Extension:Scribunto/Lua reference manual § mw.title.new. getContent() does count as a transclusion but I doubt that that will cause any problems. A quick hack in my sandbox suggests that this mechanism returns the same value as the preprocess() and callParserFunction() options.
Trappist the monk (talk) 23:16, 10 February 2023 (UTC)
Thanks both! — Martin (MSGJ · talk) 06:42, 11 February 2023 (UTC)
@Trappist the monk: Thanks for testing that out. I meant that the getContent portion was expensive. Typically playing with random pagenames is not expensive, however, anything that has to touch the database on a title that is not already part of the current parse (e.g., the current page being rendered) adds to the expensive count (otherwise we could have a single page rendering that attempts to touch the database for every page in the system which would be prohibitive and thus is explicitly not allowed by incurring expense and having an upper-bound on that). I did notice the documentation did not specifically say getContent was expensive (but I have found the documentation is often lacking and I keep adding to it). If that is true then one can build a Scribunto module that effectively does the same as the PAGESIZE parser function and avoid the expensive hit. —Uzume (talk) 03:27, 12 February 2023 (UTC)
I meant that the getContent portion was expensive. No. I have hacked a simple test module in my sandbox: Module:Sandbox/trappist the monk/pgsize and a test that uses it in my other sandbox. The test allows testing your method (not expensive) and both of the methods that I suggested in my first post to this topic (both expensive).
In my 'other' sandbox I used Abraham Lincoln as the target page. {{PAGESIZE:Abraham Lincoln}} returns 207,012 (expensive).
Trappist the monk (talk) 15:55, 12 February 2023 (UTC)
@Trappist the monk: Cool! But that seems like more an an oversight by the developers of Scribunto to me. —Uzume (talk) 21:35, 12 February 2023 (UTC)
@Trappist the monk: I used your test rig and did a more extensive comparison. In doing so I also fixed a bug in your sandbox testing module (see 1139365276). I did not attempt to make many runs and take averages so I am not sure how accurate these numbers are but I thought I would provide a quick comparison.
Method 1=getContent():len() 2=preprocess {{PAGESIZE:}} 3=callParserFunction PAGESIZE
CPU time usage 0.014 seconds 0.017 seconds 0.013 seconds
Real time usage 0.020 seconds 0.021 seconds 0.017 seconds
Preprocessor visited node count 48/1,000,000 50/1,000,000 48/1,000,000
Post-expand include size 115/2,097,152 bytes 122/2,097,152 bytes 115/2,097,152 bytes
Template argument size 22/2,097,152 bytes 22/2,097,152 bytes 22/2,097,152 bytes
Highest expansion depth 4/100 4/100 4/100
Expensive parser function count 0/500 1/500 1/500
Unstrip recursion depth 0/20 0/20 0/20
Unstrip post-expand size 256/5,000,000 bytes 256/5,000,000 bytes 256/5,000,000 bytes
Lua time usage 0.004/10.000 seconds 0.004/10.000 seconds 0.003/10.000 seconds
Lua memory usage 767,345/52,428,800 bytes 558,500/52,428,800 bytes 558,751/52,428,800 bytes
Number of Wikibase entities loaded 0/400 0/400 0/400
I highlighted some key differences which I shall call out here:
Method 1
Is in the middle in terms of CPU time, uses the most Lua memory but does not ping the expensive count
Method 2
Uses the most CPU, least Lua memory, and pings both the preprocessor node count and the expensive count
Method 3
Uses the least CPU, is in the middle in terms of Lua memory, and pings the expensive count
In my personal opinion, one of the more interesting results is that callParserFunction does not impact the "post-expand include size".
I wonder if there is a difference between callParserFunction with parser function msg (which makes a template call) and expandTemplate. Then there is always preprocess on getContent but one would have to setup a frame with something like newChild to pass arguments to such. —Uzume (talk) 20:53, 14 February 2023 (UTC)

Bug report mw.text.decode (U+03B5 epsilon)

Regarding Module:DecodeEncode, see § Bug report: bad decoding of U+03B5 ε (epsilon) DePiep (talk) 13:52, 4 February 2023 (UTC)

Testcases & sandbox changes: Module talk:DecodeEncode § testcases EPSILON -DePiep (talk) 06:59, 16 February 2023 (UTC)

Wrapper for Module:Graph and Module:Political party

I am attempting to make a wrapper for Module:Graph:Chart and Module:Political party that can get the colors and abbreviations from Module:Political party and use them in Module:Graph:Chart. after figuring out the problem with the wrong "#" symbol being returned by Module:Political party, I have something that works in User:Frietjes/political graph, but it goes through the template interface and not the module interface, which seems less efficient. after stabbing in the dark for awhile and not being able to get it to work, I thought I would ask here. I believe there is some clue to how it has to work in Module:Graph:Chart where a newFrame is created with a particular title for the parent? can anyone help provide some insight? feel free to edit my sandbox / userpage if you want to experiment. thank you! Frietjes (talk) 22:50, 27 February 2023 (UTC)

I think you could simply require Module:Graph:Chart then execute it directly. What I am currently very unclear about is what frame to pass when calling it and where the arguments would need to be (frame or frame:getParent()). I might get a chance to think more in day or two however the cost of calling the template is probably small although I'm not sure what effect on template limits it might have in tight situations. By the way, the mw.ustring.gsub could be just string.gsub. Also, mw.ustring.match could be string.match and '[%d]+' should be '%d+'. Johnuniq (talk) 09:37, 28 February 2023 (UTC)
From looking at the code, it would seem that Module:Graph:Chart uses Module:Graph (I'm unclear what it actually adds to it) by calling its chartWrapper() function. That function is an entry point for p.chart(frame). If I'm reading the code correctly, that function could be refactored to accept instead p.chart(args) as it seems the only usage of frame is for frame.args.key. Gonnym (talk) 09:38, 28 February 2023 (UTC)
@Johnuniq and Gonnym: thank you for the help, to be more clear about the problem, see User:Frietjes/political graph2 which is the same as User:Frietjes/political graph but attempts to use Module:Graph:Chart directly. this has exposed a typo in line 624 of Module:Graph. what is puzzling is why this typo is exposed by User:Frietjes/political graph2 and not by User:Frietjes/political graph? Frietjes (talk) 16:45, 28 February 2023 (UTC)
okay, so no idea where the problem is? Frietjes (talk) 23:30, 15 March 2023 (UTC)

Substitution

Is it possible to partially substitute a module? I know this is possible with templates, but how to control it for modules? For example if I use frame:expandTemplate{title = "Navbox", args = navboxArgs} is it possible that the output would contain {{Navbox|...}} rather than the substituted form of that template? — Martin (MSGJ · talk) 20:34, 15 March 2023 (UTC)

See Module:Template invocation * Pppery * it has begun... 22:09, 15 March 2023 (UTC)
Okay I looked, but I am not sure how that will answer my question? — Martin (MSGJ · talk) 22:25, 15 March 2023 (UTC)
The basic idea is that the module, when substituted (which you can detect via mw.isSubsting()) has to return the wikitext of the template call (generated using that module) rather than its expansion. See the expandTemplate function in Special:Diff/1102521258 (ironically to a module you were working on) for an example. * Pppery * it has begun... 22:32, 15 March 2023 (UTC)
Okay thanks, I can follow that. So "inline" is the default format? — Martin (MSGJ · talk) 23:10, 15 March 2023 (UTC)
No, passing "inline" as a format does nothing (the only supported format is nowiki, which you don't want here). I must have misread the docs when I made that edit. The module seems to generate the invocation with no whitespace always, although you could of course include any desired whitespace in the parameters themselves. * Pppery * it has begun... 01:14, 16 March 2023 (UTC)
That's what I guessed. It's working brilliantly, thanks for your help. — Martin (MSGJ · talk) 08:03, 16 March 2023 (UTC)

I propose to create a sports module for 2019–2021 & 2021–2023 World Test Championship League table. Abazizfahad (talk) 13:36, 20 March 2023 (UTC)

add require(strict): code check please

About module:DecodeEncode, § Template-protected edit request on 21 March 2023 (my edit request, now paused).

With current live version, I meet script errors (in development situations). I propose to add require('strict'), see sandbox (compare ). Could someone who knows about 'strict' check this change? If OK, pls set |answered=no or perform the edit right away. DePiep (talk) 14:47, 21 March 2023 (UTC)

 Done DePiep (talk) 19:38, 25 March 2023 (UTC)

Empty string

This came from a previous version of Module:Class mask:

ret = args['']

Is it using the empty string as a key to a table? This seems somewhat strange to me. — Martin (MSGJ · talk) 20:39, 23 March 2023 (UTC)

Writing t = {['a']='alpha', b='beta', ['']='empty'} is valid and means that t.a is 'alpha', t.b is 'beta', and t[''] is 'empty'. A weird warstory is at Template talk:Val/Archive 5#Template:♥ where I did a confusing workaround following a case where |=done was accidentally used in a template. That set the empty parameter to 'done' and due to other stuff, that ended up calling {{done}} which displayed an image ( Done) where that should have been impossible. Your example looks weird but it is plausible and would give 'done' with my example. Johnuniq (talk) 03:05, 24 March 2023 (UTC)
Thanks John. I guess I shouldn't have been surprised than an empty string can be a key in Lua. Rather unintuitive in this case though, because these arguments represent template parameters and obviously the name of a parameter can't be empty! — Martin (MSGJ · talk) 09:33, 26 March 2023 (UTC)
I agree that it is very unexpected for the name of a parameter to be empty, but I just gave an example where it can happen (|=done). Johnuniq (talk) 05:18, 27 March 2023 (UTC)

Getting the current frame

I am using frame:expandTemplate in a local function. Is it better to use frame = mw.getCurrentFrame() to get the current frame, or can I pass the frame as an argument to the function? — Martin (MSGJ · talk) 09:41, 26 March 2023 (UTC)

You can pass the frame object (which is just another table); see mw:Extension:Scribunto/Lua reference manual § table.
Trappist the monk (talk) 11:32, 26 March 2023 (UTC)
Where not too inconvenient, I prefer passing frame as a parameter because it's always better for the inputs to a function to be spelled out in the parameters. A minor theoretical point is that using a parameter makes the function a little more general because it would be usable with something other than the current frame. Johnuniq (talk) 05:21, 27 March 2023 (UTC)

"Funneling" artificial parent arguments into a module for testcases (Module:ArgRest)

I'm trying to create a /testcases page for the module I've made, Module:ArgRest. However, the rather unusual nature of the module makes this rather difficult; it reads the arguments of its parent AND its own arguments, with the expectation that it has been invoked by a template being transcluded onto another page. As such, I need a way to "feed" the module a set of artificial parent arguments (alongside arguments for the module itself), so that I can make testcases without having to make a separate template for each and every test. How do I do this? {{Lemondoge|Talk|Contributions}} 23:18, 29 March 2023 (UTC)

Update: I've managed to get this to be pretty much  Done (although it's a tad uglier than I would've liked); Module:ArgRest/testCaser now exists for the sole purpose of "spoofing" templates. {{Lemondoge|Talk|Contributions}} 22:45, 30 March 2023 (UTC)
@Lemondoge: Take a look at Module:Arguments/testcases - it does something similar to what you are looking to do. The trick is to use frame:newChild to create artificial parent and child frame objects. The code looks something like this:
local currentFrame = mw.getCurrentFrame()
local parent = currentFrame:newChild{title = "Parent page title", args = {arg1 = "foo", arg2 = "bar"}}
local child = parent:newChild{title = "Child page title", args = {arg1 = "baz", arg2 = "qux"}}
You can then use the child frame object as a parameter for your functions under test, etc. For example:
local myModule = require("Module:Foo")
local result = myModule.main(child)
Best — Mr. Stradivarius ♪ talk ♪ 08:40, 31 March 2023 (UTC)

Module:Hatnote list

Hello! I want to request a review of a sandbox change I've made for Module:Hatnote list (sandbox). The change allows final punctuation in the hatnote list to merge/collapse even with an italicized (and therefore de-italicized) title, which WP:ITHAT recommends. The current version can be seen in The Super Mario Bros. Movie, where the hatnote (which I edited for the title to be italicized) ends with both an exclamation mark and a full-stop. Without title italicization, only the exclamation mark appears. I didn't add an equivalent change to the module for bolded text (I have not seen bolded text in a hatnote) but I don't mind someone else adding it if they think it's also needed. LightNightLights (talk) 02:54, 6 April 2023 (UTC)

The regex looks good. I cleaned the whitespace to indent a line with tabs. It's probably not worth making a change, but I would be inclined to replace the loop with the following which is faster. It also occurs in a defined order, although that doesn't matter in this case.
local function punctuationCollapse(text)
	return text
		:gsub("%.%.$", ".")
		:gsub("%.''%.$", ".''")
		:gsub("%?%.$", "?")
		:gsub("%?''%.$", "?''")
		:gsub("%!%.$", "!")
		:gsub("%!''%.$", "!''")
		:gsub("%.%]%]%.$", ".]]")
		:gsub("%.''%]%]%.$", ".'']]")
		:gsub("%?%]%]%.$", "?]]")
		:gsub("%?''%]%]%.$", "?'']]")
		:gsub("%!%]%]%.$", "!]]")
		:gsub("%!''%]%]%.$", "!'']]")
end
You probably should propose the change at Module talk:Hatnote list. Johnuniq (talk) 06:05, 6 April 2023 (UTC)
I wholly forgot to say that I have no knowledge of Lua whatsoever. I don't even know why there are square brackets around what I can assume to be strings. I'm also willing to propose in Module talk:Hatnote list, but it might get stuck in proposal-on-obscure-page limbo, more so that the last edit there is five years ago. This page, however, seems to be a whole lot more active. LightNightLights (talk) 06:55, 6 April 2023 (UTC)
I agree that posting here is a good idea. However, it's best to follow standard procedure and also post at the relevant talk page to at least give a chance for anyone interested in that page to contribute. That's particularly true when proposing a change to something used on a zillion pages. The square brackets tell Lua that the thing enclosed is a key for the table. Johnuniq (talk) 07:38, 6 April 2023 (UTC)
That's a fair point. I've posted the proposal at Module talk:Hatnote list § Proposal for collapsing final punctuation with piped and italicized titles in hatnote list. LightNightLights (talk) 10:11, 6 April 2023 (UTC)
I have optimized it further (using the pattern ('?)%1, which matches zero or two single quotes):
local function punctuationCollapse (text)
	if text:match("[.?!]('?)%1(%]?)%2[.]$") then
		return text:sub(1, -2)
	else
		return text
	end
end
Let's continue this discussion at Module talk:Hatnote list. —Dexxor (talk) 12:56, 6 April 2023 (UTC)

Lua module help - Iterating through a table

I have zero experience with Lua, but have managed to get something working. What I would like to request is someone to take a look at my module and help me optimise it. Brief summary: {{Module:MilAward/data}} has only two records for now but later will be quite large. My module iterates through the loaded data in a truly horrible way. I have tried all the online resources I can find on how to do this better and just run into errors. If there is someone who can take a look for me I'd be grateful. Planning to replace or enhance {{Post-nominals}}, {{Medal Display}}, {{Ribbon Display}} using a central repository of data. The current Module is the bare skeleton, but I would like to get the basics working properly before I continue.

BoonDock (talk) 17:15, 3 April 2023 (UTC)

If the thing you call Code (line 3) is different for every 'item', build your table as a k/v table and then just do a simple lookup:
local data = {
    ['MMM'] = {
        Description = "Military Merit Medal",
        RibbonImage = "Ribbon - Military Merit Medal (South Africa).png",
        PageLink = "Military Merit Medal (South Africa)",
        PostNom = "MMM",
        Country = "ZAR"
        },
    ['PP'] = {
        Description = "Pro Patria Medal",
        RibbonImage = "Ribbon - Pro Patria Medal (South Africa).gif",
        PageLink = "Pro Patria Medal (South Africa)",
        PostNom = "",
        Country = "ZAR"
        },
}
Then fetch items from the table using data.MMM.Description for example.
Trappist the monk (talk) 17:28, 3 April 2023 (UTC)
Can I do a substitution? For example,
param = frame.args[1]
output = data.param.Description
I have other questions, but that one strikes me first. Thanks for asnwering. BoonDock (talk) 17:45, 3 April 2023 (UTC)
No, but you can do output = data[param].Description. Your version doesn't work because there is no ['param'] key defined in data{}.
Trappist the monk (talk) 21:32, 3 April 2023 (UTC)
I've been mulling this over and finally figured out what you were saying. Please correct me if I've gotten this wrong. Essentially, you are saying that the param passed to the module (code in my case) can be used as the direct access key to the record without iterating through the table AT ALL... if so, that's fantastic. I'm not sure how to deal with the case of a non existent key, but I'll figure it out.
To be clear, the data will look like this:
local data = {    
    MMM = {  Description = "Military Merit Medal",        
                     RibbonImage = "Ribbon - Military Merit Medal (South Africa).png",        
                     PageLink = "Military Merit Medal (South Africa)",        
                     PostNom = "MMM",        
                     Country = "ZAR"    },    
    PP = {        Description = "Pro Patria Medal",        
                      RibbonImage = "Ribbon - Pro Patria Medal (South Africa).gif",        
                      PageLink = "Pro Patria Medal (South Africa)",        
                      PostNom = "",        
                      Country = "ZAR"    } 
}
Given that, when my template invokes the function, it passes the value "MMM" as a parameter. In the module, load that value into a variable and use it to access the record directly without using any sort of loop?
    param = frame.args[1]   -- "MMM"
    output = data[param].Description   --  "Military Merit Medal"
    return output
BoonDock (talk) 03:47, 4 April 2023 (UTC)
A couple of minor points. There's a list of three-letter country codes in ISO 3166-1 alpha-3 (South Africa is ZAF) but many modules prefer ISO 3166-1 alpha-2 (South Africa is ZA). Beware that param might not be unique, e.g. MMM is also used for Member of the Order of Military Merit (Canada). Certes (talk) 23:43, 3 April 2023 (UTC)
Thanks. I had considered using the ISO codes. Would be an improvement.
I'm fully aware of the duplication of abbreviations, Military Merit Medal MMM vs Order of Military Merit (Canada) MMM and haven't come up with a fully realised solution for that. PMM is another problematic one as is GSM. I will tackle it properly once I have a grasp of the skeleton, and have it working efficiently. It's not "clean" but so far the solution could be for when there are dupes to add the country code. I'll see. At the moment, the data is duplicated for each template and is an absolute mess. Doing this will be an opportunity to sort it out to be a lot better. One of the complications is the awarding across countries. For example a lot of senior South African generals, also have the USA Legion of Merit Legion of Merit LOM as well as the ORB Order of the Cloud and Banner ORB BoonDock (talk) 00:27, 4 April 2023 (UTC)
One way is to prefix the decoration with its country, e.g. ZA-MMM. That's a bit long-winded but works well via ISO 3166-2 for country subdivision codes, e.g. BR-AL is Alagoas but US-AL is Alabama. Certes (talk) 12:55, 4 April 2023 (UTC)
Good suggestion. Only lissue is the major retcon I would have to do with over 250 each of the templates I want to replace. I think I will have to approach that in an incremental way. BoonDock (talk) 15:51, 4 April 2023 (UTC)
Certes,
Seeing as you were kind enough to suggest using the ISO country codes I thought you might have some advice. What do I do about the countries which were only partially recognised, for example Transkei, Venda, Bophuthatswana, Ciskei etc?
Second problem is what about situations where, for example, there are medals awarded to uMkhonto we Sizwe which were awarded by the ANC? When they amalgamated with the SADF in 1994, they became part of the SANDF. Which country do I use for them? I think you see where I'm struggling with this?
On a related note, You don't happen to know where I can look to find out how to access the country data on WP from a Lua module? BoonDock (talk) 19:28, 5 April 2023 (UTC)
What country data? Does Module:ISO 3166 and its submodules help?
Trappist the monk (talk) 22:59, 5 April 2023 (UTC)
Yes. Thank you. BoonDock (talk) 23:21, 5 April 2023 (UTC)
Some places not universally recognised as countries have ISO codes: Antarctica, Réunion, Taiwan, etc. For others, we could use XA–XZ and QM–QZ, which are reserved for local use, e.g. XT for Transkei. This is non-standard in the sense that another system might use XT for Tanganyika and QT for Transkei, but it's what the series is there for. Certes (talk) 17:02, 7 April 2023 (UTC)
My next question is how you can trap an error. At the moment it works with a single unnamed parameter. What if there is rather a named parameter or no parameter at all? It generates a script error when running. Is there a way I can test for that rather? BoonDock (talk) 04:53, 4 April 2023 (UTC)
Here is a somewhat rewritten version of RibbonDesc() that does some minimal error checking. I moved the loadData() call outside of any function because it only needs doing once. I declared the 'working' function _RibbonDesc() as a local and moved it above the interface function p.RibbonDesc(). The first positional parameter is forced to uppercase so that a value of 'mmm' will not cause a nil value return. I simplified both but they could probably be combined unless you plan on calling _RibbonDesc() from other functions.
local data = mw.loadData('Module:MilAward/data');

local function _RibbonDesc(code, size)
    return output = p._Ribbon(code, size) ..  " [[" .. data[code].PageLink .. "|" .. data[code].Description .. "]] ''" .. data[code].PostNom .. "''" .. " [[Category:MilAward Ribbon Description]]"
end

function p.RibbonDesc(frame)
	local args_t = frame.args
	if not args_t[1] or '' == args_t[1] then
		return '<span style="color:#d33">Error: missing positional parameter 1</span>'
	end

	local code = args_t[1]:upper() 
	if not data[code] then
		return '<span style="color:#d33">Error: invalid positional parameter 1: ' .. args_t[1] .. '</span>'
	end

	return _RibbonDesc (code, args_t[2] or "x40px")
end

return p
Similar changes can (should) be made to the other functions.
Trappist the monk (talk) 14:07, 4 April 2023 (UTC)
Brilliant. Thank you. I was wondering about recursion. In "RibbonDesc" I'm calling "Ribbon" to avoid duplication of effort. It seems to work pretty well, so I guess it isn't a problem. BoonDock (talk) 15:53, 4 April 2023 (UTC)
Done for both Functions. Working very well, thank you again! BoonDock (talk) 19:10, 4 April 2023 (UTC)

Patterns and qualifiers

I found this code in a module mw.ustring.match(title.text, 'Articles with faulty ([%w%.%- ]+) identifiers') but I was under the impression that [%w%.%- ]+ would not work because in the manual it says "Quantifiers may only be applied to individual characters or character classes". But it seems you can mix multiple characters and classes, is that correct? — Martin (MSGJ · talk) 10:23, 15 April 2023 (UTC)

Looking at this section, it appears the %? modifiers work in [set] expressions, with every other character having no special effect. A set is considered a character class (Represents the class which is), so quantifiers should work on them just fine as it suggests regardless of what the set is made of. Aidan9382 (talk) 10:32, 15 April 2023 (UTC)
As Aidan9382 said, the Lua manual defines a character class as a set of characters that can be repeated with * or + or - or ?. The set can be specified using a code such as %a or as [...] where ... can be any characters or any of the codes. So the example works. Johnuniq (talk) 01:42, 16 April 2023 (UTC)
Thanks both. Not sure why I misinterpreted, but this is a revelation for me! — Martin (MSGJ · talk) 13:08, 17 April 2023 (UTC)

Redirect module

Is it possible to make a redirect in module namespace? For example if I redirected Module:A to Module:B then calling {#invoke:A|main} would be the same as {#invoke:B|main} — Martin (MSGJ · talk) 06:59, 26 April 2023 (UTC)

Not trivially. Maybe you could pass the parameters over but it's not going to be perfect I don't think. Galobtter (talk) 07:58, 26 April 2023 (UTC)
I believe the closest solution to a redirect for modules is like how Module:CS1 does it, which is to just return the require of the target page. Aidan9382 (talk) 08:03, 26 April 2023 (UTC)
Yes, and the reason that is necessary is that a module (in Page information in the left sidebar) has "Page content model Scribunto" and that supports only Lua, not wikitext like #redirect. If Module:A is fairly new and edited by one person, namely the person who also created Module:B, I would be inclined to follow the above advice, then, next day try "What links here". Fix anything referring to Module:A (assuming there are not many) then delete Module:A. I have not seen that as a recommended strategy but if everything happened in a short period, it makes sense to me. Johnuniq (talk) 08:29, 26 April 2023 (UTC)
Makes sense, thanks — Martin (MSGJ · talk) 08:53, 26 April 2023 (UTC)
If one day phab:T120794 is implemented, then the MediaWiki software would recognize the redirecting require and internally invoke the target module instead. As far as I know, there is no forecast on this being done, though. isaacl (talk) 17:02, 26 April 2023 (UTC)

Archive 3

Does anyone know what happened to Wikipedia talk:Lua/Archive 3? It seems to have been deleted on April 9, 2022 by User:Liz and now has archived threads from 2022. I had added a link to a relevant thread in a comment for phab:T120794, but with the old content gone, it no longer points to anything. isaacl (talk) 17:08, 26 April 2023 (UTC)

I moved the 2022 archive to Wikipedia talk:Lua/Archive 11. One of the admins watching this page should undelete /Archive 3, since it was clearly deleted by mistake (Twinkle deleted the talk page when Wikipedia:Lua/Archive 3 was created as a test). * Pppery * it has begun... 00:47, 27 April 2023 (UTC)
Yes, it's clear that is what happened. I would normally have waited for Liz but since the link is used at phab I undeleted the page now. Johnuniq (talk) 00:59, 27 April 2023 (UTC)
Thanks for the undeletion. It wasn't urgent for the ticket (anyone wanting to follow it had years to do so) but nonetheless I appreciate the rapid response! isaacl (talk) 04:24, 27 April 2023 (UTC)
Just shows that admins should check the page before pressing delete ... — Martin (MSGJ · talk) 12:09, 27 April 2023 (UTC)

I just want to see how many arguments are in the frame

table.maxn(frame.args) keeps giving me 0! Help! —swpbT • beyond • mutual 19:15, 10 May 2023 (UTC)

Per the note at Module:Arguments § Known limitations, Most of the normal Lua table tools won't work properly on the args table, and that appears to include table.maxn. You'll have to either find another way to get the number of arguments (maybe iterate over the arguments yourself), or just avoid using getArgs. Aidan9382 (talk) 19:34, 10 May 2023 (UTC)
This is also true for the vanilla frame.args, which also uses a metatable. To find the number of arguments, you will indeed have to iterate over the arguments yourself. The way you should do this depends on what you want to count:
  • If you want to count all arguments, you can iterate over the table with pairs, and keep track of the total. There is already a function for this at Module:TableTools#size which you can use.
  • If you want to count only positional arguments, and you can assume that there are no gaps in the argument numbers (in other words, you don't think the template will be called as {{foo|bar|3=baz}}), then you can iterate over the table with ipairs and use the final index as the count. Or if there may be several arguments, and some of the intermediate arguments may not be used, you could use Module:Exponential search to avoid looking up every single argument.
  • If you want to count only positional arguments, but there may be gaps in the argument numbers, then you need to iterate over the table with pairs, and keep track of the number of arguments that have positive integer keys.
Let me know if you need a code example for any of these. Best — Mr. Stradivarius ♪ talk ♪ 08:04, 11 May 2023 (UTC)
Thanks!! —swpbT • beyond • mutual 18:26, 11 May 2023 (UTC)

Coding help request

There is discussion here, as well as at this ongoing TfD, about merging the vital article talk page template into {{WikiProject Banner Shell}}. To help facilitate those discussions, it would be very helpful to have a working prototype of what this would look like. Making it should be a fairly simple task, but as I don't know how to code Lua, I'd appreciate help.

To lay out the request in a bit more detail, {{Vital article}} has four parameters: |level= (the VA level an article has been designated as, e.g. 3 for the 1000-most-vital list), |topic= and |subpage= (which sort the article into a VA category, e.g. |topic=People and |subpage=Sports), and |class= (the quality rating). These should be merged, keeping their functionality the same other than renaming them to |vital_level=, |vital_topic=, etc.

For the display, the banner shell currently has e.g. This article is rated B-class on Wikipedia's content assessment scale. The only change needed here is to make the text e.g. This level-3 vital article is rated B-class on Wikipedia's content assessment scale, linking to the appropriate level.

Would anyone be interested in taking this on? If it's helpful for comparison, here's a working prototype for a merge to {{Talk header}} that would work similarly; most code added there is just copied from the vital template. {{u|Sdkb}}talk 16:45, 15 May 2023 (UTC)

I suggest to wait until the TfD is finally closed. Then, let's continue at Template talk:WikiProject banner shell? — Martin (MSGJ · talk) 20:43, 15 May 2023 (UTC)

How to pass an unlimited number of template arguments, like Babel?

I'm working on a copy of the Babel module and template with minor adjustments, but I can't seem to find out how to pass an unlimited or unspecified number of template arguments with the Invoke call. The source code in the "edit" tab of Template:Babel doesn't seem to pass any at all, but that doesn't work for my port - not even if I simply invoke the Babel module instead of the port; see my sandbox, where I'm currently testing this. This means that the code listed on the Babel template page clearly isn't the code actually used for the template, and that they're using some elusive method to pass the arguments. Does anyone know how to do this? And while we're at it, does anyone know where the actual code of the Babel template is located, and whether it's common practice (or even required) to put that code somewhere other than the template's main page? --110521sgl (talk) 16:26, 8 June 2023 (UTC)

@110521sgl: Module:Babel takes care of that in args = getArgs(frame…, and there's no other code for Template:Babel. See mw:Extension:Scribunto/Lua_reference_manual#Frame_object, and Module:Arguments. Ponor (talk) 17:36, 8 June 2023 (UTC)
found it: I had to replace {wrappers = 'Template:Babel'} by {wrappers = 'User:110521sgl/sandbox/UserlessBabel'}. I'd taken note of the "wrappers" section in Module:Arguments before, I just didn't know it was important. 110521sgl (talk) 19:18, 8 June 2023 (UTC)
Well found! Module:Arguments#Wrappers seems to lay a really horrible trap, making modules effectively unusable from anywhere other than the "authorised" template nominated in the (usually edit-protected) module. Certes (talk) 20:06, 8 June 2023 (UTC)
It's a feature not a trap! You can safely leave the wrappers option off anyway — Martin (MSGJ · talk) 20:46, 8 June 2023 (UTC)
Unless I've misunderstood, using wrappers= silently breaks exact copies of the code like the one in 110521sgl's sandbox, causing coders to bang their heads looking for bugs that don't exist then probably give up. At a minimum, each module using wrappers= needs a large sign in its documentation saying "this code only works from named template(s); don't bother trying to re-use it". Certes (talk) 21:01, 8 June 2023 (UTC)
agreed wholeheartedly. 110521sgl (talk) 21:05, 8 June 2023 (UTC)
Short answer: you do not need to pass arguments, as they are all passed in the frame by #invoke — Martin (MSGJ · talk) 19:18, 8 June 2023 (UTC)

Using colon operator

Hi guys. I'm using mw.html to build some stuff in HTML but I don't understand enough about how the colon operator works to do this. If you look at [4] you'll see one of the questions I have ... — Martin (MSGJ · talk) 20:21, 6 June 2023 (UTC)

Are you familiar with object-oriented programming? In Lua, some_object.method invokes a class method, and thus no access to the object is available within the method, and some_object:method invokes an object method, so the self keyword can be used within the method's body to access the object.
The mw.html library is designed so each object method returns the newly appended or modified object, which allows you to keep appending to/modifying the last object in the tree just by chaining method calls together. If you want to write a loop, you can store the return value into a variable and make use of it within the loop. isaacl (talk) 21:06, 6 June 2023 (UTC)
I've read the instructions and am familiar with the first paragraph. Would you be able to give me an example of the code I need to "store the return value into a variable and make use of it within the loop"? Thank you — Martin (MSGJ · talk) 22:34, 6 June 2023 (UTC)
The return value at line 515 is a reference to the object representing the HTML table element. Therefore if the chain of method calls ended there, the local variable banner would hold a reference to that HTML table element. Although mw:Extension:Scribunto/Lua reference manual#mw.html:node doesn't specify, I'm assuming from the code that the method returns a reference to self. Thus you can end the chain at line 515 and have a loop afterwards that repeatedly invokes the node method on the object representing the table element (right now, banner, but a different name might be helpful). Invoking allDone on the variable after the loop will give you a reference to the object at the root of the tree, which you could then store in a banner variable. isaacl (talk) 23:02, 6 June 2023 (UTC)

Here is an untested code sample:

local finalTable = mw.html.create('table')
    :addClass('tmbox tmbox-notice mw-collapsible innercollapse wpb')
    -- ...
            :tag('table')

for idx, htmlRow in ipairs(htmlRowList) do
    finalTable:node(htmlRow)
end
local banner = finalTable:allDone()

isaacl (talk) 23:02, 6 June 2023 (UTC)

I haven't had time to examine this but an example of using mw.html is in the function at Module:Navbox#L-375 where variable tbl is defined, then if/else tests occur to modify tbl in different ways. Johnuniq (talk) 02:10, 7 June 2023 (UTC)
Thanks both, this confirms what I thought but for some reason was not working. So just to check
tbl:node(x)
tbl:node(y)
tbl:node(z)
should be equivalent to
tbl:node(x):node(y):node(z)
correct? — Martin (MSGJ · talk) 07:48, 7 June 2023 (UTC)
Based on my understanding of your answers, this should work, but it does not because some of the elements are not being closed. Why do you recommend a new variable finalTable instead of using the banner variable? — Martin (MSGJ · talk) 12:03, 7 June 2023 (UTC)
Yes, based on mw:Extension:Scribunto/Lua reference manual#mw.html:tag, which mentions the return value of the node method, tbl:node() returns a reference to itself, namely tbl. Thus invoking node() multiple itmes on the tbl object is the same as invoking it repeatedly on each returned value from the node() method.
In your diff, the return value of banner::allDone() is a reference to the object at the root of the tree of HTML objects, but it isn't stored anywhere. Thus banner continues to hold the return value for the last method call in the chain, on line 515. This is a reference to the object representing the last table that was created. To update the banner variable, the code will have to store the allDone() return value into it: banner = banner:allDone()
Variable naming is a matter of personal preference. For this particular circumstance, I suggest using a temporary with a name to describe the object to which it is pointing at the time when it is being used, namely one of the table objects within the banner. My apologies; I haven't gone through the code enough to understand the contents of the table. My inclination would be to name the variable semantically to describe the contents. But either way the functionality will be the same. isaacl (talk) 16:36, 7 June 2023 (UTC)
I managed to get it working by using banner = banner (diff). I still don't understand why this is needed, or where exactly it is needed, because I have not used this construction with any other HTML objects, but thanks for giving me the idea. — Martin (MSGJ · talk) 21:36, 7 June 2023 (UTC)

(outdenting to facilitate including code examples) HTML documents are much like an N-ary tree of HTML elements. The mw.html library provides an API to build up a tree of corresponding objects. For generality, it doesn't define a "document" or "tree" class. A reference to any node in the tree can be considered a starting point for the subtree from that node. So to generate the HTML for the full banner, you need a reference to the root node. It might be easier to understand if the reference to the root node is kept at the start:

local banner = mw.html.create('table')   -- banner is implemented with a table.
-- Add HTML elements to the table implementing the banner
local finalTable = banner:addClass('tmbox tmbox-notice mw-collapsible innercollapse wpb')
    :addClass(status_class(project_status))
    -- ...
    :tag('tr')
        :tag('td')
        :addClass('mbox-text wpb-main')
            :attr('colspan','2')
            :tag('table')
for idx, row in ipairs(rows) do
    finalTable:node(row)
end

isaacl (talk) 02:14, 8 June 2023 (UTC)

Okay I will try that, thank you. But when I built other nodes I did not need to do this. For example this is one of the rows of the table.
local class_row =  mw.html.create('tr')
class_row
	:node(class_module{class, category = assessment_cat})
	:tag('td')
		:addClass('mbox-text')
		:attr('colspan', '2')
		:wikitext(rating)
:allDone()
I am unsure what is the difference between class_row = class_row:node(x) and just class_row:node(x) — Martin (MSGJ · talk) 07:07, 8 June 2023 (UTC)
Do you have any experience with coding a linked list in a non-object-oriented language? To traverse the list, you must specify a starting node. You can store the root node of the list in a variable and keep it for later use. If it's a doubly-linked list, you can go up the chain from an internal node and find the root node. That's what the allDone() method does: it traverses up the tree of mw.html objects and finds the root node, then returns a reference to it. (If you're not already aware, note that in Lua, objects are always stored by reference into variables, so class_row is like a pointer to the object.)
Note in the code fragment for class_row, the same thing is done as in my latest example: class_row is assigned a reference to a newly created mw.html object representing an HTML element (in the case of class_row, a <tr> element). The variable is not subsequently modified. The lines of code after the assignment are essentially equivalent to the following:
local tmp1 = class_row:node(class_module{class, category = assessment_cat})
local tmp2 = tmp1:tag('td')
local tmp3 = tmp2:addClass('mbox-text')
local tmp4 = tmp3:attr('colspan', '2')
local tmp5 = tmp4:wikitext(rating)
tmp5:allDone()
The return value of tmp5:allDone() is not being stored anywhere. isaacl (talk) 18:06, 8 June 2023 (UTC)
Based on what you've said, in my code, all the things I do to class_row are not being stored anywhere. But they definitely are being stored somewhere because in my next line I use table.insert(rows, class_row) and it works correctly with everything included — Martin (MSGJ · talk) 19:17, 8 June 2023 (UTC)
The return values aren't being stored, but the methods run and do their work to modify the objects, or create new objects and place them in the tree. It's not necessary to store the return values; recall they are just references to the objects in the tree. The actual objects they point to continue to exist even if you don't save the return values. (From an implementation perspective, the running system keeps them alive as long as they are reachable, and since they are within the tree which has links both up and down the tree, they are still reachable.) In the end you only need to have a reference to the root object of the tree you're interested in. The straightforward approach is to just keep that reference at the start. isaacl (talk) 21:37, 8 June 2023 (UTC)

Re "difference between class_row = class_row:node(x) and just class_row:node(x)", consider:

local t = mw.html.create('table')
local x = t:tag('tr'):tag('th'):wikitext('Hello'):node('Abc')
t:node('Def')
x:node('Ghi')

After running the above, tostring(t) is "<table><tr><th>HelloAbcGhi</th></tr>Def</table>".

The difference is that with class_row:node(x), something is added to class_row. But if you also assign that to class_row, it gets the value returned by node(x) which may or may not change class_row. In the above example, it does change it (x is different from t). Johnuniq (talk) 05:19, 9 June 2023 (UTC)

They are different because of the last two lines. Would x and t be any different after the first two lines? Is x a reference to a lower node in the tree? — Martin (MSGJ · talk) 09:41, 9 June 2023 (UTC)
The last two lines do not alter x or t (they do alter what x and t contain). Yes, x is a reference to a lower node in the tree as shown by where "Ghi" ends up. Johnuniq (talk) 10:15, 9 June 2023 (UTC)
Thanks for being so patient with me :) I'm not going to say I understand it yet, but perhaps slowly getting there ... What blew my mind was your first sentence above. — Martin (MSGJ · talk) 14:25, 9 June 2023 (UTC)
It can be broken down as follows:
local t = mw.html.create('table')  -- t holds reference to mw.html object representing a
                                   -- <table> element
local x =                          -- x will be assigned the last return value in the entire
                                   -- chain
    t:tag('tr')                    -- t:tag() is invoked; an mw.html object representing a
                                   -- <tr> element is created and nested within the <table>
                                   -- element.
                                   -- The method returns a reference to the newly created
                                   -- mw.html object.
    :tag('th')                     -- The tag() method is invoked on the mw.html object
                                   -- representing the <tr> element. An mw.html object
                                   -- representing a <th> element is created and nested
                                   -- within the <tr> element. The method returns a reference
                                   -- to the newly created mw.html object.
    :wikitext('Hello')             -- The wikitext() method is invoked on the mw.html object
                                   -- representing the <th> element. The argument is parsed
                                   -- as wikitext and appended to the <th> element. The
                                   -- method returns a reference to itself, the object
                                   -- representing the <th> element.
    :node('Abc')                   -- The node() method is invoked on the mw.html object
                                   -- representing the <th> element. The argument is parsed
                                   -- as HTML and appended to the <th> element. The method
                                   -- returns a reference to itself, the object representing
                                   -- the <th> element.
    -- The last return value in the chain is a reference to the object representing the <th>
    -- element. The reference is assigned to x.
t:node('Def')                      -- The node() method is invoked on t, which holds a
                                   -- reference to the mw.html object representing the
                                   -- <table> element. The argument is parsed as HTML and
                                   -- appended to the <table> element. The method returns a
                                   -- reference to itself, the object representing the
                                   -- <table> element. However nothing is done with this
                                   -- return value.
x:node('Ghi')                      -- The node() method is invoked on x, which holds a
                                   -- reference to the mw.html object representing the <th>
                                   -- element. The argument is parsed as HTML and appended
                                   -- to the <th> element. The method returns a reference to
                                   -- itself, the object representing the <th> element.
                                   -- However nothing is done with this return value.
isaacl (talk) 18:06, 9 June 2023 (UTC)