Skip to content

Commit

Permalink
python module: support for checks on board
Browse files Browse the repository at this point in the history
  • Loading branch information
carrotIndustries committed Apr 10, 2020
1 parent 5cff53c commit e47e579
Show file tree
Hide file tree
Showing 4 changed files with 188 additions and 27 deletions.
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -677,6 +677,10 @@ SRC_SHARED = $(SRC_COMMON) \
src/canvas/canvas_patch.cpp\
src/util/csv_util.cpp\
src/util/clipper_util.cpp\
src/document/document.cpp \
src/document/document_board.cpp \
src/rules/cache.cpp \
src/board/board_rules_check.cpp \

SRC_SHARED_GEN = $(SRC_COMMON_GEN)

Expand Down
191 changes: 180 additions & 11 deletions src/python_module/board.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,73 @@
#include "export_pdf/export_pdf_board.hpp"
#include "export_pnp/export_pnp.hpp"
#include "export_step/export_step.hpp"
#include "document/document_board.hpp"
#include "rules/cache.hpp"
#include <podofo/podofo.h>
#include "block/block.hpp"
#include "board/board.hpp"
#include "board/via_padstack_provider.hpp"
#include "project/project.hpp"
#include "pool/pool_cached.hpp"
#include "rules/rule_descr.hpp"

class BoardWrapper : public horizon::DocumentBoard {
public:
BoardWrapper(const horizon::Project &prj);
horizon::PoolCached pool;
horizon::Block block;
horizon::ViaPadstackProvider vpp;
horizon::Board board;
horizon::Board *get_board() override
{
return &board;
}
horizon::Block *get_block() override
{
return &block;
}
horizon::Pool *get_pool() override
{
return &pool;
}
horizon::Rules *get_rules() override
{
return &board.rules;
}
horizon::LayerProvider *get_layer_provider() override
{
return &board;
}
horizon::ViaPadstackProvider *get_via_padstack_provider() override
{
return &vpp;
}
horizon::FabOutputSettings *get_fab_output_settings() override
{
return &board.fab_output_settings;
}
horizon::PDFExportSettings *get_pdf_export_settings() override
{
return &board.pdf_export_settings;
}
horizon::STEPExportSettings *get_step_export_settings() override
{
return &board.step_export_settings;
}
horizon::PnPExportSettings *get_pnp_export_settings() override
{
return &board.pnp_export_settings;
}
horizon::BoardColors *get_colors() override
{
return &board.colors;
}
};

class BoardWrapper *create_board_wrapper(const horizon::Project &prj)
{
return new BoardWrapper(prj);
}

BoardWrapper::BoardWrapper(const horizon::Project &prj)
: pool(horizon::PoolManager::get().get_by_uuid(prj.pool_uuid)->base_path, prj.pool_cache_directory),
Expand Down Expand Up @@ -138,6 +204,19 @@ static PyObject *PyBoard_get_step_export_settings(PyObject *pself, PyObject *arg
class py_exception : public std::exception {
};

static void callback_wrapper(PyObject *cb, const std::string &s)
{
if (cb) {
PyObject *arglist = Py_BuildValue("(s)", s.c_str());
PyObject *result = PyObject_CallObject(cb, arglist);
Py_DECREF(arglist);
if (result == NULL) {
throw py_exception();
}
Py_DECREF(result);
}
}

static PyObject *PyBoard_export_step(PyObject *pself, PyObject *args)
{
auto self = reinterpret_cast<PyBoard *>(pself);
Expand All @@ -154,17 +233,7 @@ static PyObject *PyBoard_export_step(PyObject *pself, PyObject *args)
horizon::STEPExportSettings settings(settings_json);
horizon::export_step(
settings.filename, self->board->board, self->board->pool, settings.include_3d_models,
[py_callback](const std::string &s) {
if (py_callback) {
PyObject *arglist = Py_BuildValue("(s)", s.c_str());
PyObject *result = PyObject_CallObject(py_callback, arglist);
Py_DECREF(arglist);
if (result == NULL)
throw py_exception();
Py_DECREF(result);
}
},
nullptr, settings.prefix);
[py_callback](const std::string &s) { callback_wrapper(py_callback, s); }, nullptr, settings.prefix);
}
catch (const py_exception &e) {
return NULL;
Expand All @@ -180,16 +249,116 @@ static PyObject *PyBoard_export_step(PyObject *pself, PyObject *args)
Py_RETURN_NONE;
}

static void dummy_callback(const std::string &s)
{
}

