Skip to content

Commit b0821c2

Browse files
authored
Merge pull request JdeRobot#3637 from Kunal-Somani/docs/fix-typo-and-improve-backend-documentation
docs(academy): fix typo in InvalidPath and improve documentation across backend modules
2 parents 1b03762 + 42dd268 commit b0821c2

4 files changed

Lines changed: 98 additions & 9 deletions

File tree

academy/exceptions.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ class InvalidPath(Exception):
22
"""Exception raised when a path is not valid."""
33

44
def __init__(self, msg):
5-
self.message = f"Pat: {msg} is invalid."
5+
self.message = f"Path: {msg} is invalid."
66
super().__init__(self.message)
77
self.error_code = 403
88

academy/file_access.py

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,47 +13,63 @@
1313

1414

1515
class FAL(ABC):
16-
"""File Abstraction Layer"""
16+
"""
17+
Abstract base class defining the File Abstraction Layer (FAL) interface.
18+
19+
Provides a unified API for file and directory operations used by
20+
RoboticsAcademy exercises. Concrete implementations handle different
21+
storage backends (local filesystem, remote, etc.).
22+
"""
1723

1824
def __init__(self, academy="", helper=""):
1925
self.academy = academy
2026
self.helper = helper
2127
self.user = None
2228

2329
def set_user(self, user):
30+
"""Set the current user context for file operations."""
2431
self.user = user
2532

2633
@abstractmethod
2734
def academy_path(self) -> str:
35+
"""Return the root path for all academy exercise files."""
2836
pass
2937

3038
def exercise_path(self, exercise_id) -> str:
39+
"""Return the full path for a specific exercise directory."""
3140
return self.path_join(self.academy_path(), exercise_id)
3241

3342
def helpers_path(self, exercise_id) -> str:
43+
"""Return the path to the helpers directory for an exercise."""
3444
return self.path_join(self.helper, exercise_id)
3545

3646
def exercise_helper_path(self, project_id, language) -> str:
47+
"""Return the path to the language-specific template directory for an exercise."""
3748
return self.path_join(self.helpers_path(project_id), f"{language}_template/")
3849

3950
@abstractmethod
4051
def path_join(self, a: str, b: str) -> str:
52+
"""Join two path components and return the result."""
4153
pass
4254

4355
@abstractmethod
4456
def exists(self, path: str) -> bool:
57+
"""Return file size if exists, 0 if directory, -1 if not found."""
4558
pass
4659

4760
@abstractmethod
4861
def isdir(self, path: str) -> bool:
62+
"""Return True if path is an existing directory."""
4963
pass
5064

5165
@abstractmethod
5266
def isfile(self, path: str) -> bool:
67+
"""Return True if path is an existing file."""
5368
pass
5469

5570
@abstractmethod
5671
def create(self, path: str, content):
72+
"""Create a new text file at path with given content. Raises InvalidPath or ResourceAlreadyExists."""
5773
if ".." in path:
5874
raise InvalidPath(path)
5975

@@ -62,6 +78,7 @@ def create(self, path: str, content):
6278

6379
@abstractmethod
6480
def create_binary(self, path: str, content):
81+
"""Create a new binary file at path with given content. Raises InvalidPath or ResourceAlreadyExists."""
6582
if ".." in path:
6683
raise InvalidPath(path)
6784

@@ -70,18 +87,21 @@ def create_binary(self, path: str, content):
7087

7188
@abstractmethod
7289
def write(self, path: str, content):
90+
"""Overwrite an existing text file at path. Raises ResourceNotExists if missing."""
7391
size = self.exists(path)
7492
if size < 0:
7593
raise ResourceNotExists(path)
7694

7795
@abstractmethod
7896
def write_binary(self, path: str, content):
97+
"""Overwrite an existing binary file at path. Raises ResourceNotExists if missing."""
7998
size = self.exists(path)
8099
if size < 0:
81100
raise ResourceNotExists(path)
82101

83102
@abstractmethod
84103
def read(self, path: str):
104+
"""Read and return text content of file at path. Raises InvalidPath or ResourceNotExists."""
85105
if ".." in path:
86106
raise InvalidPath(path)
87107

