diff --git a/src/Mod/Path/App/TooltablePy.xml b/src/Mod/Path/App/TooltablePy.xml index 6433a3b9d7..8de47b88f3 100644 --- a/src/Mod/Path/App/TooltablePy.xml +++ b/src/Mod/Path/App/TooltablePy.xml @@ -52,5 +52,15 @@ deletes the tool found at the given position + + + setFromTemplate(dict) ... restores receiver from given template attribute dictionary + + + + + templateAttrs() ... returns a dictionary representing the receivers attributes for a template + + diff --git a/src/Mod/Path/App/TooltablePyImp.cpp b/src/Mod/Path/App/TooltablePyImp.cpp index 5e8f098625..56cd60f1f9 100644 --- a/src/Mod/Path/App/TooltablePyImp.cpp +++ b/src/Mod/Path/App/TooltablePyImp.cpp @@ -71,8 +71,11 @@ int ToolPy::PyInit(PyObject* args, PyObject* kwd) static char *kwlist[] = {"name", "tooltype", "material", "diameter", "lengthOffset", "flatRadius", "cornerRadius", "cuttingEdgeAngle", "cuttingEdgeHeight" ,NULL}; PyObject *dict = 0; - if (!kwd && PyArg_ParseTuple(args, "O!", &PyDict_Type, &dict)) { - PyObject *arg = PyTuple_New(0); + if (!kwd && (PyObject_TypeCheck(args, &PyDict_Type) || PyArg_ParseTuple(args, "O!", &PyDict_Type, &dict))) { + static PyObject *arg = PyTuple_New(0); + if (PyObject_TypeCheck(args, &PyDict_Type)) { + dict = args; + } if (!PyArg_ParseTupleAndKeywords(arg, dict, "|sssOOOOOO", kwlist, &name, &type, &mat, &dia, &len, &fla, &cor, &ang, &hei)) { return -1; } @@ -321,13 +324,19 @@ PyObject* ToolPy::setFromTemplate(PyObject * args) #if PY_MAJOR_VERSION >= 3 # define PYSTRING_FROMSTRING(str) PyUnicode_FromString(str) +# define PYINT_TYPE PyLong_Type +# define PYINT_FROMLONG(l) PyLong_FromLong(l) +# define PYINT_ASLONG(o) PyLong_AsLong(o) #else # define PYSTRING_FROMSTRING(str) PyString_FromString(str) +# define PYINT_TYPE PyInt_Type +# define PYINT_FROMLONG(l) PyInt_FromLong(l) +# define PYINT_ASLONG(o) PyInt_AsLong(o) #endif PyObject* ToolPy::templateAttrs(PyObject * args) { - if (PyArg_ParseTuple(args, "")) { + if (!args || PyArg_ParseTuple(args, "")) { PyObject *dict = PyDict_New(); PyDict_SetItemString(dict, "name", PYSTRING_FROMSTRING(getToolPtr()->Name.c_str())); PyDict_SetItemString(dict, "tooltype",PYSTRING_FROMSTRING(Tool::TypeName(getToolPtr()->Type))); @@ -373,24 +382,12 @@ int TooltablePy::PyInit(PyObject* args, PyObject* /*kwd*/) PyObject *pcObj; if (PyArg_ParseTuple(args, "O!", &(PyDict_Type), &pcObj)) { - PyObject *key, *value; - Py_ssize_t pos = 0; - while (PyDict_Next(pcObj, &pos, &key, &value)) { -#if PY_MAJOR_VERSION >= 3 - if ( !PyObject_TypeCheck(key,&(PyLong_Type)) || !PyObject_TypeCheck(value,&(Path::ToolPy::Type)) ) { -#else - if ( !PyObject_TypeCheck(key,&(PyInt_Type)) || !PyObject_TypeCheck(value,&(Path::ToolPy::Type)) ) { -#endif - PyErr_SetString(PyExc_TypeError, "The dictionary can only contain int:tool pairs"); - return -1; - } -#if PY_MAJOR_VERSION >= 3 - int ckey = (int)PyLong_AsLong(key); -#else - int ckey = (int)PyInt_AsLong(key); -#endif - Path::Tool &tool = *static_cast(value)->getToolPtr(); - getTooltablePtr()->setTool(tool,ckey); + try { + Py::Dict dict(pcObj); + setTools(dict); + } catch(...) { + PyErr_SetString(PyExc_TypeError, "The dictionary can only contain int:tool pairs"); + return -1; } return 0; } @@ -418,11 +415,7 @@ Py::Dict TooltablePy::getTools(void) const PyObject *dict = PyDict_New(); for(std::map::iterator i = getTooltablePtr()->Tools.begin(); i != getTooltablePtr()->Tools.end(); ++i) { PyObject *tool = new Path::ToolPy(i->second); -#if PY_MAJOR_VERSION >= 3 - PyDict_SetItem(dict,PyLong_FromLong(i->first),tool); -#else - PyDict_SetItem(dict,PyInt_FromLong(i->first),tool); -#endif + PyDict_SetItem(dict,PYINT_FROMLONG(i->first),tool); } return Py::Dict(dict); } @@ -434,15 +427,21 @@ void TooltablePy::setTools(Py::Dict arg) PyObject *key, *value; Py_ssize_t pos = 0; while (PyDict_Next(dict_copy, &pos, &key, &value)) { -#if PY_MAJOR_VERSION >= 3 - if ( PyObject_TypeCheck(key,&(PyLong_Type)) && (PyObject_TypeCheck(value,&(Path::ToolPy::Type))) ) { - int ckey = (int)PyLong_AsLong(key); -#else - if ( PyObject_TypeCheck(key,&(PyInt_Type)) && (PyObject_TypeCheck(value,&(Path::ToolPy::Type))) ) { - int ckey = (int)PyInt_AsLong(key); -#endif - Path::Tool &tool = *static_cast(value)->getToolPtr(); - getTooltablePtr()->setTool(tool,ckey); + if ( PyObject_TypeCheck(key,&(PYINT_TYPE)) && ((PyObject_TypeCheck(value, &(Path::ToolPy::Type))) || PyObject_TypeCheck(value, &PyDict_Type))) { + int ckey = (int)PYINT_ASLONG(key); + if (PyObject_TypeCheck(value, &(Path::ToolPy::Type))) { + Path::Tool &tool = *static_cast(value)->getToolPtr(); + getTooltablePtr()->setTool(tool, ckey); + } else { + PyErr_Clear(); + Path::Tool *tool = new Path::Tool; + Path::ToolPy pyTool(tool); + if (!pyTool.setFromTemplate(value)) { + PyErr_Print(); + throw Py::Exception("something went wrong"); + } + getTooltablePtr()->setTool(*tool, ckey); + } } else { throw Py::Exception("The dictionary can only contain int:tool pairs"); } @@ -542,3 +541,27 @@ int TooltablePy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/) } +PyObject* TooltablePy::setFromTemplate(PyObject * args) +{ + PyObject *dict = 0; + if (PyArg_ParseTuple(args, "O!", &PyDict_Type, &dict)) { + Py::Dict d(dict); + setTools(d); + Py_Return ; + } + + PyErr_SetString(PyExc_TypeError, "argument must be a dictionary returned from templateAttrs()"); + return 0; +} + +PyObject* TooltablePy::templateAttrs(PyObject * args) +{ + (void)args; + PyObject *dict = PyDict_New(); + for(std::map::iterator i = getTooltablePtr()->Tools.begin(); i != getTooltablePtr()->Tools.end(); ++i) { + Path::ToolPy tool(new Path::Tool(*i->second)); + PyObject *attrs = tool.templateAttrs(0); + PyDict_SetItem(dict, PYINT_FROMLONG(i->first), attrs); + } + return dict; +} diff --git a/src/Mod/Path/CMakeLists.txt b/src/Mod/Path/CMakeLists.txt index 40653a547e..e3183b1f20 100644 --- a/src/Mod/Path/CMakeLists.txt +++ b/src/Mod/Path/CMakeLists.txt @@ -121,6 +121,7 @@ SET(PathTests_SRCS PathTests/TestPathPost.py PathTests/TestPathStock.py PathTests/TestPathTool.py + PathTests/TestPathTooltable.py PathTests/TestPathUtil.py ) diff --git a/src/Mod/Path/PathTests/TestPathTooltable.py b/src/Mod/Path/PathTests/TestPathTooltable.py new file mode 100644 index 0000000000..dbde438e09 --- /dev/null +++ b/src/Mod/Path/PathTests/TestPathTooltable.py @@ -0,0 +1,73 @@ +# -*- coding: utf-8 -*- + +# *************************************************************************** +# * * +# * Copyright (c) 2017 sliptonic * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU Lesser General Public License (LGPL) * +# * as published by the Free Software Foundation; either version 2 of * +# * the License, or (at your option) any later version. * +# * for detail see the LICENCE text file. * +# * * +# * 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 Library General Public License for more details. * +# * * +# * You should have received a copy of the GNU Library General Public * +# * License along with this program; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# *************************************************************************** + +import FreeCAD +import Path + +from PathTests.PathTestUtils import PathTestBase + +class TestPathTooltable(PathTestBase): + + def test00(self): + '''Verify templateAttrs''' + + t = Path.Tool(name='t', diameter=1.2) + u = Path.Tool(name='u', diameter=3.4) + v = Path.Tool(name='v', diameter=5.6) + + tt = Path.Tooltable() + tt.setTool(3, t) + tt.setTool(1, u) + tt.addTools(v) + + attrs = tt.templateAttrs() + self.assertEqual(3, len(attrs)) + self.assertTrue(1 in attrs) + self.assertFalse(2 in attrs) + self.assertTrue(3 in attrs) + self.assertTrue(4 in attrs) + + self.assertEqual(attrs[1]['name'], 'u') + self.assertEqual(attrs[1]['diameter'], 3.4) + self.assertEqual(attrs[3]['name'], 't') + self.assertEqual(attrs[3]['diameter'], 1.2) + self.assertEqual(attrs[4]['name'], 'v') + self.assertEqual(attrs[4]['diameter'], 5.6) + return tt + + def test01(self): + '''Verify setFromTemplate roundtrip.''' + tt = self.test00() + uu = Path.Tooltable() + uu.setFromTemplate(tt.templateAttrs()) + + self.assertEqual(tt.Content, uu.Content) + + + def test02(self): + '''Verify template constructor.''' + tt = self.test00() + uu = Path.Tooltable(tt.templateAttrs()) + self.assertEqual(tt.Content, uu.Content) + diff --git a/src/Mod/Path/TestPathApp.py b/src/Mod/Path/TestPathApp.py index b7a6b94762..0add394bdc 100644 --- a/src/Mod/Path/TestPathApp.py +++ b/src/Mod/Path/TestPathApp.py @@ -34,3 +34,4 @@ from PathTests.TestPathDressupHoldingTags import TestHoldingTags from PathTests.TestPathDressupDogbone import TestDressupDogbone from PathTests.TestPathStock import TestPathStock from PathTests.TestPathTool import TestPathTool +from PathTests.TestPathTooltable import TestPathTooltable