1
/***************************************************************************
2
* Copyright (c) 2007 Jürgen Riegel <juergen.riegel@web.de> *
4
* This file is part of the FreeCAD CAx development system. *
6
* This library is free software; you can redistribute it and/or *
7
* modify it under the terms of the GNU Library General Public *
8
* License as published by the Free Software Foundation; either *
9
* version 2 of the License, or (at your option) any later version. *
11
* This library is distributed in the hope that it will be useful, *
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14
* GNU Library General Public License for more details. *
16
* You should have received a copy of the GNU Library General Public *
17
* License along with this library; see the file COPYING.LIB. If not, *
18
* write to the Free Software Foundation, Inc., 59 Temple Place, *
19
* Suite 330, Boston, MA 02111-1307, USA *
21
***************************************************************************/
24
#include "PreCompiled.h"
26
#include <Base/FileInfo.h>
27
#include <Base/Interpreter.h>
28
#include <Base/Stream.h>
31
#include "DocumentObject.h"
32
#include "DocumentObjectPy.h"
33
#include "MergeDocuments.h"
35
// inclusion of the generated files (generated By DocumentPy.xml)
36
#include "DocumentPy.h"
37
#include "DocumentPy.cpp"
38
#include <boost/regex.hpp>
39
#include <Base/PyWrapParseTupleAndKeywords.h>
44
PyObject* DocumentPy::addProperty(PyObject *args, PyObject *kwd)
46
char *sType {nullptr};
47
char *sName {nullptr};
48
char *sGroup {nullptr};
52
PyObject *ro = Py_False, *hd = Py_False;
53
PyObject* enumVals = nullptr;
54
static const std::array<const char *, 9> kwlist{"type", "name", "group", "doc", "attr",
55
"read_only", "hidden", "enum_vals", nullptr};
56
if (!Base::Wrapped_ParseTupleAndKeywords(
57
args, kwd, "ss|sethO!O!O", kwlist, &sType, &sName, &sGroup, "utf-8",
58
&sDoc, &attr, &PyBool_Type, &ro, &PyBool_Type, &hd, &enumVals)) {
67
Property *prop = getDocumentPtr()->
68
addDynamicProperty(sType,sName,sGroup,sDocStr.c_str(),attr,
69
Base::asBoolean(ro), Base::asBoolean(hd));
72
auto* propEnum = dynamic_cast<App::PropertyEnumeration*>(prop);
73
if (propEnum && enumVals) {
74
propEnum->setPyObject(enumVals);
77
return Py::new_reference_to(this);
80
PyObject* DocumentPy::removeProperty(PyObject *args)
83
if (!PyArg_ParseTuple(args, "s", &sName))
86
bool ok = getDocumentPtr()->removeDynamicProperty(sName);
87
return Py_BuildValue("O", (ok ? Py_True : Py_False));
90
// returns a string which represent the object e.g. when printed in python
91
std::string DocumentPy::representation() const
93
std::stringstream str;
94
str << "<Document object at " << getDocumentPtr() << ">";
99
PyObject* DocumentPy::save(PyObject * args)
101
if (!PyArg_ParseTuple(args, ""))
105
if (!getDocumentPtr()->save()) {
106
PyErr_SetString(PyExc_ValueError, "Object attribute 'FileName' is not set");
111
const char* filename = getDocumentPtr()->FileName.getValue();
112
Base::FileInfo fi(filename);
113
if (!fi.isReadable()) {
114
PyErr_Format(PyExc_IOError, "No such file or directory: '%s'", filename);
121
PyObject* DocumentPy::saveAs(PyObject * args)
124
if (!PyArg_ParseTuple(args, "et", "utf-8", &fn))
127
std::string utf8Name = fn;
131
getDocumentPtr()->saveAs(utf8Name.c_str());
136
PyObject* DocumentPy::saveCopy(PyObject * args)
139
if (!PyArg_ParseTuple(args, "s", &fn))
143
getDocumentPtr()->saveCopy(fn);
148
PyObject* DocumentPy::load(PyObject * args)
150
char* filename=nullptr;
151
if (!PyArg_ParseTuple(args, "s", &filename))
153
if (!filename || *filename == '\0') {
154
PyErr_Format(PyExc_ValueError, "Path is empty");
158
getDocumentPtr()->FileName.setValue(filename);
159
Base::FileInfo fi(filename);
160
if (!fi.isReadable()) {
161
PyErr_Format(PyExc_IOError, "No such file or directory: '%s'", filename);
165
getDocumentPtr()->restore();
167
PyErr_Format(PyExc_IOError, "Reading from file '%s' failed", filename);
173
PyObject* DocumentPy::restore(PyObject * args)
175
if (!PyArg_ParseTuple(args, ""))
177
const char* filename = getDocumentPtr()->FileName.getValue();
178
if (!filename || *filename == '\0') {
179
PyErr_Format(PyExc_ValueError, "Object attribute 'FileName' is not set");
182
Base::FileInfo fi(filename);
183
if (!fi.isReadable()) {
184
PyErr_Format(PyExc_IOError, "No such file or directory: '%s'", filename);
188
getDocumentPtr()->restore();
190
PyErr_Format(PyExc_IOError, "Reading from file '%s' failed", filename);
196
PyObject* DocumentPy::isSaved(PyObject* args)
198
if (!PyArg_ParseTuple(args, ""))
200
bool ok = getDocumentPtr()->isSaved();
201
return Py::new_reference_to(Py::Boolean(ok));
204
PyObject* DocumentPy::getProgramVersion(PyObject* args)
206
if (!PyArg_ParseTuple(args, ""))
208
const char* version = getDocumentPtr()->getProgramVersion();
209
return Py::new_reference_to(Py::String(version));
212
PyObject* DocumentPy::getFileName(PyObject* args)
214
if (!PyArg_ParseTuple(args, ""))
216
const char* fn = getDocumentPtr()->getFileName();
217
return Py::new_reference_to(Py::String(fn));
220
PyObject* DocumentPy::mergeProject(PyObject * args)
223
if (!PyArg_ParseTuple(args, "s", &filename))
227
Base::FileInfo fi(filename);
228
Base::ifstream str(fi, std::ios::in | std::ios::binary);
229
App::Document* doc = getDocumentPtr();
230
MergeDocuments md(doc);
231
md.importObjects(str);
236
PyObject* DocumentPy::exportGraphviz(PyObject * args)
239
if (!PyArg_ParseTuple(args, "|s",&fn))
242
Base::FileInfo fi(fn);
243
Base::ofstream str(fi);
244
getDocumentPtr()->exportGraphviz(str);
249
std::stringstream str;
250
getDocumentPtr()->exportGraphviz(str);
251
return PyUnicode_FromString(str.str().c_str());
255
PyObject* DocumentPy::addObject(PyObject *args, PyObject *kwd)
257
char *sType, *sName = nullptr, *sViewType = nullptr;
258
PyObject *obj = nullptr;
259
PyObject *view = nullptr;
260
PyObject *attach = Py_False;
261
static const std::array<const char *, 7> kwlist{"type", "name", "objProxy", "viewProxy", "attach", "viewType",
263
if (!Base::Wrapped_ParseTupleAndKeywords(args, kwd, "s|sOOO!s",
264
kwlist, &sType, &sName, &obj, &view, &PyBool_Type, &attach, &sViewType)) {
268
DocumentObject *pcFtr = nullptr;
270
if (!obj || !Base::asBoolean(attach)) {
271
pcFtr = getDocumentPtr()->addObject(sType,sName,true,sViewType);
274
Base::Type type = Base::Type::getTypeIfDerivedFrom(sType, DocumentObject::getClassTypeId(), true);
276
std::stringstream str;
277
str << "'" << sType << "' is not a document object type";
278
throw Base::TypeError(str.str());
280
pcFtr = static_cast<DocumentObject*>(type.createInstance());
282
// the type instance could be a null pointer
284
std::stringstream str;
285
str << "No document object found of type '" << sType << "'" << std::ends;
286
throw Py::TypeError(str.str());
288
// Allows to hide the handling with Proxy in client python code
291
// the python binding class to the document object
292
Py::Object pyftr = Py::asObject(pcFtr->getPyObject());
293
// 'pyobj' is the python class with the implementation for DocumentObject
294
Py::Object pyobj(obj);
295
if (pyobj.hasAttr("__object__")) {
296
pyobj.setAttr("__object__", pyftr);
298
pyftr.setAttr("Proxy", pyobj);
300
if (Base::asBoolean(attach)) {
301
getDocumentPtr()->addObject(pcFtr,sName);
304
Py::Callable method(pyobj.getAttr("attach"));
305
if (!method.isNone()) {
306
Py::TupleN arg(pyftr);
310
catch (Py::Exception&) {
316
// if a document class is set we also need a view provider defined which must be
317
// something different to None
320
pyvp = Py::Object(view);
323
// 'pyvp' is the python class with the implementation for ViewProvider
324
if (pyvp.hasAttr("__vobject__")) {
325
pyvp.setAttr("__vobject__", pyftr.getAttr("ViewObject"));
328
Py::Object pyprx(pyftr.getAttr("ViewObject"));
329
pyprx.setAttr("Proxy", pyvp);
330
return Py::new_reference_to(pyftr);
332
catch (Py::Exception& e) {
336
return pcFtr->getPyObject();
339
PyObject* DocumentPy::removeObject(PyObject *args)
342
if (!PyArg_ParseTuple(args, "s",&sName))
346
DocumentObject *pcFtr = getDocumentPtr()->getObject(sName);
348
getDocumentPtr()->removeObject( sName );
352
std::stringstream str;
353
str << "No document object found with name '" << sName << "'" << std::ends;
354
throw Py::ValueError(str.str());
358
PyObject* DocumentPy::copyObject(PyObject *args)
360
PyObject *obj, *rec=Py_False, *retAll=Py_False;
361
if (!PyArg_ParseTuple(args, "O|O!O!",&obj,&PyBool_Type,&rec,&PyBool_Type,&retAll))
364
std::vector<App::DocumentObject*> objs;
366
if (PySequence_Check(obj)) {
367
Py::Sequence seq(obj);
368
for (Py_ssize_t i=0;i<seq.size();++i) {
369
if (!PyObject_TypeCheck(seq[i].ptr(),&DocumentObjectPy::Type)) {
370
PyErr_SetString(PyExc_TypeError, "Expect element in sequence to be of type document object");
373
objs.push_back(static_cast<DocumentObjectPy*>(seq[i].ptr())->getDocumentObjectPtr());
376
else if (!PyObject_TypeCheck(obj,&DocumentObjectPy::Type)) {
377
PyErr_SetString(PyExc_TypeError,
378
"Expect first argument to be either a document object or sequence of document objects");
382
objs.push_back(static_cast<DocumentObjectPy*>(obj)->getDocumentObjectPtr());
387
auto ret = getDocumentPtr()->copyObject(objs, Base::asBoolean(rec), Base::asBoolean(retAll));
388
if (ret.size()==1 && single)
389
return ret[0]->getPyObject();
391
Py::Tuple tuple(ret.size());
392
for (size_t i=0;i<ret.size();++i)
393
tuple.setItem(i,Py::Object(ret[i]->getPyObject(),true));
394
return Py::new_reference_to(tuple);
398
PyObject* DocumentPy::importLinks(PyObject *args)
400
PyObject *obj = Py_None;
401
if (!PyArg_ParseTuple(args, "|O",&obj))
404
std::vector<App::DocumentObject*> objs;
405
if (PySequence_Check(obj)) {
406
Py::Sequence seq(obj);
407
for (Py_ssize_t i=0;i<seq.size();++i) {
408
if (!PyObject_TypeCheck(seq[i].ptr(),&DocumentObjectPy::Type)) {
409
PyErr_SetString(PyExc_TypeError, "Expect element in sequence to be of type document object");
412
objs.push_back(static_cast<DocumentObjectPy*>(seq[i].ptr())->getDocumentObjectPtr());
416
Base::PyTypeCheck(&obj, &DocumentObjectPy::Type,
417
"Expect first argument to be either a document object, sequence of document objects or None");
419
objs.push_back(static_cast<DocumentObjectPy*>(obj)->getDocumentObjectPtr());
423
objs = getDocumentPtr()->getObjects();
426
auto ret = getDocumentPtr()->importLinks(objs);
428
Py::Tuple tuple(ret.size());
429
for (size_t i=0;i<ret.size();++i)
430
tuple.setItem(i,Py::Object(ret[i]->getPyObject(),true));
431
return Py::new_reference_to(tuple);
436
PyObject* DocumentPy::moveObject(PyObject *args)
438
PyObject *obj, *rec=Py_False;
439
if (!PyArg_ParseTuple(args, "O!|O!",&(DocumentObjectPy::Type),&obj,&PyBool_Type,&rec))
442
DocumentObjectPy* docObj = static_cast<DocumentObjectPy*>(obj);
443
DocumentObject* move = getDocumentPtr()->moveObject(docObj->getDocumentObjectPtr(), Base::asBoolean(rec));
445
return move->getPyObject();
448
std::string str("Failed to move the object");
449
throw Py::ValueError(str);
453
PyObject* DocumentPy::openTransaction(PyObject *args)
455
PyObject *value = nullptr;
456
if (!PyArg_ParseTuple(args, "|O",&value))
464
else if (PyUnicode_Check(value)) {
465
cmd = PyUnicode_AsUTF8(value);
468
PyErr_SetString(PyExc_TypeError, "string or unicode expected");
472
getDocumentPtr()->openTransaction(cmd.c_str());
476
PyObject* DocumentPy::abortTransaction(PyObject * args)
478
if (!PyArg_ParseTuple(args, ""))
480
getDocumentPtr()->abortTransaction();
484
PyObject* DocumentPy::commitTransaction(PyObject * args)
486
if (!PyArg_ParseTuple(args, ""))
488
getDocumentPtr()->commitTransaction();
492
Py::Boolean DocumentPy::getHasPendingTransaction() const {
493
return {getDocumentPtr()->hasPendingTransaction()};
496
PyObject* DocumentPy::undo(PyObject * args)
498
if (!PyArg_ParseTuple(args, ""))
500
if (getDocumentPtr()->getAvailableUndos())
501
getDocumentPtr()->undo();
505
PyObject* DocumentPy::redo(PyObject * args)
507
if (!PyArg_ParseTuple(args, ""))
509
if (getDocumentPtr()->getAvailableRedos())
510
getDocumentPtr()->redo();
514
PyObject* DocumentPy::clearUndos(PyObject * args)
516
if (!PyArg_ParseTuple(args, ""))
518
getDocumentPtr()->clearUndos();
522
PyObject* DocumentPy::clearDocument(PyObject * args)
524
if (!PyArg_ParseTuple(args, ""))
526
getDocumentPtr()->clearDocument();
530
PyObject* DocumentPy::setClosable(PyObject* args)
533
if (!PyArg_ParseTuple(args, "O!", &PyBool_Type, &close))
535
getDocumentPtr()->setClosable(Base::asBoolean(close));
539
PyObject* DocumentPy::isClosable(PyObject* args)
541
if (!PyArg_ParseTuple(args, ""))
543
bool ok = getDocumentPtr()->isClosable();
544
return Py::new_reference_to(Py::Boolean(ok));
547
PyObject* DocumentPy::recompute(PyObject * args)
549
PyObject *pyobjs = Py_None;
550
PyObject *force = Py_False;
551
PyObject *checkCycle = Py_False;
552
if (!PyArg_ParseTuple(args, "|OO!O!",&pyobjs,
553
&PyBool_Type,&force,&PyBool_Type,&checkCycle))
557
std::vector<App::DocumentObject *> objs;
558
if (pyobjs!=Py_None) {
559
if (!PySequence_Check(pyobjs)) {
560
PyErr_SetString(PyExc_TypeError, "expect input of sequence of document objects");
564
Py::Sequence seq(pyobjs);
565
for (Py_ssize_t i=0;i<seq.size();++i) {
566
if (!PyObject_TypeCheck(seq[i].ptr(), &DocumentObjectPy::Type)) {
567
PyErr_SetString(PyExc_TypeError, "Expect element in sequence to be of type document object");
570
objs.push_back(static_cast<DocumentObjectPy*>(seq[i].ptr())->getDocumentObjectPtr());
575
if (Base::asBoolean(checkCycle))
576
options = Document::DepNoCycle;
578
int objectCount = getDocumentPtr()->recompute(objs, Base::asBoolean(force), nullptr, options);
580
// Document::recompute() hides possibly raised Python exceptions by its features
581
// So, check if an error is set and return null if yes
582
if (PyErr_Occurred()) {
586
return Py::new_reference_to(Py::Int(objectCount));
590
PyObject* DocumentPy::mustExecute(PyObject* args)
592
if (!PyArg_ParseTuple(args, ""))
594
bool ok = getDocumentPtr()->mustExecute();
595
return Py::new_reference_to(Py::Boolean(ok));
598
PyObject* DocumentPy::isTouched(PyObject* args)
600
if (!PyArg_ParseTuple(args, ""))
602
bool ok = getDocumentPtr()->isTouched();
603
return Py::new_reference_to(Py::Boolean(ok));
606
PyObject* DocumentPy::purgeTouched(PyObject* args)
608
if (!PyArg_ParseTuple(args, ""))
610
getDocumentPtr()->purgeTouched();
614
PyObject* DocumentPy::getObject(PyObject *args)
616
DocumentObject* obj = nullptr;
619
char* name = nullptr;
620
if (PyArg_ParseTuple(args, "s", &name)) {
621
obj = getDocumentPtr()->getObject(name);
627
if (PyArg_ParseTuple(args, "l", &id)) {
628
obj = getDocumentPtr()->getObjectByID(id);
632
PyErr_SetString(PyExc_TypeError, "a string or integer is required");
638
return obj->getPyObject();
643
PyObject* DocumentPy::getObjectsByLabel(PyObject *args)
646
if (!PyArg_ParseTuple(args, "s",&sName))
650
std::string name = sName;
651
std::vector<DocumentObject*> objs = getDocumentPtr()->getObjects();
652
for (auto obj : objs) {
653
if (name == obj->Label.getValue())
654
list.append(Py::asObject(obj->getPyObject()));
657
return Py::new_reference_to(list);
660
PyObject* DocumentPy::findObjects(PyObject *args, PyObject *kwds)
662
const char *sType = "App::DocumentObject", *sName = nullptr, *sLabel = nullptr;
663
static const std::array<const char *, 4> kwlist{"Type", "Name", "Label", nullptr};
664
if (!Base::Wrapped_ParseTupleAndKeywords(args, kwds, "|sss", kwlist, &sType, &sName, &sLabel)) {
668
Base::Type type = Base::Type::getTypeIfDerivedFrom(sType, App::DocumentObject::getClassTypeId(), true);
670
std::stringstream str;
671
str << "'" << sType << "' is not a document object type";
672
throw Base::TypeError(str.str());
675
std::vector<DocumentObject*> res;
678
res = getDocumentPtr()->findObjects(type, sName, sLabel);
680
catch (const boost::regex_error& e) {
681
PyErr_SetString(PyExc_RuntimeError, e.what());
686
PyObject* list = PyList_New((Py_ssize_t)res.size());
687
for (std::vector<DocumentObject*>::const_iterator It = res.begin();It != res.end();++It, index++)
688
PyList_SetItem(list, index, (*It)->getPyObject());
692
Py::Object DocumentPy::getActiveObject() const
694
DocumentObject *pcFtr = getDocumentPtr()->getActiveObject();
696
return Py::Object(pcFtr->getPyObject(), true);
700
PyObject* DocumentPy::supportedTypes(PyObject *args)
702
if (!PyArg_ParseTuple(args, ""))
705
std::vector<Base::Type> ary;
706
Base::Type::getAllDerivedFrom(App::DocumentObject::getClassTypeId(), ary);
708
for (const auto & it : ary)
709
res.append(Py::String(it.getName()));
710
return Py::new_reference_to(res);
713
Py::List DocumentPy::getObjects() const
715
std::vector<DocumentObject*> objs = getDocumentPtr()->getObjects();
718
for (auto obj : objs)
719
//Note: Here we must force the Py::Object to own this Python object as getPyObject() increments the counter
720
res.append(Py::Object(obj->getPyObject(), true));
725
Py::List DocumentPy::getTopologicalSortedObjects() const
727
std::vector<DocumentObject*> objs = getDocumentPtr()->topologicalSort();
730
for (auto obj : objs)
731
//Note: Here we must force the Py::Object to own this Python object as getPyObject() increments the counter
732
res.append(Py::Object(obj->getPyObject(), true));
737
Py::List DocumentPy::getRootObjects() const
739
std::vector<DocumentObject*> objs = getDocumentPtr()->getRootObjects();
742
for (auto obj : objs)
743
//Note: Here we must force the Py::Object to own this Python object as getPyObject() increments the counter
744
res.append(Py::Object(obj->getPyObject(), true));
749
Py::List DocumentPy::getRootObjectsIgnoreLinks() const
751
std::vector<App::DocumentObject*> objs = getDocumentPtr()->getRootObjectsIgnoreLinks();
754
for (auto obj : objs)
755
//Note: Here we must force the Py::Object to own this Python object as getPyObject() increments the counter
756
res.append(Py::Object(obj->getPyObject(), true));
761
Py::Int DocumentPy::getUndoMode() const
763
return Py::Int(getDocumentPtr()->getUndoMode());
766
void DocumentPy::setUndoMode(Py::Int arg)
768
getDocumentPtr()->setUndoMode(arg);
772
Py::Int DocumentPy::getUndoRedoMemSize() const
774
return Py::Int((long)getDocumentPtr()->getUndoMemSize());
777
Py::Int DocumentPy::getUndoCount() const
779
return Py::Int((long)getDocumentPtr()->getAvailableUndos());
782
Py::Int DocumentPy::getRedoCount() const
784
return Py::Int((long)getDocumentPtr()->getAvailableRedos());
787
Py::List DocumentPy::getUndoNames() const
789
std::vector<std::string> vList = getDocumentPtr()->getAvailableUndoNames();
792
for (const auto & It : vList)
793
res.append(Py::String(It));
798
Py::List DocumentPy::getRedoNames() const
800
std::vector<std::string> vList = getDocumentPtr()->getAvailableRedoNames();
803
for (const auto & It : vList)
804
res.append(Py::String(It));
809
Py::String DocumentPy::getDependencyGraph() const
811
std::stringstream out;
812
getDocumentPtr()->exportGraphviz(out);
816
Py::String DocumentPy::getName() const
818
return {getDocumentPtr()->getName()};
821
Py::Boolean DocumentPy::getRecomputesFrozen() const
823
return {getDocumentPtr()->testStatus(Document::Status::SkipRecompute)};
826
void DocumentPy::setRecomputesFrozen(Py::Boolean arg)
828
getDocumentPtr()->setStatus(Document::Status::SkipRecompute, arg.isTrue());
831
PyObject* DocumentPy::getTempFileName(PyObject *args)
834
if (!PyArg_ParseTuple(args, "O",&value))
838
if (PyUnicode_Check(value)) {
839
string = PyUnicode_AsUTF8(value);
842
std::string error = std::string("type must be a string!");
843
error += value->ob_type->tp_name;
844
throw Py::TypeError(error);
847
// search for a temp file name in the document transient directory
848
Base::FileInfo fileName(Base::FileInfo::getTempFileName
849
(string.c_str(),getDocumentPtr()->TransientDir.getValue()));
850
// delete the created file, we need only the name...
851
fileName.deleteFile();
853
PyObject *p = PyUnicode_DecodeUTF8(fileName.filePath().c_str(),fileName.filePath().size(),nullptr);
855
throw Base::UnicodeError("UTF8 conversion failure at PropertyString::getPyObject()");
860
PyObject *DocumentPy::getCustomAttributes(const char* attr) const
862
// Note: Here we want to return only a document object if its
863
// name matches 'attr'. However, it is possible to have an object
864
// with the same name as an attribute. If so, we return 0 as other-
865
// wise it wouldn't be possible to address this attribute any more.
866
// The object must then be addressed by the getObject() method directly.
867
App::Property* prop = getPropertyContainerPtr()->getPropertyByName(attr);
870
if (!this->ob_type->tp_dict) {
871
if (PyType_Ready(this->ob_type) < 0)
874
PyObject* item = PyDict_GetItemString(this->ob_type->tp_dict, attr);
877
// search for an object with this name
878
DocumentObject* obj = getDocumentPtr()->getObject(attr);
879
return (obj ? obj->getPyObject() : nullptr);
882
int DocumentPy::setCustomAttributes(const char* attr, PyObject *)
884
// Note: Here we want to return only a document object if its
885
// name matches 'attr'. However, it is possible to have an object
886
// with the same name as an attribute. If so, we return 0 as other-
887
// wise it wouldn't be possible to address this attribute any more.
888
// The object must then be addressed by the getObject() method directly.
889
App::Property* prop = getPropertyContainerPtr()->getPropertyByName(attr);
892
if (!this->ob_type->tp_dict) {
893
if (PyType_Ready(this->ob_type) < 0)
896
PyObject* item = PyDict_GetItemString(this->ob_type->tp_dict, attr);
899
DocumentObject* obj = getDocumentPtr()->getObject(attr);
902
std::stringstream str;
903
str << "'Document' object attribute '" << attr
904
<< "' must not be set this way" << std::ends;
905
PyErr_SetString(PyExc_RuntimeError, str.str().c_str());
912
PyObject* DocumentPy::getLinksTo(PyObject *args)
914
PyObject *pyobj = Py_None;
917
if (!PyArg_ParseTuple(args, "|Oih", &pyobj,&options, &count))
921
Base::PyTypeCheck(&pyobj, &DocumentObjectPy::Type, "Expect the first argument of type document object");
922
DocumentObject *obj = nullptr;
924
obj = static_cast<DocumentObjectPy*>(pyobj)->getDocumentObjectPtr();
926
std::set<DocumentObject *> links;
927
getDocumentPtr()->getLinksTo(links,obj,options,count);
928
Py::Tuple ret(links.size());
931
ret.setItem(i++,Py::Object(o->getPyObject(),true));
933
return Py::new_reference_to(ret);
938
Py::List DocumentPy::getInList() const
941
auto lists = PropertyXLink::getDocumentInList(getDocumentPtr());
942
if (lists.size()==1) {
943
for (auto doc : lists.begin()->second)
944
ret.append(Py::Object(doc->getPyObject(), true));
949
Py::List DocumentPy::getOutList() const
952
auto lists = PropertyXLink::getDocumentOutList(getDocumentPtr());
953
if (lists.size()==1) {
954
for (auto doc : lists.begin()->second)
955
ret.append(Py::Object(doc->getPyObject(), true));
960
PyObject *DocumentPy::getDependentDocuments(PyObject *args) {
961
PyObject *sort = Py_True;
962
if (!PyArg_ParseTuple(args, "|O!", &PyBool_Type, &sort))
965
auto docs = getDocumentPtr()->getDependentDocuments(Base::asBoolean(sort));
967
for (auto doc : docs)
968
ret.append(Py::Object(doc->getPyObject(), true));
969
return Py::new_reference_to(ret);
973
Py::Boolean DocumentPy::getRestoring() const
975
return {getDocumentPtr()->testStatus(Document::Status::Restoring)};
978
Py::Boolean DocumentPy::getPartial() const
980
return {getDocumentPtr()->testStatus(Document::Status::PartialDoc)};
983
Py::Boolean DocumentPy::getImporting() const
985
return {getDocumentPtr()->testStatus(Document::Status::Importing)};
988
Py::Boolean DocumentPy::getRecomputing() const
990
return {getDocumentPtr()->testStatus(Document::Status::Recomputing)};
993
Py::Boolean DocumentPy::getTransacting() const
995
return {getDocumentPtr()->isPerformingTransaction()};
998
Py::String DocumentPy::getOldLabel() const
1000
return {getDocumentPtr()->getOldLabel()};
1003
Py::Boolean DocumentPy::getTemporary() const
1005
return {getDocumentPtr()->testStatus(Document::TempDoc)};