footprint enumerate doesn't like wxnullstring (see hang below) and it only looks at one row. No iterator in there. *How do I iterate over the rows?*
note that there is also PCB_IO::FootprintEnumerate (some would call it a plugin) that behaves different. It's the one used in footprint.i. void FP_LIB_TABLE::FootprintEnumerate( wxArrayString& aFootprintNames, const wxString& *aNickname* ) { const FP_LIB_TABLE_ROW* *row = FindRow( aNickname );* wxASSERT( (PLUGIN*) row->plugin ); row->plugin->FootprintEnumerate( aFootprintNames, row->GetFullURI( true ), row->GetProperties() ); } *But I do see now why it's hanging*. The THROW_IO_ERROR is where things disappear. const FP_LIB_TABLE_ROW* FP_LIB_TABLE::FindRow( const wxString& aNickname ) { FP_LIB_TABLE_ROW* row = dynamic_cast< FP_LIB_TABLE_ROW* >( *findRow*( aNickname ) ); if( !row ) { wxString msg = wxString::Format( _( "fp-lib-table files contain no library with nickname \"%s\"" ), GetChars( aNickname ) ); THROW_IO_ERROR( msg ); } here is findRow() for reference: LIB_TABLE_ROW* LIB_TABLE::findRow( const wxString& aNickName ) const { LIB_TABLE* cur = (LIB_TABLE*) this; do { cur->ensureIndex(); INDEX_CITER it = cur->nickIndex.find( aNickName ); if( it != cur->nickIndex.end() ) { return &cur->rows[it->second]; // found } // not found, search fall back table(s), if any } while( ( cur = cur->fallBack ) != 0 ); return NULL; // not found } Miles On Wed, Mar 14, 2018 at 10:21 PM, Jeff Young <j...@rokeby.ie> wrote: > Sorry, I meant wxEmptyString, not nullptr. The string argument tells the > routine to enumerate only the one .pretty file; if you pass the empty > string then it will enumerate all of the .pretty files in the fp-lib-table. > > > > On 14 Mar 2018, at 21:17, miles mccoo <m...@mmccoo.com> wrote: > > from Jeff: > *wxArrayString footprintNames;* > *fp_table->FootprintEnumerate( footprintNames, nullptr )* > > *will load footprintNames with all the footprints.* > > > That method doesn't take a nullptr. From fp_lib_table.h: > void FootprintEnumerate( wxArrayString& aFootprintNames, *const wxString&* > aNickname ); > > *Is there a function somewhere that will tell me all of the paths to > libraries?* > > > But I do see now that the function hangs because I'm incorrectly calling > the method. (though that doesn't justify the hang) > > in scripting window these commands assert complaining about an empty dir: > import pcbnew > pcbnew.FootprintEnumerate('') > > > this hangs: > import pcbnew > pcbnew.FootprintEnumerate('MountingHole') > > > *This is the correct way to call i*t: (the python interface looks > different, but it is, indeed, the same function[1] > import pcbnew > pcbnew.FootprintEnumerate('/home/mmccoo/kicad/kicad- > footprints/MountingHole.pretty') > > > [u'MountingHole_2.2mm_M2', u'MountingHole_2.2mm_M2_DIN965', > u'MountingHole_2.2mm_M2_DIN965_Pad', u'MountingHole_2.2mm_M2_ISO14580', > u'MountingHole_2.2mm_M2_ISO14580_Pad', u... > > > > Miles > > > > [1] from footprint.i > wxArrayString footprintPyEnumerate( const wxString& aLibraryPath, bool > aExitOnError ) > { > wxArrayString footprintNames; > > if( aExitOnError ) > self->FootprintEnumerate( footprintNames, aLibraryPath ); > else > { > try > { > self->FootprintEnumerate( footprintNames, aLibraryPath ); > } > catch( const IO_ERROR& error ) > { > } > } > > return footprintNames; > } > > %pythoncode > %{ > def FootprintEnumerate(self, libname): > return self.footprintPyEnumerate( libname, True ) > %} > > > On Mar 14, 2018 9:30 PM, "Jeff Young" <j...@rokeby.ie> wrote: > >> Hi Miles, >> >> wxArrayString footprintNames; >> fp_table->FootprintEnumerate( footprintNames, nullptr ) >> >> will load footprintNames with all the footprints. >> >> So in GDB you need to be looking at the size of aFootprintNames, not >> fp_table. >> >> Cheers, >> Jeff. >> >> >> On 14 Mar 2018, at 20:01, miles mccoo <m...@mmccoo.com> wrote: >> >> 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 <stambau...@gmail.com> >> 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.sumin...@cern.ch <mailto:maciej.sumin...@cern.ch>> 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@lists.launchpad.net >>> > <mailto:kicad-developers@lists.launchpad.net> >>> > > 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@lists.launchpad.net >>> > <mailto:kicad-developers@lists.launchpad.net> >>> > 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@lists.launchpad.net >>> > Unsubscribe : https://launchpad.net/~kicad-developers >>> > More help : https://help.launchpad.net/ListHelp >>> > >>> >>> _______________________________________________ >>> Mailing list: https://launchpad.net/~kicad-developers >>> Post to : kicad-developers@lists.launchpad.net >>> Unsubscribe : https://launchpad.net/~kicad-developers >>> More help : https://help.launchpad.net/ListHelp >>> >> >> _______________________________________________ >> Mailing list: https://launchpad.net/~kicad-developers >> Post to : kicad-developers@lists.launchpad.net >> Unsubscribe : https://launchpad.net/~kicad-developers >> More help : https://help.launchpad.net/ListHelp >> >> >> >
_______________________________________________ Mailing list: https://launchpad.net/~kicad-developers Post to : kicad-developers@lists.launchpad.net Unsubscribe : https://launchpad.net/~kicad-developers More help : https://help.launchpad.net/ListHelp