@@ -90,6 +110,7 @@ def read(self, path: str):
90110

91111
@abstractmethod
92112
def read_binary(self, path: str):
113+
"""Read and return binary content of file at path. Raises InvalidPath or ResourceNotExists."""
93114
if ".." in path:
94115
raise InvalidPath(path)
95116

@@ -98,6 +119,7 @@ def read_binary(self, path: str):
98119

99120
@abstractmethod
100121
def listdirs(self, path: str):
122+
"""Return list of subdirectory names at path. Raises InvalidPath or ResourceNotExists."""
101123
if ".." in path:
102124
raise InvalidPath(path)
103125

@@ -109,6 +131,7 @@ def listdirs(self, path: str):
109131

110132
@abstractmethod
111133
def listfiles(self, path: str):
134+
"""Return list of file names at path. Raises InvalidPath or ResourceNotExists."""
112135
if ".." in path:
113136
raise InvalidPath(path)
114137

@@ -120,6 +143,7 @@ def listfiles(self, path: str):
120143

121144
@abstractmethod
122145
def list_formatted(self, path: str, base_group: str):
146+
"""Return formatted directory listing for the file explorer UI."""
123147
if ".." in path:
124148
raise InvalidPath(path)
125149

@@ -131,6 +155,7 @@ def list_formatted(self, path: str, base_group: str):
131155

132156
@abstractmethod
133157
def mkdir(self, path: str):
158+
"""Create a new directory at path. Raises InvalidPath or ResourceAlreadyExists."""
134159
if ".." in path:
135160
raise InvalidPath(path)
136161

@@ -139,6 +164,7 @@ def mkdir(self, path: str):
139164

140165
@abstractmethod
141166
def renamefile(self, old_path: str, new_path: str):
167+
"""Rename a file from old_path to new_path. Raises InvalidPath, ResourceNotExists, or ResourceAlreadyExists."""
142168
if ".." in new_path:
143169
raise InvalidPath(new_path)
144170

@@ -150,6 +176,7 @@ def renamefile(self, old_path: str, new_path: str):
150176

151177
@abstractmethod
152178
def renamedir(self, old_path: str, new_path: str):
179+
"""Rename a directory from old_path to new_path. Raises InvalidPath, ResourceNotExists, or ResourceAlreadyExists."""
153180
if ".." in new_path:
154181
raise InvalidPath(new_path)
155182

@@ -161,6 +188,7 @@ def renamedir(self, old_path: str, new_path: str):
161188

162189
@abstractmethod
163190
def removefile(self, path: str):
191+
"""Delete a file at path. Raises InvalidPath or ResourceNotExists."""
164192
if ".." in path:
165193
raise InvalidPath(path)
166194

@@ -173,6 +201,7 @@ def removefile(self, path: str):
173201

174202
@abstractmethod
175203
def removedir(self, path: str):
204+
"""Delete a directory and all its contents. Raises InvalidPath or ResourceNotExists."""
176205
if ".." in path:
177206
raise InvalidPath(path)
178207

@@ -184,6 +213,7 @@ def removedir(self, path: str):
184213

185214
@abstractmethod
186215
def dir_size(self, path):
216+
"""Return total size in bytes of all files under path. Raises InvalidPath or ResourceNotExists."""
187217
if ".." in path:
188218
raise InvalidPath(path)
189219

@@ -196,11 +226,17 @@ def dir_size(self, path):
196226
raise ResourceNotExists(path)
197227

198228
def filename(self, path: str) -> str:
229+
"""Return the filename without extension from a full path."""
199230
return os.path.splitext(os.path.basename(path))[0]
200231

201232

202233
class FAL_RA(FAL):
203-
"""File Abstraction Layer"""
234+
"""
235+
Concrete FAL implementation for local RoboticsAcademy filesystem.
236+
237+
Stores exercise files under the academy filesystem directory and
238+
uses standard Python os/shutil operations for all file access.
239+
"""
204240

205241
def __init__(self, base, helper):
206242
FAL.__init__(self, base, helper)

