KiCommand discussion and development - Easy pcbnew command line; 4.07 & 5.1.5/.6

A major version update to KiCommand has been pushed to github.com.

The main additions are the unit tests and command to enable those unit tests. The tests included are equivalent to all of the KiCad python default unit tests.

  • It has been refactored to be a python package.
  • added unit tests equivalent to standard KiCad python tests. Invoke with “import kicommand.test” in the Script Console.
  • added parameters to make using kicommand.run() easier within other python scripts.
  • added ability to manipulate named user stacks (with spush spop, and scopy.
  • newboard creates a new board and puts it on the top of the Board stack. board now puts the top of the Board stack onto the main stack. board command is equivalent to Board scopy.
  • added ability to use different boards than what is in pcbnew UI (loading board from file, or created a new blank board). All commands using a board, now use the “current board” on the top of the Board user stack.
  • added ability to add new empty items such as modules and pads with newadd command, which creates a new empty specified element (such as MODULE or D_PAD) to a specified parent object (board or module, for example).

The new directory structure still works with 4.0.7, but has not specifically been tested with nightly. Please provide feedback on whether it works for you in nightly. It should automatically become available in the Tools > External Tools menu.

1 Like

Updated!

Still having issues with AutoPlugins in nightly. Should still work from Scripting Console and “import kicommand”

Updates::

  • RENAMED todrawsegments to tosegments to better fit nomenclature (see below)

  • Added commands regex, bool, printf, zip, fprintf, pwd, cduser, cdproject, cd

  • Added a couple more tests in kicommand.test

  • modified init.py to update import, user’s should still use “import kicommand”

  • Updated callargs to allow non-lists as input.
    Before: only a list of lists
    Now: A list of lists, a single list, or a single value.
    Before: [objectlist] [[arglist1],[arglist2]] where arglist1 applies to
    object1, arglist2 applies to object2, then arglist1 and 2 are alternated
    for each subsequent object.
    Now: if you only have one argument, or one argument list, it is used as the
    argument(s) for all objects.

SEGMENTS/POLY/POLYGON nomenclature:

“segments” as unconnected line segments (will extend later to nonlines such as arcs or curves) and “poly” as connected line segments.

  • “poly” is a single list of points where each point is a vertex of the joined lines.

  • “segments” are individual and independent x/y value pairs.

  • “polygon(s)” will refer to the upcoming polygon segments in v5/v6

Note that in either case, if a line is supposed to connect to the first point,
that first point (for poly) or segment (for segments) must be repeated at
the end of the list.

regex,bool,printf,zip,fprintf,pwd,cduser,cdproject,cd explain

Explaining regex,bool,printf,zip,fprintf,pwd,cduser,cdproject,cd 
regex (Category: Comparison) 
    [LIST REGEX] Create a LIST of True/False values
    corresponding to whether the values in LIST match the REGEX
    (for use prior to FILTER) 
bool (Category: Conversion) 
    [OBJECT] Return OBJECT as a boolean value or list. OBJECT
    can be a string, a comma separated list of values, a list of
    strings, or list of values. 
printf (Category: Output) 
    [LISTOFLISTS FORMAT] Output each list within LISTOFLISTS
    formatted according to FORMAT in Pythons {} string format
    (https://www.python.org/dev/peps/pep-3101/). 
zip (Category: Stack) 
    [LISTOFLISTS] Creates a list with parallel objects formed by
    each list in LISTOFLISTS ((1,2,3)(4,5,6)(7,8,9)) ->
    ((1,4,7)(2,5,8)(3,6,9)). 
fprintf (Category: Output) 
    [LISTOFLISTS FORMAT FILENAME] Output to FILENAME each list
    within LISTOFLISTS formatted according to FORMAT in Pythons
    {} string format
    (https://www.python.org/dev/peps/pep-3101/). 
pwd (Category: Programming) 
    Return the present working directory. 
cduser (Category: Programming) 
    Change working directory to ~/kicad/kicommand. 
cdproject (Category: Programming) 
    Return the project directory (location of .kicad_pcb file). 
cd (Category: Programming) 
    [PATH] Change working directory to PATH.
1 Like

For those watching this thread, please note that I just updated KiCommand to work with the current (5.1.5)-3 release build.

And of course there’s a new update to KiCommand to fix some additional things. I’ve changed the append command! It now matches the python functionality (adding the item to the list). If the item itself is a list, then it is added as a single item at the end of the list argument. concat now does what append used to do. There’s a whole slew of basic tests to verify KiCommand functionality. Use import kicommand.test in the Scripting Console to run the tests. On my machine, it takes about 3 minutes to execute all the tests.

There is new “SEE ALSO” section for each command help to indicate which commands are similar or that are useful in conjunction with the command.

There is more help when there’s an error, basically listing the real python error and stack trace.

regularsize is fixed. It contained old /f and -f commands which are now just / and -.

Please let me know if you have any suggestions. I’ve found the refobj and newly added valobj very useful. For example, print all modules reference values with modules refobj textfromobj print or only the selected modules with modules selected refobj textfromobj print.

You can work on a command in small steps, use print and stack liberally while testing, then aggregate all the commands into a single user definition (removing the interspersed print and stack commands). Quite useful!

Use helpcat, explain, and see commands to explore what’s available and how things are defined. Many commands are defined by a sequence of other commands. You can build and save your own commands for future use!

I’m interested to find out if people have found KiCommand useful.

1 Like

I edited the thread title

1 Like

KiCommand has been updated again, this time with a few new commands and even more tests. The tests help find bugs, and serve as examples of usage for KiCommand commands. They also can verify a proper installation and can find minor problems with different versions of KiCAD. Please report any failing tests along with the error messages found.

If you find an error that isn’t revealed in any current tests. Please let me know and I can fix it and add a new test.

The new Tutorial is going smoothly. It will walk you through the basics of KiCommand like how to use the stack, and basic calculations. Start there if you’re new to KiCommand!

Still to come are instructions on how to find and manipulate pcb elements. There is some information there, but it’s not fully organized yet. Stay tuned!

2 Likes

Added some new commands and fixed a nasty bug in the not command. So simple, it seemed like it didn’t need testing. I was wrong. Everyone should download the latest version.

I really want to reiterate that if you’ve been wondering what KiCommand can do, you should really walk through the Tutorial. There, you’ll learn the very basics of KiCommand. There’s a little bit about querying pcb components and using the filter command.

There’s definitely more to come.

Seeking help in testing! Does anyone have time to test KiCommand with either the nightly builds or earlier 4.x releases of KiCAD? There are pretty extensive tests now in KiCommand. It just requires three steps:

  1. Copy the kicommand folder into the appropriate plugins folder.
  2. Possibly create a user-level kicommand folder. This is a non-standard folder that holds user-created commands.
  3. From the Script Console, run import kicommand.test

Hopefully, there will be a wide variety of conditions tested: operating systems (Mac, Windows, and Linux), python version (2.x and 3.x), and KiCAD version.s (4.x and 5.x). Another variable might be the wx library version.

Please list here the KiCAD “About” information as well as the KiCommand commit number (such as “ 1be79a27”).

I’ll summarize the results on the KiCommand wiki page.

I’m working through a tutorial on drawing KiCAD elements using KiCommand,

Polygons are relatively new to KiCAD: they were introduced after KiCommand got started. The drawpoly command and drawsegments command are currently synonymous. I’m thinking of changing drawpoly to actually draw a KiCAD polygon element.

Would anyone have an issue if the drawpoly command changed so that it instead created a proper POLYGON KiCAD element?

Major update to KiCommand, changing how it loads so it should show up in External Plugins… menu more reliably. Also added to the KiCommand Wiki showing how to create tracks and lines (DRAWSEGMENTS). Still working toward easy assignment of nets to tracks. Added some more tests to verify installation, and updated the README.md in the github repo. Please let me know if you see any issues.

Updated KiCommand to include four new commands for dealing with tracks and nets: setnetcode, setnetname, getnetcodefromname, and getallnetnames.

KiCommand has a fairly complete list of commands and each of these commands is defined by a command string. You can use the see command to view how they are defined. For example:

  • ’getnetcodefromname see 'setnetcode see - will show you how those two commands are built from other KiCommand commands.

Another update to KiCommand.

  • showparams now instead of “showparam”: to be consistent with drawparams and params commands.
  • New tests for some geometry and drawing commands.
  • round has been fixed to handle a closed loop of drawsegments.
  • rotate now works on arcs appropriately, and should handle all EDA_ITEMs.
  • list. - make a list of lists from a single list.
  • callargs now extends either args or objects to the length of the longest list.
  • These two changes enable the ability to list all layernames with the following command:
  • board list 0,64,1 range list. GetLayerName callargs - list all layer names from 0 to 63.

KiCommand now has numerous unit tests that test both KiCommand and the underlying Python commands. There are a bunch of extra commands and some changes to the help text and categories. Let me know if there’s anything unexpected.

Work continues on expanding support for nets and netclasses. Support for netclass commands will be uploaded soon.

Major update to KiCommand to include net and netclass commands. I haven’t tested the set* commands, but the get* commands work well.

I’ve tried to standardize on get* command using an argument, while commands that are nouns (like netnamemap, netcodemap, tracks, etc) retrieve board-wide lists/maps of objects. To do this, a few commands have changed, and there are perhaps a few holdover commands that still need updating.

Through all of this, one command seemed out of place: matchreference was renamed to filterrefregex (filter reference regular expression) and a corresponding filtervalregex added to complement. The filter* commands filter the objectlist provided as an argument based on matching criteria also provided as an argument.

Development continues, and comments, discussion, or questions are welcome.

In my attempt to be very flexible in handling lists, where functions operate seamlessly on the elements of a list, I’ve run into an ambiguity. I’ve recently extended call and callargs to work on lists where you can supply a list of objects and/or a list of arguments and/or a list of functions, and it works well. For example:

  • netclassmap Default sindex GetClearance,GetTrackWidth,GetViaDiameter,GetViaDrill,GetuViaDiameter,GetuViaDrill,GetDiffPairWidth,GetDiffPairGap split call - return as a list, each of the listed values from the netclassptr object.

The detection of a list is determined by identifying an iterator. If it is an iterator, it is considered a list. With this detection, a dictionary is identified as a ‘list’ because it has an iterator. This makes it more difficult to directly call dictionary functions, such as keys() or values().

The solution is either to surround the dictionary with list and delist to get past the detection mechanism, or to redefine the new call and callargs functions into call. and callargs., which indicate an element-by-element function. Then redefine the call and callargs to not operate on lists element by element.

I’m trying to keep in mind that KiCommand is primarily an interactive command line and determine what is most useful in that context.

While I decide how to proceed, comments are welcome.

Edit: Maybe I could add calld and callargsd to indicate “direct”, where I ignore the iterator status of the objectlist. My main problem is that I like the ease of use of handling lists automatically, and I want that to be the “default” for unadorned functions.

Hi @HiGreg, i wonder if i can use your KiCommand to highlight all “equal” components in PCBnew?
So for example if i wanted to highlight all resistors with value 1k and 0603 package could i use something like

show all r 1k 0603 

or can i alter specific attributes of a footprint with it like the “lock” with something like

lock all fp

I’ve read the wiki and your read.me but you talk a lot about data types and stuff but it’s not quite clear to me if and how i could achieve the two examples from above.
If this is off topic, tell me and i open a new thread.

This is exactly on topic. First thing to note is that KiCommand is stack based, so arguments occur before the command. You can get all 1k resistors by using either a regular expression or a string match. Let’s walk through the demo board available in the kicad install directory (share/kicad/demos/complex_hierarchy). Load that board then try the following:

  • modules getvaltext print - this will print the value text of all modules

on the demo board, I see:

[u’CONN_2’, u’CONN_2’, u’CONN_2’, u’CONN_2’, u’CONN_2’, u’CONN_2’, u’1N4148’, u’1N4148’, u’1N4148’, u’1N4148’, u’1N4148’, u’1N4148’, u’1N4148’, u’1N4148’, u’1N4007’, u’15nF’, u’4.7nF’, u’150nF’, u’150nF’, u’820pF’, u’15nF’, u’4.7nF’, u’820pF’, u’LM358N’, u’ICL7660’, u’LM358N’, u’5,6K’, u’220K’, u’1K’, u’1K’, u’47’, u’220K’, u’47’, u’220K’, u’47’, u’220K’, u’470’, u’4,7K’, u’22K’, u’22K’, u’1K’, u’1K’, u’5,6K’, u’4,7K’, u’220K’, u’470’, u’220K’, u’47’, u’22K’, u’1K’, u’22K’, u’1K’, u’47uF’, u’47uF/20V’, u’47uF/63V’, u’10uF’, u’10uF’, u’MPAS92’, u’MPAS42’, u’MPAS92’, u’MPAS42’, u’MPAS92’, u’MPAS42’, u’MPAS92’, u’MPAS42’, u’4,7K’, u’4,7K’, u’78L05’]

  • modules getreftext print - print the reference text of all modules

Result:

[u’P5’, u’P6’, u’P3’, u’P4’, u’P2’, u’P1’, u’D9’, u’D4’, u’D6’, u’D7’, u’D3’, u’D2’, u’D8’, u’D5’, u’D1’, u’C3’, u’C4’, u’C14’, u’C12’, u’C5’, u’C6’, u’C7’, u’C8’, u’U3’, u’U1’, u’U4’, u’R20’, u’R22’, u’R23’, u’R24’, u’R25’, u’R26’, u’R27’, u’R28’, u’R5’, u’R4’, u’R3’, u’R21’, u’R17’, u’R7’, u’R8’, u’R9’, u’R10’, u’R11’, u’R12’, u’R13’, u’R14’, u’R15’, u’R16’, u’R18’, u’R6’, u’R19’, u’C1’, u’C2’, u’C9’, u’C10’, u’C11’, u’Q1’, u’Q2’, u’Q3’, u’Q4’, u’Q5’, u’Q6’, u’Q7’, u’Q8’, u’RV1’, u’RV2’, u’U2’]

The next one is a little tricky. Getting the path of the footprint. Try this:

  • clear modules GetFPID call GetLibItemName call '__str__ call print - get the name of the footprint

One of the items here is named “R_Axial_DIN0204_L3.6mm_D1.6mm_P7.62mm_Horizontal”, which seems to indicate its size (but it’s not guaranteed).

Now that we know a little bit about the board, we can start to hone our command to get only the desired modules.

Using some commands to filter on the name and value, assuming resistors start with “R”:

  • modules R.* filterrefregex 1K filtervalregex print - filter on modules with reference beginning with R and value of 1K

But we want to make sure we get the 0603, so let’s assume that string is in the footprint path.

  • copy GetFPID call GetLibItemName call '__str__ call - get the library name

We’ll call the following command string the module selection command. It’s a combination of all the above:

clear modules R.* filterrefregex 1K filtervalregex copy GetFPID call GetLibItemName call '__str__ call .*0204.* regex filter

That’s the command we’ll use to find the modules. You’ll want to change that to 0603 instead of 0204. Then we need to get or set their Lock status. There’s not a built in KiCommand to lock a footprint, but we can drop into the python function.

Execute the above module selection command to get all the modules desired. Then execute only one of the following.

Execute the module selection command, then:

  • IsLocked call - get the Locked status of modules

Execute the module selection command, then:

  • true SetLocked callargs - set the Locked status of modules

Finally, check that it worked. Execute the module selection command, then:

  • IsLocked call - get the Locked status of modules

Edit:

I just pushed some new commands for your use case: getlocked, setlocked, clearlocked, getfootprintname and filterfpregex.

The locked commands mirror get/set/clear visible, but don’t exactly match the Python commands underneath (SetLocked/IsLocked).

Example:

  • modules R.* filterrefregex 1K filtervalregex .*0603.* filterfpregex copy setlocked getlocked print - get modules matching each of the three criteria, set the locked status, then retrieve the locked status and print out the result. Should result in a list of “True” values.
3 Likes

Thank you for this extensive post. I sadly will have no time to proceed with this until the end of next week, but I’ll come back and report a bit about my experience once I’m done.

A bit of background on my use case:
i assemble PCBs in small batches like 1-5 pieces, by hand. So i use the PCB file as reference for assembly but keep selecting anything in PCBnew but the whole footprint, that’s quite annoying and the reason why i want to lock them. It’s also very useful to be able to show all equal components so i don’t have to search for the bag with the 1k resistor 25 times :wink:

@Detzi, whether or not this can be done with KiCommand, I would recommend trying the InteractiveHtmlBom plugin for hand assembly. It’s meant exactly for your use case.

4 Likes

KiCommand has been tested on pre release 5.1.6 (April 20) on Windows and no changes were necessary. There is one test (the now command) that occasionally fails, but the test will be fixed in the next release.

In the last couple of releases of KiCommand, there has been much work on making command consistent, along with updates to call and callargs that will be useful to users. Please feel free to reach out with comments, questions, or suggestions.