← Back to team overview

kicad-developers team mailing list archive

Re: Need guidance/hints on accessing list of available pcbnew footprints from python

 

Wayne said:





*The footprint library table internally handles fallback library tablesso
you can iterate over all of the same information available no matterhow
deeply nested the fallback tables are from the project library tablewithout
exposing the fallback table pointer.  If you cannot access thecontents of
the entire library table without exposing the fallback tablepointer, then
the python bindings for the library table are broken.*



At this point,* I'm not using python bindings. I'm in GDB poking around. *I'm
trying to figure out what bindings I need to add

Again, I'm trying to get a list of all available footprints.



If, *in gdb*,  I step through this new (ie, in my sandbox only) function:
void GetFootprints2()
{
    if( s_PcbEditFrame ) {
        PROJECT *prj =  &s_PcbEditFrame->Prj();
        FP_LIB_TABLE* fp_table = prj->PcbFootprintLibs(
s_PcbEditFrame->Kiway() );

        wxArrayString aFootprintNames;
        fp_table->FootprintEnumerate(aFootprintNames, "MountingHole");
        std::cout << "num enumerated " << aFootprintNames.size() <<
std::endl;
    }
}

I get this

187             fp_table->FootprintEnumerate(aFootprintNames,
"MountingHole");
(gdb) print* fp_table->GetCount()*
$23 = *0*
(gdb) print fp_table->IsEmpty()
Too few arguments in function call.
(gdb) print fp_table->IsEmpty(true)
$24 = false
(gdb) print fp_table->IsEmpty(false)
$25 = true
(gdb) print *fp_table->fallBack->GetCount(*)
$27 = *92*



So, I can't iterate the rows via the At() method (which only looks at the
current table)



*If I call FootprintEnumerate, my pcbnew hangs.* both with empty string as
last arg and as above. It seems to go into some other threads and I think
it hangs in some sort of mutex.

The stack trace is below. The other threads don't look any more interesting.

Miles


(gdb) bt
#0  0x00007ffff60a1827 in futex_abstimed_wait_cancelable (private=0,
abstime=0x0, expected=0, futex_word=0x1dc1df0)
    at ../sysdeps/unix/sysv/linux/futex-internal.h:205
#1  do_futex_wait (sem=sem@entry=0x1dc1df0, abstime=0x0) at
sem_waitcommon.c:111
#2  0x00007ffff60a18d4 in __new_sem_wait_slow (sem=0x1dc1df0, abstime=0x0)
at sem_waitcommon.c:181
#3  0x00007ffff60a197a in __new_sem_wait (sem=<optimized out>) at
sem_wait.c:29
#4  0x00007fffda058fe8 in PyThread_acquire_lock () from
/usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0
#5  0x00007fffda02d926 in PyEval_RestoreThread () from
/usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0
#6  0x00007fffdaedc27c in pcbnewFinishPythonScripting () at
/home/mmccoo/kicad/kicad/pcbnew/swig/python_scripting.cpp:270
#7  0x00007fffda86e3c7 in PCB::IFACE::OnKifaceEnd (this=0x7fffdbfe1ae0
<PCB::kiface>)
    at /home/mmccoo/kicad/kicad/pcbnew/pcbnew.cpp:382
#8  0x000000000045d37d in KIWAY::OnKiwayEnd (this=0x6f3680 <Kiway>) at
/home/mmccoo/kicad/kicad/common/kiway.cpp:489
#9  0x00000000004535f8 in PGM_SINGLE_TOP::OnPgmExit (this=0x6f3a40
<program>)
    at /home/mmccoo/kicad/kicad/common/single_top.cpp:67
#10 0x0000000000454018 in APP_SINGLE_TOP::OnExit (this=0x756110) at
/home/mmccoo/kicad/kicad/common/single_top.cpp:154
#11 0x00007ffff6c4af7f in CallOnExit::~CallOnExit (this=<synthetic
pointer>, __in_chrg=<optimized out>)
    at ../src/common/init.cpp:489
#12 wxEntry (argc=<optimized out>, argv=<optimized out>) at
../src/common/init.cpp:490
#13 0x000000000044f9ed in main (argc=1, argv=0x7fffffffd7c8) at
/home/mmccoo/kicad/kicad/common/single_top.cpp:239


On Wed, Mar 14, 2018 at 6:05 PM, Wayne Stambaugh <stambaughw@xxxxxxxxx>
wrote:

