@@ -1648,6 +1648,16 @@ write_module_class(ostream &out, Object *obj) {
1648
1648
1649
1649
if (!func->_has_this ) {
1650
1650
flags += " | METH_STATIC" ;
1651
+
1652
+ // Skip adding this entry if we also have a property with the same name.
1653
+ // In that case, we will use a Dtool_StaticProperty to disambiguate
1654
+ // access to this method. See GitHub issue #444.
1655
+ for (const Property *property : obj->_properties ) {
1656
+ if (property->_has_this &&
1657
+ property->_ielement .get_name () == func->_ifunc .get_name ()) {
1658
+ continue ;
1659
+ }
1660
+ }
1651
1661
}
1652
1662
1653
1663
bool has_nonslotted = false ;
@@ -2665,6 +2675,14 @@ write_module_class(ostream &out, Object *obj) {
2665
2675
continue ;
2666
2676
}
2667
2677
2678
+ // Actually, if we have a conflicting static method with the same name,
2679
+ // we will need to use Dtool_StaticProperty instead.
2680
+ for (const Function *func : obj->_methods ) {
2681
+ if (!func->_has_this && func->_ifunc .get_name () == ielem.get_name ()) {
2682
+ continue ;
2683
+ }
2684
+ }
2685
+
2668
2686
if (num_getset == 0 ) {
2669
2687
out << " static PyGetSetDef Dtool_Properties_" << ClassName << " [] = {\n " ;
2670
2688
}
@@ -3240,9 +3258,23 @@ write_module_class(ostream &out, Object *obj) {
3240
3258
// Also add the static properties, which can't be added via getset.
3241
3259
for (Property *property : obj->_properties ) {
3242
3260
const InterrogateElement &ielem = property->_ielement ;
3243
- if (property->_has_this || property-> _getter_remaps .empty ()) {
3261
+ if (property->_getter_remaps .empty ()) {
3244
3262
continue ;
3245
3263
}
3264
+ if (property->_has_this ) {
3265
+ // Actually, continue if we have a conflicting static method with the
3266
+ // same name, which may still require use of Dtool_StaticProperty.
3267
+ bool have_shadow = false ;
3268
+ for (const Function *func : obj->_methods ) {
3269
+ if (!func->_has_this && func->_ifunc .get_name () == ielem.get_name ()) {
3270
+ have_shadow = true ;
3271
+ break ;
3272
+ }
3273
+ }
3274
+ if (!have_shadow) {
3275
+ continue ;
3276
+ }
3277
+ }
3246
3278
3247
3279
string name1 = methodNameFromCppName (ielem.get_name (), " " , false );
3248
3280
// string name2 = methodNameFromCppName(ielem.get_name(), "", true);
@@ -6896,8 +6928,42 @@ write_getset(ostream &out, Object *obj, Property *property) {
6896
6928
6897
6929
// Now write the actual getter wrapper. It will be a different wrapper
6898
6930
// depending on whether it's a mapping or a sequence.
6931
+ out << " static PyObject *Dtool_" + ClassName + " _" + ielem.get_name () + " _Getter(PyObject *self, void *) {\n " ;
6932
+
6933
+ // Is this property shadowing a static method with the same name? This is a
6934
+ // special case to handle WindowProperties::make -- see GH #444.
6935
+ if (property->_has_this ) {
6936
+ for (const Function *func : obj->_methods ) {
6937
+ if (!func->_has_this && func->_ifunc .get_name () == ielem.get_name ()) {
6938
+ string flags;
6939
+ string fptr = " &" + func->_name ;
6940
+ switch (func->_args_type ) {
6941
+ case AT_keyword_args:
6942
+ flags = " METH_VARARGS | METH_KEYWORDS" ;
6943
+ fptr = " (PyCFunction) " + fptr;
6944
+ break ;
6945
+ case AT_varargs:
6946
+ flags = " METH_VARARGS" ;
6947
+ break ;
6948
+ case AT_single_arg:
6949
+ flags = " METH_O" ;
6950
+ break ;
6951
+ default :
6952
+ flags = " METH_NOARGS" ;
6953
+ break ;
6954
+ }
6955
+ out << " if (self == nullptr) {\n "
6956
+ << " static PyMethodDef def = {\" " << ielem.get_name () << " \" , "
6957
+ << fptr << " , " << flags << " | METH_STATIC, (const char *)"
6958
+ << func->_name << " _comment};\n "
6959
+ << " return PyCFunction_New(&def, nullptr);\n "
6960
+ << " }\n\n " ;
6961
+ break ;
6962
+ }
6963
+ }
6964
+ }
6965
+
6899
6966
if (ielem.is_mapping ()) {
6900
- out << " static PyObject *Dtool_" + ClassName + " _" + ielem.get_name () + " _Getter(PyObject *self, void *) {\n " ;
6901
6967
if (property->_has_this ) {
6902
6968
out << " nassertr(self != nullptr, nullptr);\n " ;
6903
6969
}
@@ -6924,7 +6990,6 @@ write_getset(ostream &out, Object *obj, Property *property) {
6924
6990
" }\n\n " ;
6925
6991
6926
6992
} else if (ielem.is_sequence ()) {
6927
- out << " static PyObject *Dtool_" + ClassName + " _" + ielem.get_name () + " _Getter(PyObject *self, void *) {\n " ;
6928
6993
if (property->_has_this ) {
6929
6994
out << " nassertr(self != nullptr, nullptr);\n " ;
6930
6995
}
@@ -6955,7 +7020,6 @@ write_getset(ostream &out, Object *obj, Property *property) {
6955
7020
6956
7021
} else {
6957
7022
// Write out a regular, unwrapped getter.
6958
- out << " static PyObject *Dtool_" + ClassName + " _" + ielem.get_name () + " _Getter(PyObject *self, void *) {\n " ;
6959
7023
FunctionRemap *remap = property->_getter_remaps .front ();
6960
7024
6961
7025
if (remap->_has_this ) {
0 commit comments