← Back to team overview

kicad-developers team mailing list archive

[PATCH] Add python apis: GetLogicalLibs, FootprintsInLib and FootprintInfo

 

I submitted this patch before, but it fell through the cracks.

This patch makes it possible to query pcbnew for a list of footprint
libraries, and the footprints contained therein. (without reading fp-lib
myself)


my previous attempt:
https://lists.launchpad.net/kicad-developers/msg35236.html
It has some implementation notes that may be of interest.


I believe I have followed the coding guidelines which I have read several
times. If I missed something, please indicate more than "follow the
guidelines". At least a theme. (trailing space, curlies,...)


Since attachments don't seem to make it to the launchpad site, I've also
made the patch file available here:
http://mmccoo.com/random/0001-Add-the-python-apis-GetLogicalLibs-FootprintsInLib-a.patch


Miles
From 3b5bc236d6b1c075e9cb49d6432f1ea2b8e876a6 Mon Sep 17 00:00:00 2001
From: Miles McCoo <mail@xxxxxxxxxx>
Date: Fri, 4 May 2018 10:01:54 +0200
Subject: [PATCH] Add the python apis: GetLogicalLibs, FootprintsInLib and
 FootprintInfo.
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="------------2.17.0"

This is a multi-part message in MIME format.
--------------2.17.0
Content-Type: text/plain; charset=UTF-8; format=fixed
Content-Transfer-Encoding: 8bit


GetLogicalLibs will return the list of available footprint libraries
FootprintsInLib lists the footprints in a library based on the library's name.
FootprintInfo will return basic information about a particular footprint (num pads...)

A couple of interesting ways in which this patch may be different from other python interface patches:
created the file autodoc.i which gives help messages (docstrings as they are called in python) for the new APIs. The default docstrings generated by
SWIG are often not that helpful. knowing that a function takes a string is not enough. What should that string contain. It seemed to me these messages
should be together.

created the file swig_typemaps.i: a vector<int>, by default is returned as a point to a vector instance. in swig_typemaps.i should go directives for
when to expand stl templates. Other reasons to have a typemap is to automagically convert classes into something like a python tuple, dict, or list.

exposed pcb_edit_frame pointer stored in pcbnew_scripting_helpers to other parts of the SWIG files. This doesn't expose it to python. pcb_edit_frame
has a lot of interesting methods and also many that should be excluded.

Thank you to Orson (Maciej Suminski) and Jeff Young for their hints.

This thread may be of interest: https://lists.launchpad.net/kicad-developers/msg34925.html
---
 pcbnew/CMakeLists.txt                    |   2 +
 pcbnew/swig/autodoc.i                    |  44 +++++++++
 pcbnew/swig/footprint.i                  | 114 ++++++++++++++++++++++-
 pcbnew/swig/pcbnew.i                     |  13 ++-
 pcbnew/swig/pcbnew_scripting_helpers.cpp |   8 +-
 pcbnew/swig/pcbnew_scripting_helpers.h   |   3 +-
 pcbnew/swig/swig_typemaps.i              |  34 +++++++
 7 files changed, 212 insertions(+), 6 deletions(-)
 create mode 100644 pcbnew/swig/autodoc.i
 create mode 100644 pcbnew/swig/swig_typemaps.i


--------------2.17.0
Content-Type: text/x-patch; name="0001-Add-the-python-apis-GetLogicalLibs-FootprintsInLib-a.patch"
Content-Transfer-Encoding: 8bit
Content-Disposition: attachment; filename="0001-Add-the-python-apis-GetLogicalLibs-FootprintsInLib-a.patch"

diff --git a/pcbnew/CMakeLists.txt b/pcbnew/CMakeLists.txt
index 04cad9b35..614074271 100644
--- a/pcbnew/CMakeLists.txt
+++ b/pcbnew/CMakeLists.txt
@@ -441,6 +441,7 @@ if( KICAD_SCRIPTING )   # Generate pcbnew.py and pcbnew_wrap.cxx using swig
         DEPENDS plotcontroller.h
         DEPENDS exporters/gendrill_Excellon_writer.h
         DEPENDS swig/pcbnew.i
