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);
74
if (enumVals && PySequence_Check(enumVals)) {
75
std::vector<std::string> enumValsAsVector;
76
for (Py_ssize_t i = 0; i < PySequence_Length(enumVals); ++i) {
77
enumValsAsVector.emplace_back(PyUnicode_AsUTF8(PySequence_GetItem(enumVals,i)));
79
propEnum->setEnums(enumValsAsVector);
83
return Py::new_reference_to(this);
86
PyObject* DocumentPy::removeProperty(PyObject *args)
89
if (!PyArg_ParseTuple(args, "s", &sName))
92
bool ok = getDocumentPtr()->removeDynamicProperty(sName);
93
return Py_BuildValue("O", (ok ? Py_True : Py_False));
96
// returns a string which represent the object e.g. when printed in python
97
std::string DocumentPy::representation() const
99
std::stringstream str;
100
str << "<Document object at " << getDocumentPtr() << ">";
105
PyObject* DocumentPy::save(PyObject * args)
107
if (!PyArg_ParseTuple(args, ""))
111
if (!getDocumentPtr()->save()) {
112
PyErr_SetString(PyExc_ValueError, "Object attribute 'FileName' is not set");
117
const char* filename = getDocumentPtr()->FileName.getValue();
118
Base::FileInfo fi(filename);
119
if (!fi.isReadable()) {
120
PyErr_Format(PyExc_IOError, "No such file or directory: '%s'", filename);
127
PyObject* DocumentPy::saveAs(PyObject * args)
130
if (!PyArg_ParseTuple(args, "et", "utf-8", &fn))
133
std::string utf8Name = fn;
137
getDocumentPtr()->saveAs(utf8Name.c_str());
142
PyObject* DocumentPy::saveCopy(PyObject * args)
145
if (!PyArg_ParseTuple(args, "s", &fn))
149
getDocumentPtr()->saveCopy(fn);
154
PyObject* DocumentPy::load(PyObject * args)
156
char* filename=nullptr;
157
if (!PyArg_ParseTuple(args, "s", &filename))
159
if (!filename || *filename == '\0') {
160
PyErr_Format(PyExc_ValueError, "Path is empty");
164
getDocumentPtr()->FileName.setValue(filename);
165
Base::FileInfo fi(filename);
166
if (!fi.isReadable()) {
167
PyErr_Format(PyExc_IOError, "No such file or directory: '%s'", filename);
171
getDocumentPtr()->restore();
173
PyErr_Format(PyExc_IOError, "Reading from file '%s' failed", filename);
179
PyObject* DocumentPy::restore(PyObject * args)
181
if (!PyArg_ParseTuple(args, ""))
183
const char* filename = getDocumentPtr()->FileName.getValue();
184
if (!filename || *filename == '\0') {
185
PyErr_Format(PyExc_ValueError, "Object attribute 'FileName' is not set");
188
Base::FileInfo fi(filename);
189
if (!fi.isReadable()) {
190
PyErr_Format(PyExc_IOError, "No such file or directory: '%s'", filename);
194
getDocumentPtr()->restore();
196
PyErr_Format(PyExc_IOError, "Reading from file '%s' failed", filename);
202
PyObject* DocumentPy::isSaved(PyObject* args)
204
if (!PyArg_ParseTuple(args, ""))
206
bool ok = getDocumentPtr()->isSaved();
207
return Py::new_reference_to(Py::Boolean(ok));
210
PyObject* DocumentPy::getProgramVersion(PyObject* args)
212
if (!PyArg_ParseTuple(args, ""))
214
const char* version = getDocumentPtr()->getProgramVersion();
215
return Py::new_reference_to(Py::String(version));
218
PyObject* DocumentPy::getFileName(PyObject* args)
220
if (!PyArg_ParseTuple(args, ""))
222
const char* fn = getDocumentPtr()->getFileName();
223
return Py::new_reference_to(Py::String(fn));
226
PyObject* DocumentPy::mergeProject(PyObject * args)
229
if (!PyArg_ParseTuple(args, "s", &filename))
233
Base::FileInfo fi(filename);
234
Base::ifstream str(fi, std::ios::in | std::ios::binary);
235
App::Document* doc = getDocumentPtr();
236
MergeDocuments md(doc);
237
md.importObjects(str);
242
PyObject* DocumentPy::exportGraphviz(PyObject * args)
245
if (!PyArg_ParseTuple(args, "|s",&fn))
248
Base::FileInfo fi(fn);
249
Base::ofstream str(fi);
250
getDocumentPtr()->exportGraphviz(str);
255
std::stringstream str;
256
getDocumentPtr()->exportGraphviz(str);
257
return PyUnicode_FromString(str.str().c_str());
261
PyObject* DocumentPy::addObject(PyObject *args, PyObject *kwd)
263
char *sType, *sName = nullptr, *sViewType = nullptr;
264
PyObject *obj = nullptr;
265
PyObject *view = nullptr;
266
PyObject *attach = Py_False;
267
static const std::array<const char *, 7> kwlist{"type", "name", "objProxy", "viewProxy", "attach", "viewType",
269
if (!Base::Wrapped_ParseTupleAndKeywords(args, kwd, "s|sOOO!s",
270
kwlist, &sType, &sName, &obj, &view, &PyBool_Type, &attach, &sViewType)) {
274
DocumentObject *pcFtr = nullptr;
276
if (!obj || !Base::asBoolean(attach)) {
277
pcFtr = getDocumentPtr()->addObject(sType,sName,true,sViewType);
280
Base::Type type = Base::Type::getTypeIfDerivedFrom(sType, DocumentObject::getClassTypeId(), true);
282
std::stringstream str;
283
str << "'" << sType << "' is not a document object type";
284
throw Base::TypeError(str.str());
286
pcFtr = static_cast<DocumentObject*>(type.createInstance());
288
// the type instance could be a null pointer
290
std::stringstream str;
291
str << "No document object found of type '" << sType << "'" << std::ends;
292
throw Py::TypeError(str.str());
294
// Allows to hide the handling with Proxy in client python code
297
// the python binding class to the document object
298
Py::Object pyftr = Py::asObject(pcFtr->getPyObject());
299
// 'pyobj' is the python class with the implementation for DocumentObject
300
Py::Object pyobj(obj);
301
if (pyobj.hasAttr("__object__")) {
302
pyobj.setAttr("__object__", pyftr);
304
pyftr.setAttr("Proxy", pyobj);
306
if (Base::asBoolean(attach)) {
307
getDocumentPtr()->addObject(pcFtr,sName);
310
Py::Callable method(pyobj.getAttr("attach"));
311
if (!method.isNone()) {
312
Py::TupleN arg(pyftr);
316
catch (Py::Exception&) {
322
// if a document class is set we also need a view provider defined which must be
323
// something different to None
326
pyvp = Py::Object(view);
329
// 'pyvp' is the python class with the implementation for ViewProvider
330
if (pyvp.hasAttr("__vobject__")) {
331
pyvp.setAttr("__vobject__", pyftr.getAttr("ViewObject"));
334
Py::Object pyprx(pyftr.getAttr("ViewObject"));
335
pyprx.setAttr("Proxy", pyvp);
336
return Py::new_reference_to(pyftr);
338
catch (Py::Exception& e) {
342
return pcFtr->getPyObject();
345
PyObject* DocumentPy::removeObject(PyObject *args)
348
if (!PyArg_ParseTuple(args, "s",&sName))
352
DocumentObject *pcFtr = getDocumentPtr()->getObject(sName);
354
getDocumentPtr()->removeObject( sName );
358
std::stringstream str;
359
str << "No document object found with name '" << sName << "'" << std::ends;
360
throw Py::ValueError(str.str());
364
PyObject* DocumentPy::copyObject(PyObject *args)
366
PyObject *obj, *rec=Py_False, *retAll=Py_False;
367
if (!PyArg_ParseTuple(args, "O|O!O!",&obj,&PyBool_Type,&rec,&PyBool_Type,&retAll))
370
std::vector<App::DocumentObject*> objs;
372
if (PySequence_Check(obj)) {
373
Py::Sequence seq(obj);
374
for (Py_ssize_t i=0;i<seq.size();++i) {
375
if (!PyObject_TypeCheck(seq[i].ptr(),&DocumentObjectPy::Type)) {
376
PyErr_SetString(PyExc_TypeError, "Expect element in sequence to be of type document object");
379
objs.push_back(static_cast<DocumentObjectPy*>(seq[i].ptr())->getDocumentObjectPtr());
382
else if (!PyObject_TypeCheck(obj,&DocumentObjectPy::Type)) {
383
PyErr_SetString(PyExc_TypeError,
384
"Expect first argument to be either a document object or sequence of document objects");
388
objs.push_back(static_cast<DocumentObjectPy*>(obj)->getDocumentObjectPtr());
393
auto ret = getDocumentPtr()->copyObject(objs, Base::asBoolean(rec), Base::asBoolean(retAll));
394
if (ret.size()==1 && single)
395
return ret[0]->getPyObject();
397
Py::Tuple tuple(ret.size());
398
for (size_t i=0;i<ret.size();++i)
399
tuple.setItem(i,Py::Object(ret[i]->getPyObject(),true));
400
return Py::new_reference_to(tuple);
404
PyObject* DocumentPy::importLinks(PyObject *args)
406
PyObject *obj = Py_None;
407
if (!PyArg_ParseTuple(args, "|O",&obj))
410
std::vector<App::DocumentObject*> objs;
411
if (PySequence_Check(obj)) {
412
Py::Sequence seq(obj);
413
for (Py_ssize_t i=0;i<seq.size();++i) {
414
if (!PyObject_TypeCheck(seq[i].ptr(),&DocumentObjectPy::Type)) {
415
PyErr_SetString(PyExc_TypeError, "Expect element in sequence to be of type document object");
418
objs.push_back(static_cast<DocumentObjectPy*>(seq[i].ptr())->getDocumentObjectPtr());
422
Base::PyTypeCheck(&obj, &DocumentObjectPy::Type,
423
"Expect first argument to be either a document object, sequence of document objects or None");
425
objs.push_back(static_cast<DocumentObjectPy*>(obj)->getDocumentObjectPtr());
429
objs = getDocumentPtr()->getObjects();
432
auto ret = getDocumentPtr()->importLinks(objs);
434
Py::Tuple tuple(ret.size());
435
for (size_t i=0;i<ret.size();++i)
436
tuple.setItem(i,Py::Object(ret[i]->getPyObject(),true));
437
return Py::new_reference_to(tuple);
442
PyObject* DocumentPy::moveObject(PyObject *args)
444
PyObject *obj, *rec=Py_False;
445
if (!PyArg_ParseTuple(args, "O!|O!",&(DocumentObjectPy::Type),&obj,&PyBool_Type,&rec))
448
DocumentObjectPy* docObj = static_cast<DocumentObjectPy*>(obj);
449
DocumentObject* move = getDocumentPtr()->moveObject(docObj->getDocumentObjectPtr(), Base::asBoolean(rec));
451
return move->getPyObject();
454
std::string str("Failed to move the object");
455
throw Py::ValueError(str);
459
PyObject* DocumentPy::openTransaction(PyObject *args)
461
PyObject *value = nullptr;
462
if (!PyArg_ParseTuple(args, "|O",&value))
470
else if (PyUnicode_Check(value)) {
471
cmd = PyUnicode_AsUTF8(value);
474
PyErr_SetString(PyExc_TypeError, "string or unicode expected");
478
getDocumentPtr()->openTransaction(cmd.c_str());
482
PyObject* DocumentPy::abortTransaction(PyObject * args)
484
if (!PyArg_ParseTuple(args, ""))
486
getDocumentPtr()->abortTransaction();
490
PyObject* DocumentPy::commitTransaction(PyObject * args)
492
if (!PyArg_ParseTuple(args, ""))
494
getDocumentPtr()->commitTransaction();
498
Py::Boolean DocumentPy::getHasPendingTransaction() const {
499
return {getDocumentPtr()->hasPendingTransaction()};
502
PyObject* DocumentPy::undo(PyObject * args)
504
if (!PyArg_ParseTuple(args, ""))
506
if (getDocumentPtr()->getAvailableUndos())
507
getDocumentPtr()->undo();
511
PyObject* DocumentPy::redo(PyObject * args)
513
if (!PyArg_ParseTuple(args, ""))
515
if (getDocumentPtr()->getAvailableRedos())
516
getDocumentPtr()->redo();
520
PyObject* DocumentPy::clearUndos(PyObject * args)
522
if (!PyArg_ParseTuple(args, ""))
524
getDocumentPtr()->clearUndos();
528
PyObject* DocumentPy::clearDocument(PyObject * args)
530
if (!PyArg_ParseTuple(args, ""))
532
getDocumentPtr()->clearDocument();
536
PyObject* DocumentPy::setClosable(PyObject* args)
539
if (!PyArg_ParseTuple(args, "O!", &PyBool_Type, &close))
541
getDocumentPtr()->setClosable(Base::asBoolean(close));
545
PyObject* DocumentPy::isClosable(PyObject* args)
547
if (!PyArg_ParseTuple(args, ""))
549
bool ok = getDocumentPtr()->isClosable();
550
return Py::new_reference_to(Py::Boolean(ok));
553
PyObject* DocumentPy::recompute(PyObject * args)
555
PyObject *pyobjs = Py_None;
556
PyObject *force = Py_False;
557
PyObject *checkCycle = Py_False;
558
if (!PyArg_ParseTuple(args, "|OO!O!",&pyobjs,
559
&PyBool_Type,&force,&PyBool_Type,&checkCycle))
563
std::vector<App::DocumentObject *> objs;
564
if (pyobjs!=Py_None) {
565
if (!PySequence_Check(pyobjs)) {
566
PyErr_SetString(PyExc_TypeError, "expect input of sequence of document objects");
570
Py::Sequence seq(pyobjs);
571
for (Py_ssize_t i=0;i<seq.size();++i) {
572
if (!PyObject_TypeCheck(seq[i].ptr(), &DocumentObjectPy::Type)) {
573
PyErr_SetString(PyExc_TypeError, "Expect element in sequence to be of type document object");
576
objs.push_back(static_cast<DocumentObjectPy*>(seq[i].ptr())->getDocumentObjectPtr());
581
if (Base::asBoolean(checkCycle))
582
options = Document::DepNoCycle;
584
int objectCount = getDocumentPtr()->recompute(objs, Base::asBoolean(force), nullptr, options);
586
// Document::recompute() hides possibly raised Python exceptions by its features
587
// So, check if an error is set and return null if yes
588
if (PyErr_Occurred()) {
592
return Py::new_reference_to(Py::Int(objectCount));
596
PyObject* DocumentPy::mustExecute(PyObject* args)
598
if (!PyArg_ParseTuple(args, ""))
600
bool ok = getDocumentPtr()->mustExecute();
601
return Py::new_reference_to(Py::Boolean(ok));
604
PyObject* DocumentPy::isTouched(PyObject* args)
606
if (!PyArg_ParseTuple(args, ""))
608
bool ok = getDocumentPtr()->isTouched();
609
return Py::new_reference_to(Py::Boolean(ok));
612
PyObject* DocumentPy::purgeTouched(PyObject* args)
614
if (!PyArg_ParseTuple(args, ""))
616
getDocumentPtr()->purgeTouched();
620
PyObject* DocumentPy::getObject(PyObject *args)
622
DocumentObject* obj = nullptr;
625
char* name = nullptr;
626
if (PyArg_ParseTuple(args, "s", &name)) {
627
obj = getDocumentPtr()->getObject(name);
633
if (PyArg_ParseTuple(args, "l", &id)) {
634
obj = getDocumentPtr()->getObjectByID(id);
638
PyErr_SetString(PyExc_TypeError, "a string or integer is required");
644
return obj->getPyObject();
649
PyObject* DocumentPy::getObjectsByLabel(PyObject *args)
652
if (!PyArg_ParseTuple(args, "s",&sName))
656
std::string name = sName;
657
std::vector<DocumentObject*> objs = getDocumentPtr()->getObjects();
658
for (auto obj : objs) {
659
if (name == obj->Label.getValue())
660
list.append(Py::asObject(obj->getPyObject()));
663
return Py::new_reference_to(list);
666
PyObject* DocumentPy::findObjects(PyObject *args, PyObject *kwds)
668
const char *sType = "App::DocumentObject", *sName = nullptr, *sLabel = nullptr;
669
static const std::array<const char *, 4> kwlist{"Type", "Name", "Label", nullptr};
670
if (!Base::Wrapped_ParseTupleAndKeywords(args, kwds, "|sss", kwlist, &sType, &sName, &sLabel)) {
674
Base::Type type = Base::Type::getTypeIfDerivedFrom(sType, App::DocumentObject::getClassTypeId(), true);
676
std::stringstream str;
677
str << "'" << sType << "' is not a document object type";
678
throw Base::TypeError(str.str());
681
std::vector<DocumentObject*> res;
684
res = getDocumentPtr()->findObjects(type, sName, sLabel);
686
catch (const boost::regex_error& e) {
687
PyErr_SetString(PyExc_RuntimeError, e.what());
692
PyObject* list = PyList_New((Py_ssize_t)res.size());
693
for (std::vector<DocumentObject*>::const_iterator It = res.begin();It != res.end();++It, index++)
694
PyList_SetItem(list, index, (*It)->getPyObject());
698
Py::Object DocumentPy::getActiveObject() const
700
DocumentObject *pcFtr = getDocumentPtr()->getActiveObject();
702
return Py::Object(pcFtr->getPyObject(), true);
706
PyObject* DocumentPy::supportedTypes(PyObject *args)
708
if (!PyArg_ParseTuple(args, ""))
711
std::vector<Base::Type> ary;
712
Base::Type::getAllDerivedFrom(App::DocumentObject::getClassTypeId(), ary);
714
for (const auto & it : ary)
715
res.append(Py::String(it.getName()));
716
return Py::new_reference_to(res);
719
Py::List DocumentPy::getObjects() const
721
std::vector<DocumentObject*> objs = getDocumentPtr()->getObjects();
724
for (auto obj : objs)
725
//Note: Here we must force the Py::Object to own this Python object as getPyObject() increments the counter
726
res.append(Py::Object(obj->getPyObject(), true));
731
Py::List DocumentPy::getTopologicalSortedObjects() const
733
std::vector<DocumentObject*> objs = getDocumentPtr()->topologicalSort();
736
for (auto obj : objs)
737
//Note: Here we must force the Py::Object to own this Python object as getPyObject() increments the counter
738
res.append(Py::Object(obj->getPyObject(), true));
743
Py::List DocumentPy::getRootObjects() const
745
std::vector<DocumentObject*> objs = getDocumentPtr()->getRootObjects();
748
for (auto obj : objs)
749
//Note: Here we must force the Py::Object to own this Python object as getPyObject() increments the counter
750
res.append(Py::Object(obj->getPyObject(), true));
755
Py::Int DocumentPy::getUndoMode() const
757
return Py::Int(getDocumentPtr()->getUndoMode());
760
void DocumentPy::setUndoMode(Py::Int arg)
762
getDocumentPtr()->setUndoMode(arg);
766
Py::Int DocumentPy::getUndoRedoMemSize() const
768
return Py::Int((long)getDocumentPtr()->getUndoMemSize());
771
Py::Int DocumentPy::getUndoCount() const
773
return Py::Int((long)getDocumentPtr()->getAvailableUndos());
776
Py::Int DocumentPy::getRedoCount() const
778
return Py::Int((long)getDocumentPtr()->getAvailableRedos());
781
Py::List DocumentPy::getUndoNames() const
783
std::vector<std::string> vList = getDocumentPtr()->getAvailableUndoNames();
786
for (const auto & It : vList)
787
res.append(Py::String(It));
792
Py::List DocumentPy::getRedoNames() const
794
std::vector<std::string> vList = getDocumentPtr()->getAvailableRedoNames();
797
for (const auto & It : vList)
798
res.append(Py::String(It));
803
Py::String DocumentPy::getDependencyGraph() const
805
std::stringstream out;
806
getDocumentPtr()->exportGraphviz(out);
810
Py::String DocumentPy::getName() const
812
return {getDocumentPtr()->getName()};
815
Py::Boolean DocumentPy::getRecomputesFrozen() const
817
return {getDocumentPtr()->testStatus(Document::Status::SkipRecompute)};
820
void DocumentPy::setRecomputesFrozen(Py::Boolean arg)
822
getDocumentPtr()->setStatus(Document::Status::SkipRecompute, arg.isTrue());
825
PyObject* DocumentPy::getTempFileName(PyObject *args)
828
if (!PyArg_ParseTuple(args, "O",&value))
832
if (PyUnicode_Check(value)) {
833
string = PyUnicode_AsUTF8(value);
836
std::string error = std::string("type must be a string!");
837
error += value->ob_type->tp_name;
838
throw Py::TypeError(error);
841
// search for a temp file name in the document transient directory
842
Base::FileInfo fileName(Base::FileInfo::getTempFileName
843
(string.c_str(),getDocumentPtr()->TransientDir.getValue()));
844
// delete the created file, we need only the name...
845
fileName.deleteFile();
847
PyObject *p = PyUnicode_DecodeUTF8(fileName.filePath().c_str(),fileName.filePath().size(),nullptr);
849
throw Base::UnicodeError("UTF8 conversion failure at PropertyString::getPyObject()");
854
PyObject *DocumentPy::getCustomAttributes(const char* attr) const
856
// Note: Here we want to return only a document object if its
857
// name matches 'attr'. However, it is possible to have an object
858
// with the same name as an attribute. If so, we return 0 as other-
859
// wise it wouldn't be possible to address this attribute any more.
860
// The object must then be addressed by the getObject() method directly.
861
App::Property* prop = getPropertyContainerPtr()->getPropertyByName(attr);
864
if (!this->ob_type->tp_dict) {
865
if (PyType_Ready(this->ob_type) < 0)
868
PyObject* item = PyDict_GetItemString(this->ob_type->tp_dict, attr);
871
// search for an object with this name
872
DocumentObject* obj = getDocumentPtr()->getObject(attr);
873
return (obj ? obj->getPyObject() : nullptr);
876
int DocumentPy::setCustomAttributes(const char* attr, PyObject *)
878
// Note: Here we want to return only a document object if its
879
// name matches 'attr'. However, it is possible to have an object
880
// with the same name as an attribute. If so, we return 0 as other-
881
// wise it wouldn't be possible to address this attribute any more.
882
// The object must then be addressed by the getObject() method directly.
883
App::Property* prop = getPropertyContainerPtr()->getPropertyByName(attr);
886
if (!this->ob_type->tp_dict) {
887
if (PyType_Ready(this->ob_type) < 0)
890
PyObject* item = PyDict_GetItemString(this->ob_type->tp_dict, attr);
893
DocumentObject* obj = getDocumentPtr()->getObject(attr);
896
std::stringstream str;
897
str << "'Document' object attribute '" << attr
898
<< "' must not be set this way" << std::ends;
899
PyErr_SetString(PyExc_RuntimeError, str.str().c_str());
906
PyObject* DocumentPy::getLinksTo(PyObject *args)
908
PyObject *pyobj = Py_None;
911
if (!PyArg_ParseTuple(args, "|Oih", &pyobj,&options, &count))
915
Base::PyTypeCheck(&pyobj, &DocumentObjectPy::Type, "Expect the first argument of type document object");
916
DocumentObject *obj = nullptr;
918
obj = static_cast<DocumentObjectPy*>(pyobj)->getDocumentObjectPtr();
920
std::set<DocumentObject *> links;
921
getDocumentPtr()->getLinksTo(links,obj,options,count);
922
Py::Tuple ret(links.size());
925
ret.setItem(i++,Py::Object(o->getPyObject(),true));
927
return Py::new_reference_to(ret);
932
Py::List DocumentPy::getInList() const
935
auto lists = PropertyXLink::getDocumentInList(getDocumentPtr());
936
if (lists.size()==1) {
937
for (auto doc : lists.begin()->second)
938
ret.append(Py::Object(doc->getPyObject(), true));
943
Py::List DocumentPy::getOutList() const
946
auto lists = PropertyXLink::getDocumentOutList(getDocumentPtr());
947
if (lists.size()==1) {
948
for (auto doc : lists.begin()->second)
949
ret.append(Py::Object(doc->getPyObject(), true));
954
PyObject *DocumentPy::getDependentDocuments(PyObject *args) {
955
PyObject *sort = Py_True;
956
if (!PyArg_ParseTuple(args, "|O!", &PyBool_Type, &sort))
959
auto docs = getDocumentPtr()->getDependentDocuments(Base::asBoolean(sort));
961
for (auto doc : docs)
962
ret.append(Py::Object(doc->getPyObject(), true));
963
return Py::new_reference_to(ret);
967
Py::Boolean DocumentPy::getRestoring() const
969
return {getDocumentPtr()->testStatus(Document::Status::Restoring)};
972
Py::Boolean DocumentPy::getPartial() const
974
return {getDocumentPtr()->testStatus(Document::Status::PartialDoc)};
977
Py::Boolean DocumentPy::getImporting() const
979
return {getDocumentPtr()->testStatus(Document::Status::Importing)};
982
Py::Boolean DocumentPy::getRecomputing() const
984
return {getDocumentPtr()->testStatus(Document::Status::Recomputing)};
987
Py::Boolean DocumentPy::getTransacting() const
989
return {getDocumentPtr()->isPerformingTransaction()};
992
Py::String DocumentPy::getOldLabel() const
994
return {getDocumentPtr()->getOldLabel()};
997
Py::Boolean DocumentPy::getTemporary() const
999
return {getDocumentPtr()->testStatus(Document::TempDoc)};