> On 3/14/2018 11:04 AM, miles mccoo wrote:
> > Thanks for the tips, Orson. That gave me what I needed, sort of.
> > Additional guidance needed.
> >
> >
> >
> > Let me describe what I have working and everyone can tell me if I
> > understood everything correctly. You may want things moved around a bit
> > as well.
> >
> > *high level view* is that I added pcbnew.GetFootprints(libname="") which
> > returns a list of python dicts. like this:
> > {'uniquepadcount': 1, 'padcount': 1, 'name':
> > 'MountingHole_2.2mm_M2_DIN965_Pad', 'lib': 'MountingHole', 'doc':
> > 'Mounting Hole 2.2mm, M2, DIN965', 'ordernum': 0, 'keywords': 'mounting
> > hole 2.2mm m2 din965'}
> >
> >
> > First, I'll mention that there already exists a footprint.i which has
> > functions like FootprintLoad for getting an actual module instance.
> > Couple issues there:
> >
> >   * This is where I wanted to put GetFootprints, but *the code *(based
> >     off Orson's hint) *wants a Kiway, which I only know to get
> >     from PcbEditFrame*. pcbnew_scripting_helpers knows about
> >     the PcbEditFrame so that's where I put it.
> >   * footprints.i has a Footprint enumerate, but it wants a library path,
> >     which I don't have. More important, *it hangs when I run it*. I've
> >     CC'd JP Charras who authored that code (also one of the main Kicad
> >     people?).
> >
> >
> > *Additional wierdness*
> >
> > The needed function should look like this:
> > auto fp_info_list( FOOTPRINT_LIST::GetInstance( Kiway() ) );
> > fp_info_list->ReadFootprintFiles( Prj().PcbFootprintLibs(), !nickname ?
> > NULL : &nickname );
> > for( auto& footprint : fp_info_list->GetList() ) {
> >
> > }
> >
> > fp_info_list is a local, which returns a list of unique footprint_info
> > ptrs. The problems are:
> >
> >   * footprint_info doesn't have a copy constructor. It's abstract
> >     virtual. So I can't make a copy of the GetList
> >   * I can't return GetList to SWIG since fp_info_list goes out of scope.
> >   * so I return fp_info_list to SWIG via a unique_ptr[1]
> >
> >
> > I then have a swig typemap which gets GetList and generates the list of
> > dicts. See [2] for the main code
> >
> >
> > So that's what I have based off Orson's suggestion.
> >
> >
> > *More detail on the other path I had been exploring* (which avoids some
> > of the unique ptr stuff)*:*
> >
> > from pcb_edit_frame, I can get prj. from prj I can use FP_LIB_TABLE*
> > PcbFootprintLibs. FP_LIB_TABLE is a LIB_TABLE which links to a fallback
> > LIB_TABLE. That fallback is protected.*If I could expose it via a Get
> > method, this path could work too*.
>
> The footprint library table internally handles fallback library tables
> so you can iterate over all of the same information available no matter
> how deeply nested the fallback tables are from the project library table
> without exposing the fallback table pointer.  If you cannot access the
> contents of the entire library table without exposing the fallback table
> pointer, then the python bindings for the library table are broken.  If
> you need to access the global library table, you can load it directly by
> creating a new FP_LIB_TABLE object and using
> FP_LIB_TABLE::GetGlobalTableFileName() but that should not be necessary.
>
> >
> >
> > the includefallback I was referring to is in lib_table_base.h
> >
> > /**
> >      * Return true if the table is empty.
> >      *
> >      * @param aIncludeFallback is used to determine if the fallback
> > table should be
> >      *                         included in the test.
> >      *
> >      * @return true if the footprint library table is empty.
> >      */
> >     bool IsEmpty( bool *aIncludeFallback* = true );
> >
> >
> > these APIs don't have that:
> > int GetCount()       { return rows.size(); }
> >
> >     LIB_TABLE_ROW* At( int aIndex ) { return &rows[aIndex]; }
> >
> >
> >
> > A GetFallback method could do the trick? If I could get to it, I could
> > iterate over
> >
> >
> > Apologies for the long mail. *Getting the list of footprints seems
> > harder than it should be? Anything I can do to help fix that? *Some
> > refactoring, perhaps.
> >
> >
> > Miles
> >
> >
> > [1] swig doesn't play nicely with unique_ptrs.
> > see  http://www.swig.org/Doc3.0/SWIGDocumentation.html#SWIGPlus_nn19
> > and https://stackoverflow.com/a/27699663/23630
> >
> > [2]
> > // I am returing a shared_ptr to fp_info_list because that's the only
> way to
> > // hold onto the list of footprint_infos long enough for the swig
> typename
> > // to dictionary'ify it.
> > // I can't just copy the footprint_infos; they as an abstract class
> > (load()=0)
> > // I don't like it, but this function should only be called by swig.
> > std::unique_ptr<FOOTPRINT_LIST> GetFootprints(const wxString &libname)
> > {
> >     // retval is a local unique ptr. If I just return GetList, it will
> > be filled
> >     // with 0x0s. This is because when fp_info_list is desctructed, the
> > unique_ptrs
> >     // returned by it will disappear as well.
> >
> >     std::unique_ptr<FOOTPRINT_LIST> retval;
> >
> >     if( s_PcbEditFrame ) {
> >         PROJECT *prj =  &s_PcbEditFrame->Prj();
> >         retval =  FOOTPRINT_LIST::GetInstance( s_PcbEditFrame->Kiway() );
> >         retval->ReadFootprintFiles( prj->PcbFootprintLibs(), !libname ?
> > NULL : &libname );
> >     }
> >     return retval;
> > }
> >
> >
> >
> >
> >
> > // http://www.swig.org/Doc3.0/SWIGDocumentation.html#SWIGPlus_nn19
> > // theoretically, the following should suppress the use of
> SwigValueWrapper
> > // but I couldn't get it to work:
> > // %feature("novaluewrapper") std::unique_ptr<FOOTPRINT_LIST>;
> >
> > // The template stuff below is based on this answer:
> > // https://stackoverflow.com/a/27699663/23630
> > // I can't say I understand how/why it works.
> > namespace std {
> >   %feature("novaluewrapper") unique_ptr;
> >   template <typename Type>
> >   struct unique_ptr {
> >       // we're not actually using the template feature of
> >       // swig to do anything. just want to avoid the use of SwigWrapper
> >   };
> > }
> > %template(UNIQUE_PTR_FOOTPRINT_LIST) std::unique_ptr<FOOTPRINT_LIST>;
> >
> >
> > %typemap(out) std::unique_ptr<FOOTPRINT_LIST> {
> >
> >     PyObject * retval = $result = PyList_New(0);
> >
> >     if ( !$1 ) return retval;
> >
> >     for( auto& footprint : $1->GetList() ) {
> >
> >         PyObject *fpobj = PyDict_New();
> >         int fail = 0;
> >         fail |= PyDict_SetItemString(fpobj, "name",
> >  PyString_FromString(footprint->GetFootprintName()));
> >         fail |= PyDict_SetItemString(fpobj, "lib",
> > PyString_FromString(footprint->GetNickname()));
> >         fail |= PyDict_SetItemString(fpobj, "doc",
> > PyString_FromString(footprint->GetDoc()));
> >         fail |= PyDict_SetItemString(fpobj, "keywords",
> > PyString_FromString(footprint->GetKeywords()));
> >
> >         fail |= PyDict_SetItemString(fpobj, "padcount",
> >  PyInt_FromLong(footprint->GetPadCount()));
> >         fail |= PyDict_SetItemString(fpobj, "uniquepadcount",
> > PyInt_FromLong(footprint->GetUniquePadCount()));
> >         fail |= PyDict_SetItemString(fpobj, "ordernum",
> >  PyInt_FromLong(footprint->GetOrderNum()));
> >
> >         if (fail) {
> >             SWIG_exception_fail(SWIG_TypeError, "unable to convert
> > FOOTPRINT_INFO list");
> >         }
> >         PyList_Append(retval, fpobj);
> >     }
> >
> >  }
> >
> >
> > On Tue, Mar 13, 2018 at 12:15 PM, Maciej Sumiński
> > <maciej.suminski@xxxxxxx <mailto:maciej.suminski@xxxxxxx>> wrote:
> >
> >     Hi Miles,
> >
> >     Have you seen FOOTPRINT_VIEWER_FRAME::ReCreateFootprintList()
> >     (pcbnew/footprint_viewer_frame.cpp)? It might be the easiest way to
> go.
> >     Perhaps it could be wrapped in a function provided by the scripting
> >     interface.
> >
> >     I could not find 'includefallback' option you have mentioned, would
> you
> >     point me to the relevant source code?
> >
> >     Regards,
> >     Orson
> >
> >     On 03/13/2018 10:49 AM, miles mccoo wrote:
> >     > In one of my python plugins, I want to know the list of available
> >     > footprints (mounting holes, in this case)
> >     >
> >     > Digging through the code, I can't make heads or tails of how to
> get this
> >     > information. There are a bunch of abstract class involved.
> impls....
> >     >
> >     > There are a couple possibilities, none of which seem clean.
> >     >
> >     > *Stuff from FOOTPRINT plugin*
> >     > looking in footprint.i, I see some APIs that are close.
> >     > If I have a directory path to a fp library, I can
> >     > call pcbnew.FootprintEnumerate for a nice list.
> >     >
> >     > but for that, I first have to have a list of fp library paths.
> >     *How do I
> >     > get such a list? *This seems like the closest answer. I see my
> >     config dir
> >     > has a fp-lib-table file which would be easy to parse. But that's a
> hack.
> >     >
> >     >
> >     >
> >     > *FOOTPRINT_LIST_IMPL possibility*
> >     > looking in load_select_footprint, I see it has a static
> FOOTPRINT_LIST_IMPL
> >     > which does have the APIs I'd need to get to a nice list of
> footprint_infos.
> >     > But it's static to that file. I could copy the relevant code to
> >     > python_scripting_helpers. but that feels messy.
> >     >
> >     > PCB_BASE_FRAME does have a method for popping up a table for a
> user to
> >     > choose a footprint, which is nice for UI. It could even be useful
> for
> >     > python plugins with some GUI stuff. But many python scripts will
> just want
> >     > a list of libraries and modules.
> >     >
> >     >
> >     >
> >     > *PROJECT possibility*
> >     > I tried exposing PROJECT to python as it has a number of useful
> sounding
> >     > API including PcbFootprintLibs which returns a FP_LIB_TABLE. By
> poking
> >     > around in gdb, I see that FP_LIB_TABLE has GetCount and IsEmpty.
> IsEmpty
> >     > returns false if I set includefallback to true. and the fallback
> list does
> >     > indeed have stuff in it. But it's protected and I don't see how to
> get to
> >     > it.
> >     >
> >     > Can I expose the fallback table via a public get method?
> >     >
> >     >
> >     > Is that a path that has any hope?
> >     >
> >     >
> >     >
> >     >
> >     >  *So what's the most straight forward way to get to the list of
> >     libraries
> >     > and modules within them?*
> >     >
> >     > Thanks
> >     > Miles
> >     >
> >     >
> >     >
> >     > _______________________________________________
> >     > Mailing list: https://launchpad.net/~kicad-developers
> >     <https://launchpad.net/~kicad-developers>
> >     > Post to     : kicad-developers@xxxxxxxxxxxxxxxxxxx
> >     <mailto:kicad-developers@xxxxxxxxxxxxxxxxxxx>
> >     > Unsubscribe : https://launchpad.net/~kicad-developers
> >     <https://launchpad.net/~kicad-developers>
> >     > More help   : https://help.launchpad.net/ListHelp
> >     <https://help.launchpad.net/ListHelp>
> >     >
> >
> >
> >
> >     _______________________________________________
> >     Mailing list: https://launchpad.net/~kicad-developers
> >     <https://launchpad.net/~kicad-developers>
> >     Post to     : kicad-developers@xxxxxxxxxxxxxxxxxxx
> >     <mailto:kicad-developers@xxxxxxxxxxxxxxxxxxx>
> >     Unsubscribe : https://launchpad.net/~kicad-developers
> >     <https://launchpad.net/~kicad-developers>
> >     More help   : https://help.launchpad.net/ListHelp
> >     <https://help.launchpad.net/ListHelp>
> >
> >
> >
> >
> > _______________________________________________
> > Mailing list: https://launchpad.net/~kicad-developers
> > Post to     : kicad-developers@xxxxxxxxxxxxxxxxxxx
> > Unsubscribe : https://launchpad.net/~kicad-developers
> > More help   : https://help.launchpad.net/ListHelp
> >
>
> _______________________________________________
> Mailing list: https://launchpad.net/~kicad-developers
> Post to     : kicad-developers@xxxxxxxxxxxxxxxxxxx
> Unsubscribe : https://launchpad.net/~kicad-developers
> More help   : https://help.launchpad.net/ListHelp
>

Follow ups

References