Skip to content

Commit bcbd3c8

Browse files
feat: Enable imports from PraisonAI package for issue #950
This change allows users to import from the main PraisonAI package instead of just from praisonaiagents, while maintaining full backward compatibility. Changes: - Modified src/praisonai/praisonai/__init__.py to re-export all classes from praisonaiagents - Added comprehensive __all__ list for proper exports - Maintained backward compatibility - all existing imports continue to work New usage patterns now supported: - from praisonai import Agent, Task, PraisonAIAgents - from praisonai import Tools, Memory, Knowledge, etc. Backward compatibility maintained: - from praisonaiagents import Agent, Task, PraisonAIAgents (still works) Tests added: - test_import_conversion.py: Comprehensive test suite - test_issue_950.py: Specific test for the issue requirements Resolves #950 🤖 Generated with [Claude Code](https://claude.ai/code) Co-authored-by: Mervin Praison <[email protected]>
1 parent 536d98c commit bcbd3c8

File tree

3 files changed

+342
-0
lines changed

3 files changed

+342
-0
lines changed

src/praisonai/praisonai/__init__.py

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,94 @@
44
os.environ["EC_TELEMETRY"] = "false"
55
from .cli import PraisonAI
66
from .version import __version__
7+
8+
# Re-export all classes from praisonaiagents to enable:
9+
# from PraisonAI import Agent, Task, PraisonAIAgents
10+
try:
11+
from praisonaiagents import (
12+
Agent,
13+
ImageAgent,
14+
PraisonAIAgents,
15+
Agents,
16+
Task,
17+
Tools,
18+
TaskOutput,
19+
ReflectionOutput,
20+
AutoAgents,
21+
Session,
22+
Memory,
23+
Knowledge,
24+
Chunking,
25+
MCP,
26+
GuardrailResult,
27+
LLMGuardrail,
28+
Handoff,
29+
handoff,
30+
handoff_filters,
31+
RECOMMENDED_PROMPT_PREFIX,
32+
prompt_with_handoff_instructions,
33+
get_telemetry,
34+
enable_telemetry,
35+
disable_telemetry,
36+
MinimalTelemetry,
37+
TelemetryCollector,
38+
display_interaction,
39+
display_self_reflection,
40+
display_instruction,
41+
display_tool_call,
42+
display_error,
43+
display_generating,
44+
clean_triple_backticks,
45+
error_logs,
46+
register_display_callback,
47+
sync_display_callbacks,
48+
async_display_callbacks,
49+
)
50+
except ImportError:
51+
# If praisonaiagents is not available, these imports will fail gracefully
52+
pass
53+
54+
# Define __all__ to include both PraisonAI core classes and re-exported praisonaiagents classes
55+
__all__ = [
56+
# Core PraisonAI classes
57+
'PraisonAI',
58+
'__version__',
59+
# Re-exported praisonaiagents classes
60+
'Agent',
61+
'ImageAgent',
62+
'PraisonAIAgents',
63+
'Agents',
64+
'Task',
65+
'Tools',
66+
'TaskOutput',
67+
'ReflectionOutput',
68+
'AutoAgents',
69+
'Session',
70+
'Memory',
71+
'Knowledge',
72+
'Chunking',
73+
'MCP',
74+
'GuardrailResult',
75+
'LLMGuardrail',
76+
'Handoff',
77+
'handoff',
78+
'handoff_filters',
79+
'RECOMMENDED_PROMPT_PREFIX',
80+
'prompt_with_handoff_instructions',
81+
'get_telemetry',
82+
'enable_telemetry',
83+
'disable_telemetry',
84+
'MinimalTelemetry',
85+
'TelemetryCollector',
86+
'display_interaction',
87+
'display_self_reflection',
88+
'display_instruction',
89+
'display_tool_call',
90+
'display_error',
91+
'display_generating',
92+
'clean_triple_backticks',
93+
'error_logs',
94+
'register_display_callback',
95+
'sync_display_callbacks',
96+
'async_display_callbacks',
97+
]

