diff --git a/src/crewai/project/crew_base.py b/src/crewai/project/crew_base.py index 53d3d5f3c..b5c93240b 100644 --- a/src/crewai/project/crew_base.py +++ b/src/crewai/project/crew_base.py @@ -29,7 +29,16 @@ def CrewBase(cls: T) -> T: ) original_tasks_config_path = getattr(cls, "tasks_config", "config/tasks.yaml") + # Initialize empty agents and tasks lists for linting purposes + # These will be populated by the @crew decorator when the crew method is called + _agents = [] + _tasks = [] + def __init__(self, *args, **kwargs): + # Initialize agents and tasks before anything else + self._agents = [] + self._tasks = [] + super().__init__(*args, **kwargs) self.load_configurations() self.map_all_agent_variables() @@ -249,6 +258,32 @@ def CrewBase(cls: T) -> T: self.tasks_config[task_name]["callbacks"] = [ callback_functions[callback]() for callback in callbacks ] + + @property + def agents(self): + """ + Returns the list of agents for this crew. + This property is populated by the @crew decorator when the crew method is called. + """ + return self._agents + + @agents.setter + def agents(self, value): + """Sets the list of agents for this crew.""" + self._agents = value + + @property + def tasks(self): + """ + Returns the list of tasks for this crew. + This property is populated by the @crew decorator when the crew method is called. + """ + return self._tasks + + @tasks.setter + def tasks(self, value): + """Sets the list of tasks for this crew.""" + self._tasks = value # Include base class (qual)name in the wrapper class (qual)name. WrappedClass.__name__ = CrewBase.__name__ + "(" + cls.__name__ + ")" diff --git a/tests/test_crewbase_linting.py b/tests/test_crewbase_linting.py new file mode 100644 index 000000000..c6df9d91f --- /dev/null +++ b/tests/test_crewbase_linting.py @@ -0,0 +1,53 @@ +import pytest +from crewai import Agent, Crew, Task, Process +from crewai.project import CrewBase, agent, task, crew + + +@CrewBase +class TestCrewBaseLinting: + """Test class for verifying that CrewBase doesn't cause linting errors.""" + + # Override config paths to avoid loading non-existent files + agents_config = {} + tasks_config = {} + + @agent + def agent_one(self) -> Agent: + return Agent( + role="Test Agent", + goal="Test Goal", + backstory="Test Backstory" + ) + + @task + def task_one(self) -> Task: + # Create a task with an agent assigned to it + return Task( + description="Test Description", + expected_output="Test Output", + agent=self.agent_one() # Assign the agent to the task + ) + + @crew + def crew(self) -> Crew: + # Access self.agents and self.tasks to verify no linting errors + return Crew( + agents=self.agents, # Should not cause linting errors + tasks=self.tasks, # Should not cause linting errors + process=Process.sequential, + verbose=True, + ) + + +def test_crewbase_linting(): + """Test that CrewBase doesn't cause linting errors.""" + crew_instance = TestCrewBaseLinting() + crew_obj = crew_instance.crew() + + # Verify that agents and tasks are accessible + assert len(crew_instance.agents) > 0 + assert len(crew_instance.tasks) > 0 + + # Verify that the crew object was created correctly + assert crew_obj is not None + assert isinstance(crew_obj, Crew)