← Back to team overview

kicad-developers team mailing list archive

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

 

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 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>
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
> > 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