kicad-developers team mailing list archive
-
kicad-developers team
-
Mailing list archive
-
Message #34965
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