academy/models.py

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
"""
2-
models.py
2+
Django ORM models for Robotics Academy.
3+
4+
Defines the database schema for exercises, universes, worlds,
5+
robots, and tools used by the Robotics Academy platform.
36
"""
47

58
from django.db import models
@@ -23,7 +26,11 @@
2326

2427
class Tool(models.Model):
2528
"""
26-
Modelo Tool para Robotics Academy
29+
Represents a tool available in the Robotics Academy platform.
30+
31+
Attributes:
32+
name: Unique identifier and primary key for the tool.
33+
base_config: Default configuration string for the tool.
2734
"""
2835

2936
name = models.CharField(max_length=50, blank=False, unique=True, primary_key=True)
@@ -38,7 +45,11 @@ class Meta:
3845

3946
class Robot(models.Model):
4047
"""
41-
Modelo Robot para RoboticsAcademy
48+
Represents a robot available in the Robotics Academy platform.
49+
50+
Attributes:
51+
name: Unique name identifying the robot.
52+
launch_file_path: Path to the ROS launch file for this robot.
4253
"""
4354

4455
name = models.CharField(max_length=100, blank=False, unique=True)
@@ -53,7 +64,15 @@ class Meta:
5364

5465
class World(models.Model):
5566
"""
56-
Modelo World para RoboticsCademy
67+
Represents a simulation world in the Robotics Academy platform.
68+
69+
Attributes:
70+
name: Unique name identifying the world.
71+
launch_file_path: Path to the ROS launch file for this world.
72+
tools_config: JSON string with tool configuration overrides.
73+
ros_version: ROS version used (ROS or ROS2).
74+
type: Simulator type (none, gazebo, gz, physical).
75+
start_pose: List of starting poses for robots in this world.
5776
"""
5877

5978
name = models.CharField(max_length=100, blank=False, unique=True)
@@ -81,7 +100,12 @@ class Meta:
81100

82101
class Universe(models.Model):
83102
"""
84-
Modelo Universe para Robotics Academy
103+
Represents a universe combining a world and a robot.
104+
105+
Attributes:
106+
name: Unique name identifying the universe.
107+
world: Associated World instance.
108+
robot: Associated Robot instance.
85109
"""
86110

87111
name = models.CharField(max_length=100, blank=False, unique=True)
@@ -104,7 +128,17 @@ class Meta:
104128

105129
class Exercise(models.Model):
106130
"""
107-
Robotics Academy Exercise model
131+
Represents a Robotics Academy exercise.
132+
133+
Attributes:
134+
exercise_id: Unique string identifier for the exercise.
135+
name: Human-readable name of the exercise.
136+
description: Short description of the exercise goals.
137+
tags: JSON-encoded list of tags (e.g. MULTILANGUAGE).
138+
status: Lifecycle status (ACTIVE, INACTIVE, PROTOTYPE).
139+
universes: Associated Universe instances via ExerciseUniverses.
140+
tools: Associated Tool instances.
141+
url: Optional URL for additional exercise resources.
108142
"""
109143

110144
exercise_id = models.CharField(max_length=40, blank=False, unique=True)
@@ -126,6 +160,14 @@ class Meta:
126160

127161

128162
class ExerciseUniverses(models.Model):
163+
"""
164+
Through model linking Exercise and Universe with a default flag.
165+
166+
Attributes:
167+
exercise: Related Exercise instance.
168+
universe: Related Universe instance.
169+
is_default: Whether this universe is the default for the exercise.
170+
"""
129171
exercise = models.ForeignKey(Exercise, on_delete=models.CASCADE)
130172
universe = models.ForeignKey(Universe, on_delete=models.CASCADE)
131173
is_default = models.BooleanField()

academy/serializers.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
1+
"""
2+
Serializers for Robotics Academy API.
3+
"""
4+
15
from rest_framework import serializers
26

37

48
class FileContentSerializer(serializers.Serializer):
9+
"""
10+
Serializer for file content responses.
11+
12+
Fields:
13+
content: The text content of the file as a string.
14+
"""
15+
516
content = serializers.CharField()

0 commit comments

Comments
 (0)