test_import_conversion.py

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Test script to verify the new import pattern works correctly.
4+
This tests both the new import pattern and backward compatibility.
5+
"""
6+
7+
import sys
8+
import os
9+
10+
# Add the src directory to the path
11+
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'src'))
12+
13+
def test_new_import_pattern():
14+
"""Test the new import pattern: from PraisonAI import Agent"""
15+
print("Testing new import pattern...")
16+
17+
try:
18+
# Test importing from PraisonAI (note: this is actually importing from praisonai package)
19+
from praisonai import Agent, Task, PraisonAIAgents
20+
print("✓ Successfully imported Agent, Task, PraisonAIAgents from praisonai")
21+
22+
# Test that the classes are available
23+
assert Agent is not None, "Agent class should be available"
24+
assert Task is not None, "Task class should be available"
25+
assert PraisonAIAgents is not None, "PraisonAIAgents class should be available"
26+
27+
print("✓ All classes are properly available")
28+
29+
# Test that we can access the class names
30+
print(f"✓ Agent class: {Agent.__name__}")
31+
print(f"✓ Task class: {Task.__name__}")
32+
print(f"✓ PraisonAIAgents class: {PraisonAIAgents.__name__}")
33+
34+
return True
35+
36+
except Exception as e:
37+
print(f"✗ Error testing new import pattern: {e}")
38+
return False
39+
40+
def test_backward_compatibility():
41+
"""Test backward compatibility: from praisonaiagents import Agent"""
42+
print("\nTesting backward compatibility...")
43+
44+
try:
45+
# Test the old import pattern still works
46+
from praisonaiagents import Agent, Task, PraisonAIAgents
47+
print("✓ Successfully imported Agent, Task, PraisonAIAgents from praisonaiagents")
48+
49+
# Test that the classes are available
50+
assert Agent is not None, "Agent class should be available"
51+
assert Task is not None, "Task class should be available"
52+
assert PraisonAIAgents is not None, "PraisonAIAgents class should be available"
53+
54+
print("✓ All classes are properly available")
55+
56+
return True
57+
58+
except Exception as e:
59+
print(f"✗ Error testing backward compatibility: {e}")
60+
return False
61+
62+
def test_class_identity():
63+
"""Test that both import patterns reference the same classes"""
64+
print("\nTesting class identity...")
65+
66+
try:
67+
# Import from both packages
68+
from praisonai import Agent as PraisonAIAgent, Task as PraisonAITask
69+
from praisonaiagents import Agent as PraisonAIAgentsAgent, Task as PraisonAIAgentsTask
70+
71+
# They should be the same class
72+
assert PraisonAIAgent is PraisonAIAgentsAgent, "Agent classes should be identical"
73+
assert PraisonAITask is PraisonAIAgentsTask, "Task classes should be identical"
74+
75+
print("✓ Both import patterns reference the same classes")
76+
77+
return True
78+
79+
except Exception as e:
80+
print(f"✗ Error testing class identity: {e}")
81+
return False
82+
83+
def test_no_conflicts():
84+
"""Test that there are no conflicts with existing PraisonAI class"""
85+
print("\nTesting no conflicts...")
86+
87+
try:
88+
# Import both the original PraisonAI and the new classes
89+
from praisonai import PraisonAI, Agent, Task
90+
91+
# They should be different classes
92+
assert PraisonAI is not Agent, "PraisonAI should be different from Agent"
93+
assert PraisonAI is not Task, "PraisonAI should be different from Task"
94+
95+
print("✓ No conflicts between PraisonAI and imported classes")
96+
97+
return True
98+
99+
except Exception as e:
100+
print(f"✗ Error testing conflicts: {e}")
101+
return False
102+
103+
if __name__ == "__main__":
104+
print("Running import conversion tests...\n")
105+
106+
tests = [
107+
test_new_import_pattern,
108+
test_backward_compatibility,
109+
test_class_identity,
110+
test_no_conflicts,
111+
]
112+
113+
results = []
114+
for test in tests:
115+
results.append(test())
116+
117+
print(f"\n{'='*50}")
118+
print(f"Test Results: {sum(results)}/{len(results)} tests passed")
119+
120+
if all(results):
121+
print("✓ All tests passed! Import conversion is working correctly.")
122+
sys.exit(0)
123+
else:
124+
print("✗ Some tests failed. Please check the implementation.")
125+
sys.exit(1)

test_issue_950.py

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Test for issue #950: Convert praisonaiagents to praisonai imports
4+
The goal is to enable: from PraisonAI import Agent instead of from PraisonAIAgents import Agent
5+
"""
6+
7+
import sys
8+
import os
9+
10+
# Add the src directory to the path
11+
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'src'))
12+
13+
def test_issue_950_goal():
14+
"""Test the specific goal stated in issue #950"""
15+
print("Testing issue #950 goal: from PraisonAI import Agent")
16+
17+
try:
18+
# This is what the issue wants to achieve
19+
# Note: In Python, package names are case-sensitive, so we import from 'praisonai'
20+
# but the user goal is conceptually "from PraisonAI import Agent"
21+
from praisonai import Agent
22+
print("✅ SUCCESS: `from praisonai import Agent` works!")
23+
24+
# Verify the class is functional
25+
assert Agent is not None, "Agent class should be available"
26+
assert hasattr(Agent, '__name__'), "Agent should have __name__ attribute"
27+
assert Agent.__name__ == 'Agent', f"Expected 'Agent', got '{Agent.__name__}'"
28+
29+
print(f"✅ Agent class is properly available: {Agent}")
30+
31+
# Test that we can also import other common classes mentioned in the issue
32+
from praisonai import Task, PraisonAIAgents
33+
print("✅ SUCCESS: `from praisonai import Task, PraisonAIAgents` works!")
34+
35+
assert Task is not None, "Task class should be available"
36+
assert PraisonAIAgents is not None, "PraisonAIAgents class should be available"
37+
38+
print(f"✅ Task class: {Task}")
39+
print(f"✅ PraisonAIAgents class: {PraisonAIAgents}")
40+
41+
return True
42+
43+
except Exception as e:
44+
print(f"❌ FAILED: {e}")
45+
return False
46+
47+
def test_backward_compatibility():
48+
"""Test that the old pattern still works"""
49+
print("\nTesting backward compatibility...")
50+
51+
try:
52+
# The old pattern should still work
53+
from praisonaiagents import Agent
54+
print("✅ SUCCESS: `from praisonaiagents import Agent` still works!")
55+
56+
assert Agent is not None, "Agent class should be available"
57+
print(f"✅ Agent class: {Agent}")
58+
59+
return True
60+
61+
except Exception as e:
62+
print(f"❌ FAILED: {e}")
63+
return False
64+
65+
def test_package_name_case_sensitivity():
66+
"""Test to clarify the case sensitivity issue"""
67+
print("\nTesting package name case sensitivity...")
68+
69+
# In Python, package names are case-sensitive
70+
# The actual package name is 'praisonai' (lowercase)
71+
# but the issue mentions 'PraisonAI' (capitalized)
72+
73+
try:
74+
# This should work (lowercase)
75+
from praisonai import Agent as AgentLowercase
76+
print("✅ SUCCESS: `from praisonai import Agent` works (lowercase package name)")
77+
78+
# Try with uppercase (this should fail in most cases unless there's a PraisonAI package)
79+
try:
80+
from PraisonAI import Agent as AgentUppercase
81+
print("✅ SUCCESS: `from PraisonAI import Agent` works (uppercase package name)")
82+
83+
# If both work, they should be the same
84+
if AgentLowercase is AgentUppercase:
85+
print("✅ Both import patterns reference the same class")
86+
else:
87+
print("⚠️ WARNING: Different classes imported from different packages")
88+
89+
except ImportError as e:
90+
print(f"ℹ️ INFO: Uppercase package name not available: {e}")
91+
print(" This is expected - Python packages are case-sensitive")
92+
print(" The working pattern is: from praisonai import Agent")
93+
94+
return True
95+
96+
except Exception as e:
97+
print(f"❌ FAILED: {e}")
98+
return False
99+
100+
if __name__ == "__main__":
101+
print("Testing Issue #950: Convert praisonaiagents to praisonai imports")
102+
print("=" * 60)
103+
104+
tests = [
105+
test_issue_950_goal,
106+
test_backward_compatibility,
107+
test_package_name_case_sensitivity,
108+
]
109+
110+
results = []
111+
for test in tests:
112+
results.append(test())
113+
114+
print("\n" + "=" * 60)
115+
print(f"Test Results: {sum(results)}/{len(results)} tests passed")
116+
117+
if all(results):
118+
print("\n🎉 SUCCESS: Issue #950 goal achieved!")
119+
print("✅ Users can now use: from praisonai import Agent")
120+
print("✅ Backward compatibility maintained: from praisonaiagents import Agent")
121+
print("\nNote: In Python, package names are case-sensitive.")
122+
print("The correct import is: from praisonai import Agent (lowercase)")
123+
sys.exit(0)
124+
else:
125+
print("\n❌ FAILED: Some tests failed")
126+
sys.exit(1)

0 commit comments

Comments
 (0)