Skip to content

Commit 971f7ac

Browse files
BUG: fins failing to accept both sweep and angle (#59)
Co-authored-by: Gabriel Barberini <[email protected]>
1 parent da0bdb0 commit 971f7ac

File tree

3 files changed

+132
-100
lines changed

3 files changed

+132
-100
lines changed

Makefile

Lines changed: 52 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,69 @@
1+
VENV_BIN ?= ./infinity_env/bin
2+
PYLINTHOME ?= .pylint.d
3+
4+
export PYLINTHOME
5+
6+
ifneq (,$(wildcard $(VENV_BIN)/black))
7+
BLACK := $(VENV_BIN)/black
8+
else
9+
BLACK := black
10+
endif
11+
12+
ifneq (,$(wildcard $(VENV_BIN)/ruff))
13+
RUFF := $(VENV_BIN)/ruff
14+
else
15+
RUFF := ruff
16+
endif
17+
18+
ifneq (,$(wildcard $(VENV_BIN)/flake8))
19+
FLAKE8 := $(VENV_BIN)/flake8
20+
else
21+
FLAKE8 := flake8
22+
endif
23+
24+
ifneq (,$(wildcard $(VENV_BIN)/pylint))
25+
PYLINT := $(VENV_BIN)/pylint
26+
else
27+
PYLINT := pylint
28+
endif
29+
30+
ifneq (,$(wildcard $(VENV_BIN)/pytest))
31+
PYTEST := $(VENV_BIN)/pytest
32+
else
33+
PYTEST := python3 -m pytest
34+
endif
35+
36+
ifneq (,$(wildcard $(VENV_BIN)/uvicorn))
37+
UVICORN := $(VENV_BIN)/uvicorn
38+
else
39+
UVICORN := python3 -m uvicorn
40+
endif
41+
142
format: black ruff
243
lint: flake8 pylint
344

445
black:
5-
black ./src || true
6-
black ./tests || true
46+
$(BLACK) ./src || true
47+
$(BLACK) ./tests || true
748

849
flake8:
9-
flake8 --ignore E501,E402,F401,W503,C0414 ./src || true
10-
flake8 --ignore E501,E402,F401,W503,C0414 ./tests || true
50+
$(FLAKE8) --ignore E501,E402,F401,W503,C0414 ./src || true
51+
$(FLAKE8) --ignore E501,E402,F401,W503,C0414 ./tests || true
1152

1253
pylint:
13-
pylint ./src || true
14-
pylint ./tests || true
54+
@mkdir -p $(PYLINTHOME)
55+
$(PYLINT) ./src || true
56+
$(PYLINT) ./tests || true
1557

1658
ruff:
17-
ruff check --fix ./src || true
18-
ruff check --fix ./tests || true
59+
$(RUFF) check --fix ./src || true
60+
$(RUFF) check --fix ./tests || true
1961

2062
test:
21-
python3 -m pytest .
63+
$(PYTEST) .
2264

2365
dev:
24-
python3 -m uvicorn src:app --reload --port 3000 --loop uvloop
66+
$(UVICORN) src:app --reload --port 3000 --loop uvloop
2567

2668
clean:
2769
docker stop infinity-api

src/models/sub/aerosurfaces.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,18 @@ class Fins(BaseModel):
4444
sweep_length: Optional[float] = None
4545
sweep_angle: Optional[float] = None
4646

47+
_base_keys = {"fins_kind", "name", "n", "root_chord", "span", "position"}
48+
4749
def get_additional_parameters(self):
48-
return {
49-
key: value
50-
for key, value in self.dict().items()
51-
if value is not None
52-
and key
53-
not in ["fins_kind", "name", "n", "root_chord", "span", "position"]
50+
params = {
51+
k: v
52+
for k, v in self.dict().items()
53+
if v is not None and k not in self._base_keys
5454
}
55+
if "sweep_angle" in params and "sweep_length" in params:
56+
params.pop("sweep_length")
57+
58+
return params
5559

5660

5761
# TODO: implement airbrakes

src/utils.py

Lines changed: 70 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,8 @@ def for_flight(cls) -> 'DiscretizeConfig':
5454

5555

5656
class InfinityEncoder(RocketPyEncoder):
57-
def __init__(self, *args, **kwargs):
58-
super().__init__(*args, **kwargs)
59-
60-
def default(self, obj):
57+
def default(self, o):
58+
obj = o
6159
if (
6260
isinstance(obj, Function)
6361
and not callable(obj.source)
@@ -75,7 +73,7 @@ def default(self, obj):
7573
mutate_self=False,
7674
)
7775
if isinstance(obj, Flight):
78-
obj._Flight__evaluate_post_process
76+
obj._Flight__evaluate_post_process()
7977
solution = np.array(obj.solution)
8078
size = len(solution)
8179
if size > 25:
@@ -117,92 +115,80 @@ def rocketpy_encoder(obj):
117115

118116

119117
def collect_attributes(obj, attribute_classes=None):
120-
"""
121-
Collect attributes from various simulation classes and populate them from the flight object.
122-
"""
123-
if attribute_classes is None:
124-
attribute_classes = []
118+
"""Collect and serialize attributes from simulation classes."""
119+
attribute_classes = attribute_classes or []
125120

126121
attributes = rocketpy_encoder(obj)
127-
128122
for attribute_class in attribute_classes:
129-
if issubclass(attribute_class, FlightSimulation):
130-
flight_attributes_list = [
131-
attr
132-
for attr in attribute_class.__annotations__.keys()
133-
if attr not in ["message", "rocket", "env"]
134-
]
135-
try:
136-
for key in flight_attributes_list:
137-
if key not in attributes:
138-
try:
139-
value = getattr(obj, key)
140-
attributes[key] = value
141-
except Exception:
142-
pass
143-
except Exception:
144-
pass
145-
146-
elif issubclass(attribute_class, RocketSimulation):
147-
rocket_attributes_list = [
148-
attr
149-
for attr in attribute_class.__annotations__.keys()
150-
if attr not in ["message", "motor"]
151-
]
152-
try:
153-
for key in rocket_attributes_list:
154-
if key not in attributes.get("rocket", {}):
155-
try:
156-
value = getattr(obj.rocket, key)
157-
attributes.setdefault("rocket", {})[key] = value
158-
except Exception:
159-
pass
160-
except Exception:
161-
pass
162-
163-
elif issubclass(attribute_class, MotorSimulation):
164-
motor_attributes_list = [
165-
attr
166-
for attr in attribute_class.__annotations__.keys()
167-
if attr not in ["message"]
168-
]
169-
try:
170-
for key in motor_attributes_list:
171-
if key not in attributes.get("rocket", {}).get(
172-
"motor", {}
173-
):
174-
try:
175-
value = getattr(obj.rocket.motor, key)
176-
attributes.setdefault("rocket", {}).setdefault(
177-
"motor", {}
178-
)[key] = value
179-
except Exception:
180-
pass
181-
except Exception:
182-
pass
183-
184-
elif issubclass(attribute_class, EnvironmentSimulation):
185-
environment_attributes_list = [
186-
attr
187-
for attr in attribute_class.__annotations__.keys()
188-
if attr not in ["message"]
189-
]
190-
try:
191-
for key in environment_attributes_list:
192-
if key not in attributes.get("env", {}):
193-
try:
194-
value = getattr(obj.env, key)
195-
attributes.setdefault("env", {})[key] = value
196-
except Exception:
197-
pass
198-
except Exception:
199-
pass
200-
else:
201-
continue
123+
_populate_simulation_attributes(obj, attribute_class, attributes)
202124

203125
return rocketpy_encoder(attributes)
204126

205127

128+
def _populate_simulation_attributes(obj, attribute_class, attributes):
129+
if not isinstance(attribute_class, type):
130+
return
131+
132+
mappings = (
133+
(FlightSimulation, (), (), {"message", "rocket", "env"}),
134+
(RocketSimulation, ("rocket",), ("rocket",), {"message", "motor"}),
135+
(
136+
MotorSimulation,
137+
("rocket", "motor"),
138+
("rocket", "motor"),
139+
{"message"},
140+
),
141+
(EnvironmentSimulation, ("env",), ("env",), {"message"}),
142+
)
143+
144+
for klass, source_path, target_path, exclusions in mappings:
145+
if not issubclass(attribute_class, klass):
146+
continue
147+
148+
keys = _annotation_keys(attribute_class, exclusions)
149+
if not keys:
150+
return
151+
152+
source = _resolve_attribute_path(obj, source_path)
153+
if source is None:
154+
return
155+
156+
target = _resolve_attribute_target(attributes, target_path)
157+
_copy_missing_attributes(source, target, keys)
158+
return
159+
160+
161+
def _annotation_keys(attribute_class, exclusions):
162+
annotations = getattr(attribute_class, "__annotations__", {})
163+
return [key for key in annotations if key not in exclusions]
164+
165+
166+
def _resolve_attribute_path(root, path):
167+
current = root
168+
for attr in path:
169+
if current is None:
170+
return None
171+
current = getattr(current, attr, None)
172+
return current
173+
174+
175+
def _resolve_attribute_target(attributes, path):
176+
target = attributes
177+
for key in path:
178+
target = target.setdefault(key, {})
179+
return target
180+
181+
182+
def _copy_missing_attributes(source, target, keys):
183+
for key in keys:
184+
if key in target:
185+
continue
186+
try:
187+
target[key] = getattr(source, key)
188+
except AttributeError:
189+
continue
190+
191+
206192
def _fix_datetime_fields(data):
207193
"""
208194
Fix datetime fields that RocketPyEncoder converted to lists.

0 commit comments

Comments
 (0)