static PyObject *PyBoard_run_checks(PyObject *pself, PyObject *args)
{
auto self = reinterpret_cast<PyBoard *>(pself);
PyObject *py_rules = nullptr;
PyObject *py_rule_ids = nullptr;
if (!PyArg_ParseTuple(args, "O!O", &PyDict_Type, &py_rules, &py_rule_ids))
return NULL;
PyObject *iter = nullptr;
if (!(iter = PyObject_GetIter(py_rule_ids))) {
PyErr_SetString(PyExc_TypeError, "rule ids must be iterable");
return NULL;
}

std::set<horizon::RuleID> ids;

while (PyObject *item = PyIter_Next(iter)) {
auto rule_name = PyUnicode_AsUTF8(item);
if (!rule_name) {
Py_DECREF(item);
Py_DECREF(iter);
return NULL;
}
Py_DECREF(item);
horizon::RuleID id;
try {
id = horizon::rule_id_lut.lookup(rule_name);
ids.emplace(id);
}
catch (...) {
PyErr_SetString(PyExc_IOError, "rule not found");
Py_DECREF(item);
Py_DECREF(iter);
return NULL;
}
}

Py_DECREF(iter);

if (PyErr_Occurred()) {
return NULL;
}
try {
auto rules_json = json_from_py(py_rules);
horizon::BoardRules rules;
rules.load_from_json(rules_json);

horizon::RulesCheckCache cache(self->board);
json j;
for (auto id : ids) {
auto r = self->board->board.rules.check(id, &self->board->board, cache, &dummy_callback);
j[horizon::rule_id_lut.lookup_reverse(id)] = r.serialize();
}
return py_from_json(j);
}
catch (const py_exception &e) {
return NULL;
}
catch (const std::exception &e) {
PyErr_SetString(PyExc_IOError, e.what());
return NULL;
}
catch (...) {
PyErr_SetString(PyExc_IOError, "unknown exception");
return NULL;
}
Py_RETURN_NONE;
}

static PyObject *PyBoard_get_rules(PyObject *pself, PyObject *args)
{
auto self = reinterpret_cast<PyBoard *>(pself);
auto rules = self->board->board.rules.serialize();
return py_from_json(rules);
}

static PyObject *PyBoard_get_rule_ids(PyObject *pself, PyObject *args)
{
auto self = reinterpret_cast<PyBoard *>(pself);
auto rules = self->board->board.rules.get_rule_ids();
auto r = PySet_New(NULL);
if (!r)
return NULL;
for (auto id : rules) {
if (horizon::rule_descriptions.at(id).can_check) {
auto u = PyUnicode_FromString(horizon::rule_id_lut.lookup_reverse(id).c_str());
if (PySet_Add(r, u) == -1) {
return NULL;
}
}
}
return r;
}

static PyMethodDef PyBoard_methods[] = {
{"get_gerber_export_settings", PyBoard_get_gerber_export_settings, METH_NOARGS,
"Return gerber export settings"},
{"export_gerber", PyBoard_export_gerber, METH_VARARGS, "Export gerber"},
{"get_pdf_export_settings", PyBoard_get_pdf_export_settings, METH_NOARGS, "Return PDF export settings"},
{"get_pnp_export_settings", PyBoard_get_pnp_export_settings, METH_NOARGS, "Return PnP export settings"},
{"get_step_export_settings", PyBoard_get_step_export_settings, METH_NOARGS, "Return STEP export settings"},
{"get_rules", PyBoard_get_rules, METH_NOARGS, "Return rules"},
{"get_rule_ids", PyBoard_get_rule_ids, METH_NOARGS, "Return rule IDs"},
{"export_pdf", PyBoard_export_pdf, METH_VARARGS, "Export PDF"},
{"export_pnp", PyBoard_export_pnp, METH_VARARGS, "Export pick and place"},
{"export_step", PyBoard_export_step, METH_VARARGS, "Export STEP"},
{"run_checks", PyBoard_run_checks, METH_VARARGS, "Run checks"},
{NULL} /* Sentinel */
};

Expand Down
16 changes: 2 additions & 14 deletions src/python_module/board.hpp
Original file line number Diff line number Diff line change
@@ -1,24 +1,12 @@
#pragma once
#include <Python.h>
#include "block/block.hpp"
#include "board/board.hpp"
#include "board/via_padstack_provider.hpp"
#include "project/project.hpp"
#include "pool/pool_cached.hpp"

extern PyTypeObject BoardType;

class BoardWrapper {
public:
BoardWrapper(const horizon::Project &prj);
horizon::PoolCached pool;
horizon::Block block;
horizon::ViaPadstackProvider vpp;
horizon::Board board;
};
class BoardWrapper *create_board_wrapper(const horizon::Project &prj);

typedef struct {
PyObject_HEAD
/* Type-specific fields go here. */
BoardWrapper *board;
class BoardWrapper *board;
} PyBoard;
4 changes: 2 additions & 2 deletions src/python_module/project.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ static PyObject *PyProject_open_board(PyObject *pself)
PyErr_SetString(PyExc_FileNotFoundError, "pool not found");
return NULL;
}
BoardWrapper *board = nullptr;
class BoardWrapper *board = nullptr;
try {
board = new BoardWrapper(self->project->project);
board = create_board_wrapper(self->project->project);
}
catch (const std::exception &e) {
PyErr_SetString(PyExc_IOError, e.what());
Expand Down

0 comments on commit e47e579

Please sign in to comment.