Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Decreasing the number of dynamically shadowed bindings #233

Open
wants to merge 19 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion source/src/python/PyRosetta/rosetta.config
Original file line number Diff line number Diff line change
Expand Up @@ -659,9 +659,31 @@
-function basic::Tracer::create_impl
-function basic::MemTracer::create_impl

######
# Bad/Ambiguous Overloads of copy-constructor, see test T121_core.ResidueSelector.test_residue_selector_ctors for a test case
######
# RESIDUE SELECTORS
-function core::select::jump_selector::NotJumpSelector::NotJumpSelector(const class core::select::jump_selector::NotJumpSelector &)
-function core::select::jump_selector::AndJumpSelector::AndJumpSelector(const class core::select::jump_selector::AndJumpSelector &)
-function core::select::jump_selector::AndJumpSelector::AndJumpSelector(class std::shared_ptr< const core::select::jump_selector::JumpSelector > )
-function core::select::residue_selector::NotResidueSelector::NotResidueSelector(const class core::select::residue_selector::NotResidueSelector &)

-function core::select::residue_selector::AndResidueSelector::AndResidueSelector(const class core::select::residue_selector::AndResidueSelector &)
-function core::select::residue_selector::AndResidueSelector::AndResidueSelector(class std::shared_ptr< const core::select::residue_selector::ResidueSelector > )
-function core::select::residue_selector::RandomGlycanFoliageSelector::RandomGlycanFoliageSelector(const class core::select::residue_selector::RandomGlycanFoliageSelector &)
-function core::select::residue_selector::SymmetricalResidueSelector::SymmetricalResidueSelector(const class core::select::residue_selector::SymmetricalResidueSelector &)
-function core::select::residue_selector::SymmetricalResidueSelector::SymmetricalResidueSelector(class std::shared_ptr< const core::select::residue_selector::ResidueSelector >)
-function core::select::residue_selector::NativeSelector::NativeSelector(const class core::select::residue_selector::NativeSelector &)
-function core::select::residue_selector::SymmetricalResidueSelector::SymmetricalResidueSelector(const class core::select::residue_selector::SymmetricalResidueSelector &)
-function core::select::residue_selector::SymmetricalResidueSelector::SymmetricalResidueSelector(class std::shared_ptr< const core::select::residue_selector::ResidueSelector >)
-function core::pack::task::residue_selector::ClashBasedShellSelector::ClashBasedShellSelector(const class core::pack::task::residue_selector::ClashBasedShellSelector &)
-function core::pack::task::residue_selector::ClashBasedShellSelector::ClashBasedShellSelector(class std::shared_ptr< const core::select::residue_selector::ResidueSelector >)
# PACK DAEMON EXPRESSIONS
-function protocols::pack_daemon::ExpExpression::ExpExpression(const class protocols::pack_daemon::ExpExpression &)
-function protocols::pack_daemon::InSetExpression::InSetExpression(const class protocols::pack_daemon::InSetExpression &)
-function protocols::pack_daemon::LnExpression::LnExpression(const class protocols::pack_daemon::LnExpression &)
# NICHE CLASSES THAT JACK FEELS COMFORTABLE MASKING OUT
-class protocols::mean_field::jagged_array< protocols::mean_field::AAProb >
-class protocols::mean_field::jagged_array< protocols::mean_field::RotProb >

# problem with bool specialization? error: address of overloaded function 'swap' does not match required type 'void (core::id::DOF_ID_Map<bool> &, core::id::DOF_ID_Map<bool> &)'
-function core::id::swap
Expand Down
194 changes: 194 additions & 0 deletions source/src/python/PyRosetta/src/test/T003_ParentalShadowing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
# :noTabs=true:
# (c) Copyright Rosetta Commons Member Institutions.
# (c) This file is part of the Rosetta software suite and is made available under license.
# (c) The Rosetta software is developed by the contributing members of the Rosetta Commons.
# (c) For more information, see http://www.rosettacommons.org. Questions about this can be
# (c) addressed to University of Washington CoMotion, email: [email protected].

## @author Jack Maguire

import pyrosetta
from pyrosetta.rosetta import core, numeric, protocols, basic
import re

def verbose():
return False

class IsBad():
def __init__(self):
self.bad = False
self.count = 0
def register(self):
self.bad = True
self.count += 1

global_is_bad = IsBad()

class MyClass:
def __init__(self):
pass

class GreenListManager:
def __init__(self):
# Only add things here that are overloaded in a way that results in specification, not divergent behavior
self.greenlist_regex = [
"<class 'pyrosetta.rosetta.protocols.mean_field.jagged_array_*",
"<class 'pyrosetta.rosetta.protocols.mean_field.*",
"<class 'pyrosetta.rosetta.protocols.hbnet.HBNetScore'>$",
"<class 'pyrosetta.rosetta.core.chemical.PoseResidueTypeSet'>$",
"<class 'pyrosetta.rosetta.protocols.multistage_rosetta_scripts.cluster.metrics.*",
"<class 'pyrosetta.rosetta.protocols.evaluation.SingleValuePoseEvaluator*",
"<class 'pyrosetta.rosetta.core.pack.dunbrack.DunbrackRotamer_*",
]
def bypass(self, name):
for g in self.greenlist_regex:
if re.match( g, name ) is not None:
return True
return False