+        DEPENDS swig/autodoc.i
         DEPENDS swig/board.i
         DEPENDS swig/board_connected_item.i
         DEPENDS swig/board_design_settings.i
@@ -458,6 +459,7 @@ if( KICAD_SCRIPTING )   # Generate pcbnew.py and pcbnew_wrap.cxx using swig
         DEPENDS swig/pad.i
         DEPENDS swig/pcb_text.i
         DEPENDS swig/plugins.i
+        DEPENDS swig/swig_typemaps.i
         DEPENDS swig/text_mod.i
         DEPENDS swig/track.i
         DEPENDS swig/units.i
diff --git a/pcbnew/swig/autodoc.i b/pcbnew/swig/autodoc.i
new file mode 100644
index 000000000..ded5a43f6
--- /dev/null
+++ b/pcbnew/swig/autodoc.i
@@ -0,0 +1,44 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 1992-2018 KiCad Developers, see AUTHORS.txt for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+ */
+
+
+// The purpose of this file is to contain the help message docstrings seens from
+// the python interface.
+// SWIG will generate a default docstring but that is limited to the signature
+// of the function.
+// By specifying these docstrings manually, we can include additional hints.
+
+%feature("autodoc", "return a list of modules in a library.
+Takes a library name:
+mods = pcbnew.FootprintsInLib('MountingHole')
+") FootprintsInLib;
+
+%feature("autodoc", "Returns information about a footprint.
+example: pcbnew.FootprintInfo('MountingHole:MountingHole_3.2mm_M3')
+The ':' delimiter between the library and modules is important.
+Example output:
+{ 'uniquepadcount': 0, 'padcount': 0, 'name': 'MountingHole_3.2mm_M3',
+  'lib': 'MountingHole', 'doc': 'Mounting Hole 3.2mm, no annular, M3',
+  'ordernum': 0, 'keywords': 'mounting hole 3.2mm no annular m3'}") FootprintInfo;
+
+%feature("autodoc", "returns a list of all available footprint libraries") GetLogicalLibs;
diff --git a/pcbnew/swig/footprint.i b/pcbnew/swig/footprint.i
index 844ea3146..0edd6e22f 100644
--- a/pcbnew/swig/footprint.i
+++ b/pcbnew/swig/footprint.i
@@ -2,7 +2,7 @@
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
  * Copyright (C) 2012 NBEE Embedded Systems, Miguel Angel Ajo <miguelangel@xxxxxxx>
- * Copyright (C) 1992-2017 KiCad Developers, see AUTHORS.txt for contributors.
+ * Copyright (C) 1992-2018 KiCad Developers, see AUTHORS.txt for contributors.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -36,6 +36,11 @@
 %template(MODULE_List)  DLIST<MODULE>;
 %{
 #include <class_module.h>
+#include <project.h>
+#include <footprint_info.h>
+#include <fp_lib_table.h>
+#include <kiway.h>
+#include <stdexcept>
 %}
 
 
@@ -97,6 +102,113 @@
     %}
 }
 
