Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
7bb5a09
FIX: improve optional dependency imports
Gui-FernandesBR Sep 6, 2023
bc73fcd
MAINT: introducing requirements-optional.txt file
Gui-FernandesBR Sep 6, 2023
e690da6
MAINT: improve dependency management function
Gui-FernandesBR Sep 6, 2023
7cf2435
FIX: applying comments reviews
Gui-FernandesBR Sep 6, 2023
4b93df6
Merge branch 'fix/env-analysis-dependency-imports' of https://github.…
Gui-FernandesBR Sep 6, 2023
b048e24
FIX: __check_extra_requirements() not working
Gui-FernandesBR Sep 6, 2023
04f6a54
Fix code style issues with Black
lint-action Sep 6, 2023
174663b
MAINT: update github workflows files
Gui-FernandesBR Sep 7, 2023
0413472
FIX: adding IPython as an optional require
Gui-FernandesBR Sep 7, 2023
bcccebc
FIX: restore ipython version to 8.8 to allow py3.8
Gui-FernandesBR Sep 7, 2023
507a5fb
Merge branch 'fix/env-analysis-dependency-imports' into maint/update-…
Gui-FernandesBR Sep 7, 2023
d032296
TST: apply import_optional_dependency to tests
Gui-FernandesBR Sep 7, 2023
7b72ee6
Merge branch 'fix/env-analysis-dependency-imports' into maint/update-…
Gui-FernandesBR Sep 7, 2023
9ddcec9
TST: test the import rocketpy
Gui-FernandesBR Sep 7, 2023
979a5c7
FIX: improve extra req checks
Gui-FernandesBR Sep 10, 2023
5341548
GIT: improve pytest workflow based on rev
Gui-FernandesBR Sep 10, 2023
cfdd041
Merge pull request #405 from RocketPy-Team/maint/update-git-actions
Gui-FernandesBR Sep 13, 2023
6382364
MAINT: avoid using eval()
Gui-FernandesBR Sep 15, 2023
96a8ffc
FIX: importlib metadata import error.
phmbressan Sep 15, 2023
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
7 changes: 5 additions & 2 deletions .github/auto-assign.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,19 @@ addReviewers: true
# Set to 'author' to add PR's author as a assignee
addAssignees: author

# A list of reviewers to be added to PRs (GitHub user name)
# A list of reviewers to be added to PRs (GitHub user name)
reviewers:
- Gui-FernandesBR
- giovaniceotto
- MateusStano

- phmbressan

# A number of reviewers added to the PR
# Set 0 to add all the reviewers (default: 0)
numberOfReviewers: 0

# A list of keywords to be skipped the process if PR's title include it
skipKeywords:
- wip
- work in progress
- draft
21 changes: 0 additions & 21 deletions .github/workflows/auto-assign-projects

This file was deleted.

4 changes: 1 addition & 3 deletions .github/workflows/auto-assign.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
name: Auto Assign Issues and PRs once opened
name: Auto Assign PRs once opened
on:
issues:
types: [opened]
pull_request:
types: [opened]
jobs:
Expand Down
11 changes: 8 additions & 3 deletions .github/workflows/test_pytest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,15 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements-tests.txt
- name: Build RocketPy
- name: Build RocketPy (without optional dependencies)
run: |
pip install .
- name: Import rocketpy in python and test if it works
run: |
pip install -e.[all]
python -c "import sys, rocketpy; print(f'{rocketpy.__name__} running on Python {sys.version}')"
- name: Install optional dependencies
run: |
pip install -r requirements-tests.txt
- name: Test with pytest
run: |
pytest
Expand Down
1 change: 1 addition & 0 deletions docs/user/requirements.rst
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ In case you want to use this class, you will need to install the following packa

- `timezonefinder` : to allow for automatic timezone detection,
- `windrose` : to allow for windrose plots,
- `ipython` : to allow for animated plots,
- `ipywidgets` : to allow for GIFs generation,
- `jsonpickle` : to allow for saving and loading of class instances.

Expand Down
5 changes: 5 additions & 0 deletions requirements-optional.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
windrose>=1.6.8
ipython
ipywidgets>=7.6.3
jsonpickle
timezonefinder
5 changes: 0 additions & 5 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,6 @@ numpy>=1.13
scipy>=1.0
matplotlib>=3.0
netCDF4>=1.6.4
windrose>=1.6.8
ipywidgets>=7.6.3
requests
pytz
timezonefinder
simplekml
jsonpickle
numericalunits
69 changes: 53 additions & 16 deletions rocketpy/EnvironmentAnalysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import json
from collections import defaultdict

import matplotlib.ticker as mtick
import netCDF4
import numpy as np
import pytz
Expand All @@ -19,23 +18,14 @@
from rocketpy.Function import Function
from rocketpy.units import convert_units

try:
import ipywidgets as widgets
import jsonpickle
from timezonefinder import TimezoneFinder
from windrose import WindroseAxes
except ImportError as error:
raise ImportError(
f"The following error was encountered while importing dependencies: '{error}'. "
"Please note that the EnvironmentAnalysis requires additional dependencies, "
"which can be installed by running 'pip install rocketpy[env_analysis]'."
)
from .plots.environment_analysis_plots import _EnvironmentAnalysisPlots
from .prints.environment_analysis_prints import _EnvironmentAnalysisPrints
from .tools import (
bilinear_interpolation,
check_requirement_version,
geopotential_to_height_agl,
geopotential_to_height_asl,
import_optional_dependency,
time_num_to_date_string,
)