greenlist = GreenListManager()

def extract_class_signature_from_overload_line( l ):
# 1. (pose: pyrosetta.rosetta.core.pose.Pose, residue_positions: pyrosetta.rosetta.utility.vector1_bool) -> None
l = l.split("->")[0]
# 1. (pose: pyrosetta.rosetta.core.pose.Pose, residue_positions: pyrosetta.rosetta.utility.vector1_bool)
s1 = l.find("(")+1
s2 = l.rfind(")")
if s1==s2: return []
l = l[s1:s2]
#pose: pyrosetta.rosetta.core.pose.Pose, residue_positions: pyrosetta.rosetta.utility.vector1_bool
ls = [a.strip().rstrip() for a in l.split( "," )]
#['pose: pyrosetta.rosetta.core.pose.Pose', 'residue_positions: pyrosetta.rosetta.utility.vector1_bool']
ls = [ a[a.find(":")+1:].strip() for a in ls ]
#['pyrosetta.rosetta.core.pose.Pose', 'pyrosetta.rosetta.utility.vector1_bool']
ls = [ eval(a) for a in ls ]
#[<class 'pyrosetta.rosetta.core.pose.Pose'>, <class 'pyrosetta.rosetta.utility.vector1_bool'>]
# returns a list of classes
return ls

def signatures_conflict( sig1, sig2, only_enforce_distinct_parents=True ):
# if only_enforce_distinct_parents=True, we will not complain if foo(<class B>) shadows foo(<class B>), we will only complain if foo(<class B>) shadows foo(<class A>) where A is a parent of B
if len(sig1) != len(sig2): return False

if (sig1 == sig2) and only_enforce_distinct_parents: return False

for i in range(len(sig1)):
class1 = sig1[i]
class2 = sig2[i]
check12 = issubclass( class1, class2 ) and class1 is not bool
check21 = issubclass( class2, class1 ) and class2 is not bool
if not (check12 or check21):
# if neither class clashes with the other one, these two signatures are safe
return False

return True


def test_function( F, custom_name = None ):

if custom_name is None:
custom_name = str(F)

if greenlist.bypass( custom_name ):
return

failed = True
try:
F( MyClass() )
failed = False
except Exception as E:
exception_str = str(E)

assert failed, F
assert "The following argument types are supported" in exception_str or "No module named 'numpy'" in exception_str, exception_str

signatures = []
for l in exception_str.split("\n"):
if l[0:4] != " " or l[5] != ".": continue
#if "->" not in l: continue

if "*" in l:
if verbose(): print( "Skipping weird signature", l )
# like 2. pyrosetta.rosetta.core.chemical.MutableChiRecord(atm_vec: pyrosetta.rosetta.utility.vector1_void_*)
continue

if "::" in l:
if verbose(): print( "Skipping incompletely bound signature", l )
continue

if "Tuple[" in l or "Callable[" in l or "tuple[" in l:
if verbose(): print( "Skipping complicated signature (for now?)", l )
continue

try:
sig = extract_class_signature_from_overload_line( l )
except Exception as e:
if str(e).startswith("name '") and str(e).endswith("' is not defined"):
if verbose(): print( "Skipping incompletely bound signature", l, ":", str(e) )
continue
print( "ERROR" )
print( l )
print( "-----" )
print( e )
exit( 0 )
signatures.append( sig )

for i in range(len(signatures)):
for j in range(i+1,len(signatures)):
if signatures_conflict( signatures[i], signatures[j] ):
print( f"CONFLICT `{custom_name}` --- `{signatures[i]}` --- `{signatures[j]}`" )
global_is_bad.register()

def test_class( C ):
# 1. test __init__
try:
test_function( C )
except AssertionError as E:
if "No constructor defined" in str(E):
if verbose(): print( "No constructor defined for", C )
pass
else:
raise E

# 2. test functions
for cname in dir(C):
if cname.startswith("__"): continue
#if cname == "__init__": continue

cattr = getattr(C,cname)
type_str = str( type( cattr ) )
if type_str == "<class 'instancemethod'>":
try:
test_function( cattr, custom_name=f"{C}::{cname}" )
except AssertionError as e:
if "takes no arguments" in str(e):
pass
else:
raise e
elif type_str == "<class 'module'>":
print( cattr )
exit( 0 ) #testing to see if this is possible
test_module( cattr )
else:
if verbose(): print( "skipping type", type_str, "for", cname, "in", C )

def test_module( D ):
for dname in dir(D):
dattr = getattr(D,dname)
type_str = str( type( dattr ) )
if type_str == "<class 'pybind11_builtins.pybind11_type'>":
if dname.endswith( "Creator" ):
if verbose(): print( "skipping creator type", dname )
else:
test_class( dattr )
elif type_str == "<class 'builtin_function_or_method'>":
test_function( dattr )
elif type_str == "<class 'module'>":
test_module( dattr )
else:
if verbose(): print( "skipping type", type_str, "for", dname )

for module in [core, numeric, protocols, basic]:
test_module( module )
if global_is_bad.bad:
raise Exception(f"Found {global_is_bad.count} shadowing instances")