+
+%inline %{
+    wxArrayString FootprintsInLib( const wxString& libname )
+    {
+        /* here, we enumerate by the library's name (the nickname)
+           for example:
+           mods = pcbnew.FootprintInLib( 'MountingHole' )
+           print("lib has {} modules", len(mods))
+        */
+        PCB_EDIT_FRAME* edit_frame = ScriptingGetPcbEditFrame();
+        if ( edit_frame )
+        {
+            PROJECT *prj =  &edit_frame->Prj();
+            FP_LIB_TABLE* fp_table = prj->PcbFootprintLibs( edit_frame->Kiway() );
+
+            try
+            {
+                wxArrayString aFootprintNames;
+                fp_table->FootprintEnumerate( aFootprintNames, libname );
+                return aFootprintNames;
+            }
+            catch ( IO_ERROR& e )
+            {
+                std::cout << "got IO_ERROR " << e.Problem() << " at " << e.Where() << std::endl;
+            }
+        }
+
+        return {};
+    }
+%}
+
+
+%inline %{
+    /* This function enables this python code:
+       for lib in pcbnew.GetLogicalLibs():
+           mods = pcbnew.FootprintsInLib( lib )
+           print( "lib {} has {} modules".format( lib, len( mods ) ) )
+    */
+    std::vector<wxString> GetLogicalLibs()
+    {
+        PCB_EDIT_FRAME* edit_frame = ScriptingGetPcbEditFrame();
+        if ( edit_frame )
+        {
+            PROJECT *prj =  &edit_frame->Prj();
+            FP_LIB_TABLE* fp_table = prj->PcbFootprintLibs( edit_frame->Kiway() );
+            return fp_table->GetLogicalLibs();
+        }
+
+        return {};
+    }
+%}
+
+
+%inline %{
+    /* This function returns information about a footprint. As an example. this:
+       pcbnew.FootprintInfo( 'MountingHole:MountingHole_3.2mm_M3' )
+       yields this:
+       { 'uniquepadcount': 0, 'padcount': 0, 'name': 'MountingHole_3.2mm_M3',
+         'lib': 'MountingHole', 'doc': 'Mounting Hole 3.2mm, no annular, M3',
+         'ordernum': 0, 'keywords': 'mounting hole 3.2mm no annular m3'}
+
+       This function is different from most of the others:
+       * first, it's in an inline block.
+       * second, and more interesting, is that it returns a PyObject directly.
+         This is because the lookedup instance FOOTPRINT_INFO will go out of scope
+         when we leave this function. So we create a PyObject (actually a dict) here.
+    */
+    PyObject *FootprintInfo( const wxString &modname )
+    {
+        // I'm using BeforeLast because it returns the empty string if ':' is
+        // not found. makes it easy to check for success.
+        wxString libname = modname.BeforeLast( ':' );
+        if ( libname.IsEmpty() )
+        {
+            throw std::invalid_argument( std::string( "expected module name of format libname:modname. got ") +
+                                         modname.ToStdString() );
+        }
+
+        PCB_EDIT_FRAME* edit_frame = ScriptingGetPcbEditFrame();
+        if ( edit_frame )
+        {
+            PROJECT *prj =  &edit_frame->Prj();
+            FOOTPRINT_LIST* fpl = FOOTPRINT_LIST::GetInstance( edit_frame->Kiway() );
+            fpl->ReadFootprintFiles( prj->PcbFootprintLibs(), &libname );
+            FOOTPRINT_INFO* footprint = fpl->GetModuleInfo( modname );
+            if ( footprint ) {
+                PyObject *retval = PyDict_New();
+
+                PyDict_SetItemString( retval, "name",     PyString_FromString( footprint->GetFootprintName() ) );
+                // I find nickname to be misleading. it's the name of the lib.
+                PyDict_SetItemString( retval, "lib",      PyString_FromString( footprint->GetNickname() ) );
+                PyDict_SetItemString( retval, "doc",      PyString_FromString( footprint->GetDoc() ) );
+                PyDict_SetItemString( retval, "keywords", PyString_FromString( footprint->GetKeywords() ) );
+
+                PyDict_SetItemString( retval, "padcount",       PyInt_FromLong( footprint->GetPadCount() ) );
+                PyDict_SetItemString( retval, "uniquepadcount", PyInt_FromLong( footprint->GetUniquePadCount() ) );
+                PyDict_SetItemString( retval, "ordernum",       PyInt_FromLong( footprint->GetOrderNum() ) );
+
+                return retval;
+            }
+        }
+
+        Py_INCREF( Py_None );
+        return Py_None;
+    }
+%}
+
 %pythoncode
 %{
     def GetPluginForPath(libname):
diff --git a/pcbnew/swig/pcbnew.i b/pcbnew/swig/pcbnew.i
index 3181df762..8bf797f0f 100644
--- a/pcbnew/swig/pcbnew.i
+++ b/pcbnew/swig/pcbnew.i
@@ -2,7 +2,7 @@
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
  * Copyright (C) 2012 NBEE Embedded Systems, Miguel Angel Ajo <miguelangel@xxxxxxx>
- * Copyright (C) 1992-2017 KiCad Developers, see AUTHORS.txt for contributors.
+ * Copyright (C) 1992-2018 KiCad Developers, see AUTHORS.txt for contributors.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -35,6 +35,12 @@
 %include "docstrings.i"
 #endif
 
+// docstrings.i above comes from doxygen. The docstrings contained
+// in autodoc.i are manually writen for the python world.
+%include autodoc.i
+
+%include swig_typemaps.i
+
 // support for wchar_t
 %include "cwstring.i"
 
@@ -94,6 +100,9 @@ Therefore please help gather the subset of C++ functions for this class that do
 throw and add them here, before the class declarations.
 
 */
+HANDLE_EXCEPTIONS(FootprintEnumerate)
+HANDLE_EXCEPTIONS(FootprintInfo)
+HANDLE_EXCEPTIONS(footprintPyEnumerate)
 HANDLE_EXCEPTIONS(PLUGIN::Load)
 HANDLE_EXCEPTIONS(PLUGIN::Save)
 HANDLE_EXCEPTIONS(PLUGIN::FootprintEnumerate)
@@ -124,5 +133,3 @@ HANDLE_EXCEPTIONS(LoadBoard)
 %include footprint.i
 %include plugins.i
 %include units.i
-
-
diff --git a/pcbnew/swig/pcbnew_scripting_helpers.cpp b/pcbnew/swig/pcbnew_scripting_helpers.cpp
index 065c029f7..3ec2f39a6 100644
--- a/pcbnew/swig/pcbnew_scripting_helpers.cpp
+++ b/pcbnew/swig/pcbnew_scripting_helpers.cpp
@@ -2,7 +2,7 @@
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
  * Copyright (C) 2012 NBEE Embedded Systems, Miguel Angel Ajo <miguelangel@xxxxxxx>
- * Copyright (C) 1992-2017 KiCad Developers, see AUTHORS.txt for contributors.
+ * Copyright (C) 1992-2018 KiCad Developers, see AUTHORS.txt for contributors.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -59,6 +59,12 @@ void ScriptingSetPcbEditFrame( PCB_EDIT_FRAME* aPcbEditFrame )
 }
 
 