Expand Down Expand Up @@ -194,6 +184,9 @@ def __init__(
self.unit_system = unit_system
self.max_expected_altitude = max_expected_altitude

# Check if extra requirements are installed
self.__check_requirements()

# Manage units and timezones
self.__init_data_parsing_units()
self.__find_preferred_timezone()
Expand Down Expand Up @@ -232,6 +225,39 @@ def __init__(

# Private, auxiliary methods

def __check_requirements(self):
"""Check if extra requirements are installed. If not, print a message
informing the user that some methods may not work and how to install
the extra requirements for environment analysis.

Returns
-------
None
"""
env_analysis_require = { # The same as in the setup.py file
"timezonefinder": "",
"windrose": ">=1.6.8",
"IPython": "",
"ipywidgets": ">=7.6.3",
"jsonpickle": "",
}
has_error = False
for module_name, version in env_analysis_require.items():
version = ">=0" if not version else version
try:
check_requirement_version(module_name, version)
except (ValueError, ImportError) as e:
has_error = True
print(
f"The following error occurred while importing {module_name}: {e}"
)
if has_error:
print(
"Given the above errors, some methods may not work. Please run "
+ "'pip install rocketpy[env_analysis]' to install extra requirements."
)
return None

def __init_surface_dictionary(self):
# Create dictionary of file variable names to process surface data
return {
Expand Down Expand Up @@ -382,10 +408,19 @@ def __localize_input_dates(self):
def __find_preferred_timezone(self):
if self.preferred_timezone is None:
# Use local timezone based on lat lon pair
tf = TimezoneFinder()
self.preferred_timezone = pytz.timezone(
tf.timezone_at(lng=self.longitude, lat=self.latitude)
)
try:
timezonefinder = import_optional_dependency("timezonefinder")
tf = timezonefinder.TimezoneFinder()
self.preferred_timezone = pytz.timezone(
tf.timezone_at(lng=self.longitude, lat=self.latitude)
)
except ImportError:
print(
"'timezonefinder' not installed, defaulting to UTC."
+ " Install timezonefinder to get local time zone."
+ " To do so, run 'pip install timezonefinder'"
)
self.preferred_timezone = pytz.timezone("UTC")
elif isinstance(self.preferred_timezone, str):
self.preferred_timezone = pytz.timezone(self.preferred_timezone)

Expand Down Expand Up @@ -2727,6 +2762,7 @@ def load(self, filename="env_analysis_dict"):
EnvironmentAnalysis object

"""
jsonpickle = import_optional_dependency("jsonpickle")
encoded_class = open(filename).read()
return jsonpickle.decode(encoded_class)

Expand All @@ -2743,6 +2779,7 @@ def save(self, filename="env_analysis_dict"):
-------
None
"""
jsonpickle = import_optional_dependency("jsonpickle")
encoded_class = jsonpickle.encode(self)
file = open(filename, "w")
file.write(encoded_class)
Expand Down
20 changes: 15 additions & 5 deletions rocketpy/plots/environment_analysis_plots.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,17 @@
__copyright__ = "Copyright 20XX, RocketPy Team"
__license__ = "MIT"

import ipywidgets as widgets
import matplotlib.pyplot as plt
import matplotlib.ticker as mtick
import numpy as np
from IPython.display import HTML
from matplotlib import pyplot as plt
from matplotlib.animation import FuncAnimation
from matplotlib.animation import PillowWriter as ImageWriter
from scipy import stats
from windrose import WindroseAxes

from rocketpy.units import convert_units

from ..tools import find_two_closest_integers
from ..tools import find_two_closest_integers, import_optional_dependency

# TODO: `wind_speed_limit` and `clear_range_limits` and should be numbers, not booleans

Expand Down Expand Up @@ -856,6 +853,8 @@ def plot_wind_rose(
-------
WindroseAxes
"""
windrose = import_optional_dependency("windrose")
WindroseAxes = windrose.WindroseAxes
ax = WindroseAxes.from_ax(fig=fig, rect=rect)
ax.bar(
wind_direction,
Expand Down Expand Up @@ -990,8 +989,9 @@ def animate_average_wind_rose(self, figsize=(5, 5), filename="wind_rose.gif"):

Returns
-------
Image : ipywidgets.widgets.widget_media.Image
Image : ipywidgets.widget_media.Image
"""
widgets = import_optional_dependency("ipywidgets")
metadata = dict(
title="windrose",
artist="windrose",
Expand Down Expand Up @@ -1113,6 +1113,9 @@ def animate_wind_gust_distribution(self):
HTML : IPython.core.display.HTML
The animation as an HTML object
"""
module = import_optional_dependency("IPython.display")
HTML = module.HTML # this is a class

# Gather animation data
wind_gusts = self.env_analysis.surface_wind_gust_by_hour

Expand Down Expand Up @@ -1311,6 +1314,9 @@ def animate_surface_wind_speed_distribution(self, wind_speed_limit=False):
-------
HTML : IPython.core.display.HTML
"""
module = import_optional_dependency("IPython.display")
HTML = module.HTML # this is a class

# Gather animation data
surface_wind_speeds_at_given_hour = self.env_analysis.surface_wind_speed_by_hour

Expand Down Expand Up @@ -1608,6 +1614,8 @@ def animate_wind_speed_profile(self, clear_range_limits=False):
Whether to clear the sky range limits or not, by default False. This
is useful when the launch site is constrained in terms or altitude.
"""
module = import_optional_dependency("IPython.display")
HTML = module.HTML # this is a class

# Create animation
fig, ax = plt.subplots(dpi=200)
Expand Down Expand Up @@ -1687,6 +1695,8 @@ def animate_wind_heading_profile(self, clear_range_limits=False):
Whether to clear the sky range limits or not, by default False. This
is useful when the launch site is constrained in terms or altitude.
"""
module = import_optional_dependency("IPython.display")
HTML = module.HTML # this is a class

# Create animation
fig, ax = plt.subplots(dpi=200)
Expand Down
Loading