+PCB_EDIT_FRAME* ScriptingGetPcbEditFrame()
+{
+    return s_PcbEditFrame;
+}
+
+
 BOARD* LoadBoard( wxString& aFileName )
 {
     if( aFileName.EndsWith( wxT( ".kicad_pcb" ) ) )
diff --git a/pcbnew/swig/pcbnew_scripting_helpers.h b/pcbnew/swig/pcbnew_scripting_helpers.h
index 6233b3ac5..8d9bea831 100644
--- a/pcbnew/swig/pcbnew_scripting_helpers.h
+++ b/pcbnew/swig/pcbnew_scripting_helpers.h
@@ -2,7 +2,7 @@
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
  * Copyright (C) 2013 NBEE Embedded Systems SL, Miguel Angel Ajo <miguelangel@xxxxxx>
- * Copyright (C) 2013-2017 KiCad Developers, see AUTHORS.txt for contributors.
+ * Copyright (C) 2013-2018 KiCad Developers, see AUTHORS.txt for contributors.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -35,6 +35,7 @@
 #ifndef SWIG
 void    ScriptingSetPcbEditFrame( PCB_EDIT_FRAME* aPCBEdaFrame );
 
+PCB_EDIT_FRAME* ScriptingGetPcbEditFrame();
 #endif
 
 // For Python scripts: return the current board.
diff --git a/pcbnew/swig/swig_typemaps.i b/pcbnew/swig/swig_typemaps.i
new file mode 100644
index 000000000..8c370c8d8
--- /dev/null
+++ b/pcbnew/swig/swig_typemaps.i
@@ -0,0 +1,34 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 1992-2018 KiCad Developers, see AUTHORS.txt for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+ */
+
+
+%{
+#include <wx/string.h>
+#include <vector>
+%}
+
+%include "std_vector.i"
+namespace std
+{
+    %template( vector_wxstring ) vector<wxString>;
+}

--------------2.17.0--



Follow ups