gr-libs 0.1.5__tar.gz → 0.1.7.post0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {gr_libs-0.1.5/gr_libs.egg-info → gr_libs-0.1.7.post0}/PKG-INFO +22 -1
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/README.md +20 -0
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/gr_libs/__init__.py +5 -1
- gr_libs-0.1.7.post0/gr_libs/_version.py +21 -0
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/gr_libs/environment/__init__.py +2 -2
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/gr_libs/environment/environment.py +1 -1
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/gr_libs/metrics/metrics.py +1 -2
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/gr_libs/ml/tabular/tabular_q_learner.py +1 -1
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/gr_libs/ml/utils/storage.py +7 -0
- gr_libs-0.1.7.post0/gr_libs/recognizer/graml/__init__.py +0 -0
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/gr_libs/recognizer/graml/graml_recognizer.py +21 -12
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/gr_libs/recognizer/recognizer.py +0 -1
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0/gr_libs.egg-info}/PKG-INFO +22 -1
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/gr_libs.egg-info/SOURCES.txt +5 -6
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/gr_libs.egg-info/requires.txt +1 -0
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/gr_libs.egg-info/top_level.txt +3 -0
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/pyproject.toml +3 -1
- gr_libs-0.1.7.post0/tests/test_graml.py +16 -0
- gr_libs-0.1.7.post0/tests/test_graql.py +4 -0
- gr_libs-0.1.7.post0/tutorials/graml_minigrid_tutorial.py +34 -0
- gr_libs-0.1.7.post0/tutorials/graml_panda_tutorial.py +41 -0
- gr_libs-0.1.7.post0/tutorials/graml_parking_tutorial.py +39 -0
- gr_libs-0.1.7.post0/tutorials/graml_point_maze_tutorial.py +39 -0
- gr_libs-0.1.7.post0/tutorials/graql_minigrid_tutorial.py +34 -0
- gr_libs-0.1.5/.github/workflows/release.yml +0 -32
- gr_libs-0.1.5/.gitignore +0 -160
- gr_libs-0.1.5/all_experiments.py +0 -194
- gr_libs-0.1.5/gr_libs/recognizer/recognizer_doc.md +0 -61
- gr_libs-0.1.5/odgr_executor.py +0 -125
- gr_libs-0.1.5/tutorials/graml_minigrid_tutorial.py +0 -30
- gr_libs-0.1.5/tutorials/graml_panda_tutorial.py +0 -37
- gr_libs-0.1.5/tutorials/graml_parking_tutorial.py +0 -34
- gr_libs-0.1.5/tutorials/graml_point_maze_tutorial.py +0 -35
- gr_libs-0.1.5/tutorials/graql_minigrid_tutorial.py +0 -29
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/evaluation/analyze_results_cross_alg_cross_domain.py +0 -0
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/evaluation/create_minigrid_map_image.py +0 -0
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/evaluation/file_system.py +0 -0
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/evaluation/generate_experiments_results.py +0 -0
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/evaluation/generate_experiments_results_new_ver1.py +0 -0
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/evaluation/generate_experiments_results_new_ver2.py +0 -0
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/evaluation/generate_task_specific_statistics_plots.py +0 -0
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/evaluation/get_plans_images.py +0 -0
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/evaluation/increasing_and_decreasing_.py +0 -0
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/gr_libs/environment/utils/__init__.py +0 -0
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/gr_libs/environment/utils/utils.py +0 -0
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/gr_libs/metrics/__init__.py +0 -0
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/gr_libs/ml/__init__.py +0 -0
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/gr_libs/ml/agent.py +0 -0
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/gr_libs/ml/base/__init__.py +0 -0
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/gr_libs/ml/base/rl_agent.py +0 -0
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/gr_libs/ml/consts.py +0 -0
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/gr_libs/ml/neural/__init__.py +0 -0
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/gr_libs/ml/neural/deep_rl_learner.py +0 -0
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/gr_libs/ml/neural/utils/__init__.py +0 -0
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/gr_libs/ml/neural/utils/dictlist.py +0 -0
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/gr_libs/ml/neural/utils/penv.py +0 -0
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/gr_libs/ml/planner/__init__.py +0 -0
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/gr_libs/ml/planner/mcts/__init__.py +0 -0
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/gr_libs/ml/planner/mcts/mcts_model.py +0 -0
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/gr_libs/ml/planner/mcts/utils/__init__.py +0 -0
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/gr_libs/ml/planner/mcts/utils/node.py +0 -0
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/gr_libs/ml/planner/mcts/utils/tree.py +0 -0
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/gr_libs/ml/sequential/__init__.py +0 -0
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/gr_libs/ml/sequential/lstm_model.py +0 -0
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/gr_libs/ml/tabular/__init__.py +0 -0
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/gr_libs/ml/tabular/state.py +0 -0
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/gr_libs/ml/tabular/tabular_rl_agent.py +0 -0
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/gr_libs/ml/utils/__init__.py +0 -0
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/gr_libs/ml/utils/env.py +0 -0
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/gr_libs/ml/utils/format.py +0 -0
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/gr_libs/ml/utils/math.py +0 -0
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/gr_libs/ml/utils/other.py +0 -0
- {gr_libs-0.1.5/gr_libs/recognizer → gr_libs-0.1.7.post0/gr_libs/problems}/__init__.py +0 -0
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0/gr_libs/problems}/consts.py +0 -0
- {gr_libs-0.1.5/gr_libs/recognizer/gr_as_rl → gr_libs-0.1.7.post0/gr_libs/recognizer}/__init__.py +0 -0
- {gr_libs-0.1.5/gr_libs/recognizer/graml → gr_libs-0.1.7.post0/gr_libs/recognizer/gr_as_rl}/__init__.py +0 -0
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/gr_libs/recognizer/gr_as_rl/gr_as_rl_recognizer.py +0 -0
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/gr_libs/recognizer/graml/gr_dataset.py +0 -0
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/gr_libs/recognizer/utils/__init__.py +0 -0
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/gr_libs/recognizer/utils/format.py +0 -0
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/gr_libs.egg-info/dependency_links.txt +0 -0
- {gr_libs-0.1.5 → gr_libs-0.1.7.post0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: gr_libs
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.7.post0
|
4
4
|
Summary: Package with goal recognition frameworks baselines
|
5
5
|
Author: Ben Nageris
|
6
6
|
Author-email: Matan Shamir <matan.shamir@live.biu.ac.il>, Osher Elhadad <osher.elhadad@live.biu.ac.il>
|
@@ -17,6 +17,7 @@ Requires-Dist: torchvision
|
|
17
17
|
Requires-Dist: rl_zoo3
|
18
18
|
Requires-Dist: stable_baselines3[extra]
|
19
19
|
Requires-Dist: sb3_contrib
|
20
|
+
Requires-Dist: pytest
|
20
21
|
Provides-Extra: minigrid
|
21
22
|
Requires-Dist: gr_envs[minigrid]; extra == "minigrid"
|
22
23
|
Provides-Extra: highway
|
@@ -111,6 +112,25 @@ After installing GRLib, you will have access to custom Gym environments, allowin
|
|
111
112
|
|
112
113
|
Tutorials demonstrating basic ODGR scenarios is available in the sub-package `tutorials`. These tutorials walk through the initialization and deployment process, showcasing how different GR algorithms adapt to emerging goals in various Gym environments.
|
113
114
|
|
115
|
+
## Working with an initial dataset of trained agents
|
116
|
+
gr_libs also includes a library of trained agents for the various supported environments within the package.
|
117
|
+
To get the dataset of trained agents, you can run:
|
118
|
+
```sh
|
119
|
+
python download_dataset.py
|
120
|
+
```
|
121
|
+
|
122
|
+
An alternative is to use our docker image, which includes the dataset in it.
|
123
|
+
You can:
|
124
|
+
1. pull the image:
|
125
|
+
```sh
|
126
|
+
docker pull ghcr.io/MatanShamir1/gr_test_base:latest
|
127
|
+
```
|
128
|
+
2. run a container:
|
129
|
+
```sh
|
130
|
+
docker run -it ghcr.io/MatanShamir1/gr_test_base:latest bash
|
131
|
+
```
|
132
|
+
3. don't forget to install the package from within the container, go back to 'Setup' for that.
|
133
|
+
|
114
134
|
### Method 1: Writing a Custom Script
|
115
135
|
|
116
136
|
1. **Create a recognizer**
|
@@ -118,6 +138,7 @@ Tutorials demonstrating basic ODGR scenarios is available in the sub-package `tu
|
|
118
138
|
Specify the domain name and specific environment for the recognizer, effectively telling it the domain theory - the collection of states and actions in the environment.
|
119
139
|
|
120
140
|
```python
|
141
|
+
import gr_libs.environment # Triggers gym env registration - you must run it!
|
121
142
|
recognizer = Graql(
|
122
143
|
domain_name="minigrid",
|
123
144
|
env_name="MiniGrid-SimpleCrossingS13N4"
|
@@ -83,6 +83,25 @@ After installing GRLib, you will have access to custom Gym environments, allowin
|
|
83
83
|
|
84
84
|
Tutorials demonstrating basic ODGR scenarios is available in the sub-package `tutorials`. These tutorials walk through the initialization and deployment process, showcasing how different GR algorithms adapt to emerging goals in various Gym environments.
|
85
85
|
|
86
|
+
## Working with an initial dataset of trained agents
|
87
|
+
gr_libs also includes a library of trained agents for the various supported environments within the package.
|
88
|
+
To get the dataset of trained agents, you can run:
|
89
|
+
```sh
|
90
|
+
python download_dataset.py
|
91
|
+
```
|
92
|
+
|
93
|
+
An alternative is to use our docker image, which includes the dataset in it.
|
94
|
+
You can:
|
95
|
+
1. pull the image:
|
96
|
+
```sh
|
97
|
+
docker pull ghcr.io/MatanShamir1/gr_test_base:latest
|
98
|
+
```
|
99
|
+
2. run a container:
|
100
|
+
```sh
|
101
|
+
docker run -it ghcr.io/MatanShamir1/gr_test_base:latest bash
|
102
|
+
```
|
103
|
+
3. don't forget to install the package from within the container, go back to 'Setup' for that.
|
104
|
+
|
86
105
|
### Method 1: Writing a Custom Script
|
87
106
|
|
88
107
|
1. **Create a recognizer**
|
@@ -90,6 +109,7 @@ Tutorials demonstrating basic ODGR scenarios is available in the sub-package `tu
|
|
90
109
|
Specify the domain name and specific environment for the recognizer, effectively telling it the domain theory - the collection of states and actions in the environment.
|
91
110
|
|
92
111
|
```python
|
112
|
+
import gr_libs.environment # Triggers gym env registration - you must run it!
|
93
113
|
recognizer = Graql(
|
94
114
|
domain_name="minigrid",
|
95
115
|
env_name="MiniGrid-SimpleCrossingS13N4"
|
@@ -1,2 +1,6 @@
|
|
1
1
|
from gr_libs.recognizer.graml.graml_recognizer import ExpertBasedGraml, GCGraml
|
2
|
-
from gr_libs.recognizer.gr_as_rl.gr_as_rl_recognizer import Graql
|
2
|
+
from gr_libs.recognizer.gr_as_rl.gr_as_rl_recognizer import Graql
|
3
|
+
try:
|
4
|
+
from ._version import version as __version__
|
5
|
+
except ImportError:
|
6
|
+
__version__ = "0.0.0" # fallback if file isn't present
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# file generated by setuptools-scm
|
2
|
+
# don't change, don't track in version control
|
3
|
+
|
4
|
+
__all__ = ["__version__", "__version_tuple__", "version", "version_tuple"]
|
5
|
+
|
6
|
+
TYPE_CHECKING = False
|
7
|
+
if TYPE_CHECKING:
|
8
|
+
from typing import Tuple
|
9
|
+
from typing import Union
|
10
|
+
|
11
|
+
VERSION_TUPLE = Tuple[Union[int, str], ...]
|
12
|
+
else:
|
13
|
+
VERSION_TUPLE = object
|
14
|
+
|
15
|
+
version: str
|
16
|
+
__version__: str
|
17
|
+
__version_tuple__: VERSION_TUPLE
|
18
|
+
version_tuple: VERSION_TUPLE
|
19
|
+
|
20
|
+
__version__ = version = '0.1.7.post0'
|
21
|
+
__version_tuple__ = version_tuple = (0, 1, 7, 'post0')
|
@@ -12,11 +12,11 @@ def is_extra_installed(package: str, extra: str) -> bool:
|
|
12
12
|
return False # The package is not installed
|
13
13
|
|
14
14
|
# Check if `gr_libs[minigrid]` was installed
|
15
|
-
for env in ["minigrid", "panda", "
|
15
|
+
for env in ["minigrid", "panda", "highway", "maze"]:
|
16
16
|
if is_extra_installed("gr_libs", f"gr_envs[{env}]"):
|
17
17
|
try:
|
18
18
|
importlib.import_module(f"gr_envs.{env}_scripts.envs")
|
19
19
|
except ImportError:
|
20
|
-
raise ImportError(f"
|
20
|
+
raise ImportError(f"gr_envs[{env}] was not installed, but gr_libs[{env}] requires it! if you messed with gr_envs installation, you can reinstall gr_libs.")
|
21
21
|
else:
|
22
22
|
warnings.warn(f"gr_libs[{env}] was not installed, skipping {env} imports.", RuntimeWarning)
|
@@ -105,7 +105,7 @@ class MinigridProperty(EnvProperty):
|
|
105
105
|
env_id = problem_name.split("-DynamicGoal-")[0] + "-DynamicGoal-" + problem_name.split("-DynamicGoal-")[1]
|
106
106
|
result = register(
|
107
107
|
id=env_id,
|
108
|
-
entry_point="
|
108
|
+
entry_point="gr_envs.minigrid_scripts.envs:CustomColorEnv",
|
109
109
|
kwargs={"size": 13 if 'Simple' in problem_name else 9,
|
110
110
|
"num_crossings": 4 if 'Simple' in problem_name else 3,
|
111
111
|
"goal_pos": self.str_to_goal(problem_name),
|
@@ -5,7 +5,6 @@ import numpy as np
|
|
5
5
|
|
6
6
|
from typing import Callable, Generator, List, Dict, Tuple, Any
|
7
7
|
from math import log2
|
8
|
-
from numpy.core.fromnumeric import mean
|
9
8
|
from scipy.stats import wasserstein_distance
|
10
9
|
from gymnasium.spaces.discrete import Discrete
|
11
10
|
# import torch
|
@@ -43,7 +42,7 @@ def kl_divergence_norm_softmax(observations: List[Tuple[State, Any]], agent, act
|
|
43
42
|
qp2_flatten_distribution_list: List[float] = agent.get_actions_probabilities(
|
44
43
|
observation=(observation, agent_pos))
|
45
44
|
distances.append(kl_divergence(qp1, qp2_flatten_distribution_list))
|
46
|
-
return mean(distances)
|
45
|
+
return np.mean(distances)
|
47
46
|
|
48
47
|
|
49
48
|
def amplify(values, alpha=1.0):
|
@@ -351,7 +351,7 @@ class TabularQLearner(TabularRLAgent):
|
|
351
351
|
def simplify_observation(self, observation):
|
352
352
|
return [(obs['direction'], agent_pos_x, agent_pos_y, action) for ((obs, (agent_pos_x, agent_pos_y)), action) in observation] # list of tuples, each tuple the sample
|
353
353
|
|
354
|
-
def generate_observation(self, action_selection_method: MethodType, random_optimalism, save_fig
|
354
|
+
def generate_observation(self, action_selection_method: MethodType, random_optimalism, save_fig=False, fig_path: str=None, env_prop=None):
|
355
355
|
"""
|
356
356
|
Generate a single observation given a list of agents
|
357
357
|
|
@@ -15,6 +15,13 @@ def get_storage_framework_dir(recognizer: str):
|
|
15
15
|
return os.path.join(get_storage_dir(),recognizer)
|
16
16
|
|
17
17
|
def get_storage_dir():
|
18
|
+
# Prefer local directory if it exists (e.g., in GitHub workspace)
|
19
|
+
if os.path.exists("dataset"):
|
20
|
+
return "dataset"
|
21
|
+
# Fall back to pre-mounted directory (e.g., in Docker container)
|
22
|
+
if os.path.exists("/preloaded_data"):
|
23
|
+
return "/preloaded_data"
|
24
|
+
# Default to "dataset" even if it doesn't exist (e.g., will be created)
|
18
25
|
return "dataset"
|
19
26
|
|
20
27
|
def _get_models_directory_name():
|
File without changes
|
@@ -82,14 +82,14 @@ class Graml(LearningRecognizer):
|
|
82
82
|
dev_loader=DataLoader(dev_dataset, batch_size=self.env_prop.get_lstm_props().batch_size, shuffle=False, collate_fn=self.collate_func))
|
83
83
|
save_weights(model=self.model, path=self.model_file_path)
|
84
84
|
|
85
|
-
def goals_adaptation_phase(self, dynamic_goals: List[EnvProperty]):
|
85
|
+
def goals_adaptation_phase(self, dynamic_goals: List[EnvProperty], save_fig=False):
|
86
86
|
self.is_first_inf_since_new_goals = True
|
87
87
|
self.current_goals = dynamic_goals
|
88
88
|
# start by training each rl agent on the base goal set
|
89
89
|
self.embeddings_dict = {} # relevant if the embedding of the plan occurs during the goals adaptation phase
|
90
90
|
self.plans_dict = {} # relevant if the embedding of the plan occurs during the inference phase
|
91
91
|
for goal in self.current_goals:
|
92
|
-
obss = self.generate_sequences_library(goal)
|
92
|
+
obss = self.generate_sequences_library(goal, save_fig=save_fig)
|
93
93
|
self.plans_dict[str(goal)] = obss
|
94
94
|
|
95
95
|
def get_goal_plan(self, goal):
|
@@ -150,7 +150,7 @@ class Graml(LearningRecognizer):
|
|
150
150
|
return closest_goal
|
151
151
|
|
152
152
|
@abstractmethod
|
153
|
-
def generate_sequences_library(self, goal: str) -> List[List[Tuple[np.ndarray, np.ndarray]]]:
|
153
|
+
def generate_sequences_library(self, goal: str, save_fig=False) -> List[List[Tuple[np.ndarray, np.ndarray]]]:
|
154
154
|
pass
|
155
155
|
|
156
156
|
# this function duplicates every sequence and creates a consecutive and non-consecutive version of it
|
@@ -192,10 +192,10 @@ class MCTSBasedGraml(BGGraml, GaAdaptingRecognizer):
|
|
192
192
|
super().__init__(*args, **kwargs)
|
193
193
|
if self.rl_agent_type==None: self.rl_agent_type = TabularQLearner
|
194
194
|
|
195
|
-
def generate_sequences_library(self, goal: str) -> List[List[Tuple[np.ndarray, np.ndarray]]]:
|
195
|
+
def generate_sequences_library(self, goal: str, save_fig=False) -> List[List[Tuple[np.ndarray, np.ndarray]]]:
|
196
196
|
problem_name = self.env_prop.goal_to_problem_str(goal)
|
197
197
|
img_path = os.path.join(get_policy_sequences_result_path(self.env_prop.domain_name, recognizer=self.__class__.__name__), problem_name + "_MCTS")
|
198
|
-
return mcts_model.plan(self.env_prop.name, problem_name, goal, save_fig=
|
198
|
+
return mcts_model.plan(self.env_prop.name, problem_name, goal, save_fig=save_fig, img_path=img_path, env_prop=self.env_prop)
|
199
199
|
|
200
200
|
class ExpertBasedGraml(BGGraml, GaAgentTrainerRecognizer):
|
201
201
|
def __init__(self, *args, **kwargs):
|
@@ -206,15 +206,23 @@ class ExpertBasedGraml(BGGraml, GaAgentTrainerRecognizer):
|
|
206
206
|
else:
|
207
207
|
self.rl_agent_type = DeepRLAgent
|
208
208
|
|
209
|
-
def generate_sequences_library(self, goal: str) -> List[List[Tuple[np.ndarray, np.ndarray]]]:
|
209
|
+
def generate_sequences_library(self, goal: str, save_fig=False) -> List[List[Tuple[np.ndarray, np.ndarray]]]:
|
210
210
|
problem_name = self.env_prop.goal_to_problem_str(goal)
|
211
211
|
kwargs = {"domain_name":self.domain_name, "problem_name":problem_name}
|
212
212
|
if self.dynamic_train_configs_dict[problem_name][0] != None: kwargs["algorithm"] = self.dynamic_train_configs_dict[problem_name][0]
|
213
213
|
if self.dynamic_train_configs_dict[problem_name][1] != None: kwargs["num_timesteps"] = self.dynamic_train_configs_dict[problem_name][1]
|
214
214
|
agent = self.rl_agent_type(**kwargs)
|
215
215
|
agent.learn()
|
216
|
-
|
217
|
-
|
216
|
+
agent_kwargs = {
|
217
|
+
"action_selection_method": metrics.greedy_selection,
|
218
|
+
"random_optimalism": False,
|
219
|
+
"save_fig": save_fig,
|
220
|
+
"env_prop": self.env_prop
|
221
|
+
}
|
222
|
+
if save_fig:
|
223
|
+
fig_path = get_and_create(f"{os.path.abspath(os.path.join(get_policy_sequences_result_path(domain_name=self.env_prop.domain_name, env_name=self.env_prop.name, recognizer=self.__class__.__name__), problem_name))}_bg_sequence")
|
224
|
+
agent_kwargs["fig_path"] = fig_path
|
225
|
+
return [agent.generate_observation(**agent_kwargs)]
|
218
226
|
|
219
227
|
def goals_adaptation_phase(self, dynamic_goals: List[str], dynamic_train_configs):
|
220
228
|
self.dynamic_goals_problems = [self.env_prop.goal_to_problem_str(g) for g in dynamic_goals]
|
@@ -244,20 +252,21 @@ class GCGraml(Graml, GaAdaptingRecognizer):
|
|
244
252
|
gc_agent.learn()
|
245
253
|
self.agents.append(ContextualAgent(problem_name=self.env_prop.name, problem_goal="general", agent=gc_agent))
|
246
254
|
|
247
|
-
def generate_sequences_library(self, goal: str) -> List[List[Tuple[np.ndarray, np.ndarray]]]:
|
255
|
+
def generate_sequences_library(self, goal: str, save_fig=False) -> List[List[Tuple[np.ndarray, np.ndarray]]]:
|
248
256
|
problem_name = self.env_prop.goal_to_problem_str(goal)
|
249
257
|
kwargs = {"domain_name":self.domain_name, "problem_name":self.env_prop.name} # problem name is env name in gc case
|
250
258
|
if self.original_train_configs[0][0] != None: kwargs["algorithm"] = self.original_train_configs[0][0]
|
251
259
|
if self.original_train_configs[0][1] != None: kwargs["num_timesteps"] = self.original_train_configs[0][1]
|
252
260
|
agent = self.rl_agent_type(**kwargs)
|
253
261
|
agent.learn()
|
254
|
-
fig_path = get_and_create(f"{os.path.abspath(os.path.join(get_policy_sequences_result_path(domain_name=self.env_prop.domain_name, env_name=self.env_prop.name, recognizer=self.__class__.__name__), problem_name))}_gc_sequence")
|
255
262
|
agent_kwargs = {
|
256
263
|
"action_selection_method": metrics.stochastic_amplified_selection,
|
257
264
|
"random_optimalism": True,
|
258
|
-
"save_fig":
|
259
|
-
"fig_path": fig_path
|
265
|
+
"save_fig": save_fig
|
260
266
|
}
|
267
|
+
if save_fig:
|
268
|
+
fig_path = get_and_create(f"{os.path.abspath(os.path.join(get_policy_sequences_result_path(domain_name=self.env_prop.domain_name, env_name=self.env_prop.name, recognizer=self.__class__.__name__), problem_name))}_gc_sequence")
|
269
|
+
agent_kwargs["fig_path"] = fig_path
|
261
270
|
if self.env_prop.use_goal_directed_problem(): agent_kwargs["goal_directed_problem"] = problem_name
|
262
271
|
else: agent_kwargs["goal_directed_goal"] = goal
|
263
272
|
obss = []
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: gr_libs
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.7.post0
|
4
4
|
Summary: Package with goal recognition frameworks baselines
|
5
5
|
Author: Ben Nageris
|
6
6
|
Author-email: Matan Shamir <matan.shamir@live.biu.ac.il>, Osher Elhadad <osher.elhadad@live.biu.ac.il>
|
@@ -17,6 +17,7 @@ Requires-Dist: torchvision
|
|
17
17
|
Requires-Dist: rl_zoo3
|
18
18
|
Requires-Dist: stable_baselines3[extra]
|
19
19
|
Requires-Dist: sb3_contrib
|
20
|
+
Requires-Dist: pytest
|
20
21
|
Provides-Extra: minigrid
|
21
22
|
Requires-Dist: gr_envs[minigrid]; extra == "minigrid"
|
22
23
|
Provides-Extra: highway
|
@@ -111,6 +112,25 @@ After installing GRLib, you will have access to custom Gym environments, allowin
|
|
111
112
|
|
112
113
|
Tutorials demonstrating basic ODGR scenarios is available in the sub-package `tutorials`. These tutorials walk through the initialization and deployment process, showcasing how different GR algorithms adapt to emerging goals in various Gym environments.
|
113
114
|
|
115
|
+
## Working with an initial dataset of trained agents
|
116
|
+
gr_libs also includes a library of trained agents for the various supported environments within the package.
|
117
|
+
To get the dataset of trained agents, you can run:
|
118
|
+
```sh
|
119
|
+
python download_dataset.py
|
120
|
+
```
|
121
|
+
|
122
|
+
An alternative is to use our docker image, which includes the dataset in it.
|
123
|
+
You can:
|
124
|
+
1. pull the image:
|
125
|
+
```sh
|
126
|
+
docker pull ghcr.io/MatanShamir1/gr_test_base:latest
|
127
|
+
```
|
128
|
+
2. run a container:
|
129
|
+
```sh
|
130
|
+
docker run -it ghcr.io/MatanShamir1/gr_test_base:latest bash
|
131
|
+
```
|
132
|
+
3. don't forget to install the package from within the container, go back to 'Setup' for that.
|
133
|
+
|
114
134
|
### Method 1: Writing a Custom Script
|
115
135
|
|
116
136
|
1. **Create a recognizer**
|
@@ -118,6 +138,7 @@ Tutorials demonstrating basic ODGR scenarios is available in the sub-package `tu
|
|
118
138
|
Specify the domain name and specific environment for the recognizer, effectively telling it the domain theory - the collection of states and actions in the environment.
|
119
139
|
|
120
140
|
```python
|
141
|
+
import gr_libs.environment # Triggers gym env registration - you must run it!
|
121
142
|
recognizer = Graql(
|
122
143
|
domain_name="minigrid",
|
123
144
|
env_name="MiniGrid-SimpleCrossingS13N4"
|
@@ -1,10 +1,5 @@
|
|
1
|
-
.gitignore
|
2
1
|
README.md
|
3
|
-
all_experiments.py
|
4
|
-
consts.py
|
5
|
-
odgr_executor.py
|
6
2
|
pyproject.toml
|
7
|
-
.github/workflows/release.yml
|
8
3
|
evaluation/analyze_results_cross_alg_cross_domain.py
|
9
4
|
evaluation/create_minigrid_map_image.py
|
10
5
|
evaluation/file_system.py
|
@@ -15,6 +10,7 @@ evaluation/generate_task_specific_statistics_plots.py
|
|
15
10
|
evaluation/get_plans_images.py
|
16
11
|
evaluation/increasing_and_decreasing_.py
|
17
12
|
gr_libs/__init__.py
|
13
|
+
gr_libs/_version.py
|
18
14
|
gr_libs.egg-info/PKG-INFO
|
19
15
|
gr_libs.egg-info/SOURCES.txt
|
20
16
|
gr_libs.egg-info/dependency_links.txt
|
@@ -54,9 +50,10 @@ gr_libs/ml/utils/format.py
|
|
54
50
|
gr_libs/ml/utils/math.py
|
55
51
|
gr_libs/ml/utils/other.py
|
56
52
|
gr_libs/ml/utils/storage.py
|
53
|
+
gr_libs/problems/__init__.py
|
54
|
+
gr_libs/problems/consts.py
|
57
55
|
gr_libs/recognizer/__init__.py
|
58
56
|
gr_libs/recognizer/recognizer.py
|
59
|
-
gr_libs/recognizer/recognizer_doc.md
|
60
57
|
gr_libs/recognizer/gr_as_rl/__init__.py
|
61
58
|
gr_libs/recognizer/gr_as_rl/gr_as_rl_recognizer.py
|
62
59
|
gr_libs/recognizer/graml/__init__.py
|
@@ -64,6 +61,8 @@ gr_libs/recognizer/graml/gr_dataset.py
|
|
64
61
|
gr_libs/recognizer/graml/graml_recognizer.py
|
65
62
|
gr_libs/recognizer/utils/__init__.py
|
66
63
|
gr_libs/recognizer/utils/format.py
|
64
|
+
tests/test_graml.py
|
65
|
+
tests/test_graql.py
|
67
66
|
tutorials/graml_minigrid_tutorial.py
|
68
67
|
tutorials/graml_panda_tutorial.py
|
69
68
|
tutorials/graml_parking_tutorial.py
|
@@ -22,7 +22,8 @@ dependencies = [
|
|
22
22
|
"torchvision",
|
23
23
|
"rl_zoo3",
|
24
24
|
"stable_baselines3[extra]",
|
25
|
-
"sb3_contrib"
|
25
|
+
"sb3_contrib",
|
26
|
+
"pytest"
|
26
27
|
]
|
27
28
|
classifiers = [
|
28
29
|
"Programming Language :: Python :: 3",
|
@@ -42,3 +43,4 @@ packages = {find = {}}
|
|
42
43
|
[tool.setuptools_scm]
|
43
44
|
version_scheme = "post-release"
|
44
45
|
local_scheme = "node-and-date"
|
46
|
+
write_to = "gr_libs/_version.py" # This line writes the version to a file within the package
|
@@ -0,0 +1,16 @@
|
|
1
|
+
from tutorials.graml_minigrid_tutorial import run_graml_minigrid_tutorial
|
2
|
+
from tutorials.graml_panda_tutorial import run_graml_panda_tutorial
|
3
|
+
from tutorials.graml_parking_tutorial import run_graml_parking_tutorial
|
4
|
+
from tutorials.graml_point_maze_tutorial import run_graml_point_maze_tutorial
|
5
|
+
|
6
|
+
def test_graml_minigrid_tutorial():
|
7
|
+
run_graml_minigrid_tutorial()
|
8
|
+
|
9
|
+
def test_graml_panda_tutorial():
|
10
|
+
run_graml_panda_tutorial()
|
11
|
+
|
12
|
+
def test_graml_parking_tutorial():
|
13
|
+
run_graml_parking_tutorial()
|
14
|
+
|
15
|
+
def test_graml_point_maze_tutorial():
|
16
|
+
run_graml_point_maze_tutorial()
|
@@ -0,0 +1,34 @@
|
|
1
|
+
from gr_libs.environment.environment import MINIGRID, QLEARNING
|
2
|
+
from gr_libs.metrics.metrics import stochastic_amplified_selection
|
3
|
+
from gr_libs.ml.tabular.tabular_q_learner import TabularQLearner
|
4
|
+
from gr_libs.ml.utils.format import random_subset_with_order
|
5
|
+
from gr_libs import ExpertBasedGraml
|
6
|
+
|
7
|
+
def run_graml_minigrid_tutorial():
|
8
|
+
recognizer = ExpertBasedGraml(
|
9
|
+
domain_name=MINIGRID,
|
10
|
+
env_name="MiniGrid-SimpleCrossingS13N4"
|
11
|
+
)
|
12
|
+
|
13
|
+
recognizer.domain_learning_phase(base_goals=[(11,1), (11,11), (1,11), (7,11), (8,1), (10,6), (6,9), (11,3), (11,5)],
|
14
|
+
train_configs=[(QLEARNING, 100000) for _ in range(9)])
|
15
|
+
|
16
|
+
recognizer.goals_adaptation_phase(
|
17
|
+
dynamic_goals = [(11,1), (11,11), (1,11)],
|
18
|
+
dynamic_train_configs=[(QLEARNING, 100000) for _ in range(3)] # for expert sequence generation.
|
19
|
+
)
|
20
|
+
# TD3 is different from recognizer and expert algorithms, which are SAC #
|
21
|
+
actor = TabularQLearner(domain_name="minigrid", problem_name="MiniGrid-SimpleCrossingS13N4-DynamicGoal-11x1-v0", algorithm=QLEARNING, num_timesteps=100000)
|
22
|
+
actor.learn()
|
23
|
+
# sample is generated stochastically to simulate suboptimal behavior, noise is added to the actions values #
|
24
|
+
full_sequence = actor.generate_observation(
|
25
|
+
action_selection_method=stochastic_amplified_selection,
|
26
|
+
random_optimalism=True, # the noise that's added to the actions
|
27
|
+
)
|
28
|
+
|
29
|
+
partial_sequence = random_subset_with_order(full_sequence, (int)(0.5 * len(full_sequence)), is_consecutive=False)
|
30
|
+
closest_goal = recognizer.inference_phase(partial_sequence, (11,1), 0.5)
|
31
|
+
print(f"closest_goal returned by GRAML: {closest_goal}\nactual goal actor aimed towards: (11, 1)")
|
32
|
+
|
33
|
+
if __name__ == "__main__":
|
34
|
+
run_graml_minigrid_tutorial()
|
@@ -0,0 +1,41 @@
|
|
1
|
+
|
2
|
+
import numpy as np
|
3
|
+
from stable_baselines3 import PPO, SAC
|
4
|
+
import gr_libs.environment.environment
|
5
|
+
from gr_libs.environment.environment import PANDA, EnvProperty, GCEnvProperty, PandaProperty
|
6
|
+
from gr_libs.environment.utils.utils import domain_to_env_property
|
7
|
+
from gr_libs.metrics.metrics import stochastic_amplified_selection
|
8
|
+
from gr_libs.ml.neural.deep_rl_learner import DeepRLAgent, GCDeepRLAgent
|
9
|
+
from gr_libs.ml.utils.format import random_subset_with_order
|
10
|
+
from gr_libs import GCGraml
|
11
|
+
|
12
|
+
def run_graml_panda_tutorial():
|
13
|
+
recognizer = GCGraml( # TODO make these tutorials into pytests
|
14
|
+
domain_name=PANDA,
|
15
|
+
env_name="PandaMyReachDense"
|
16
|
+
)
|
17
|
+
recognizer.domain_learning_phase(
|
18
|
+
base_goals=[np.array([PandaProperty.sample_goal()]) for _ in range(1,30)],
|
19
|
+
train_configs=[(SAC, 800000)]
|
20
|
+
)
|
21
|
+
recognizer.goals_adaptation_phase(
|
22
|
+
dynamic_goals=[np.array([[-0.1, -0.1, 0.1]]), np.array([[-0.1, 0.1, 0.1]]), np.array([[0.2, 0.2, 0.1]])]
|
23
|
+
)
|
24
|
+
# TD3 is different from recognizer and expert algorithms, which are SAC #
|
25
|
+
property_type = domain_to_env_property(PANDA)
|
26
|
+
env_property = property_type("PandaMyReachDense")
|
27
|
+
problem_name = env_property.goal_to_problem_str(np.array([[-0.1, -0.1, 0.1]]))
|
28
|
+
actor = DeepRLAgent(domain_name=PANDA, problem_name=problem_name, algorithm=PPO, num_timesteps=400000)
|
29
|
+
actor.learn()
|
30
|
+
# sample is generated stochastically to simulate suboptimal behavior, noise is added to the actions values #
|
31
|
+
full_sequence = actor.generate_observation(
|
32
|
+
action_selection_method=stochastic_amplified_selection,
|
33
|
+
random_optimalism=True, # the noise that's added to the actions
|
34
|
+
)
|
35
|
+
|
36
|
+
partial_sequence = random_subset_with_order(full_sequence, (int)(0.5 * len(full_sequence)), is_consecutive=False)
|
37
|
+
closest_goal = recognizer.inference_phase(partial_sequence, np.array([[-0.1, -0.1, 0.1]]), 0.5)
|
38
|
+
print(f"closest_goal returned by GRAML: {closest_goal}\nactual goal actor aimed towards: [-0.1, -0.1, 0.1]")
|
39
|
+
|
40
|
+
if __name__ == "__main__":
|
41
|
+
run_graml_panda_tutorial()
|
@@ -0,0 +1,39 @@
|
|
1
|
+
|
2
|
+
from stable_baselines3 import PPO, SAC, TD3
|
3
|
+
from gr_libs.environment.environment import PARKING, EnvProperty, GCEnvProperty, ParkingProperty
|
4
|
+
from gr_libs.metrics.metrics import stochastic_amplified_selection
|
5
|
+
from gr_libs.ml.neural.deep_rl_learner import DeepRLAgent, GCDeepRLAgent
|
6
|
+
from gr_libs.ml.utils.format import random_subset_with_order
|
7
|
+
from gr_libs.recognizer.graml.graml_recognizer import ExpertBasedGraml, GCGraml
|
8
|
+
import gr_libs.environment.environment
|
9
|
+
|
10
|
+
def run_graml_parking_tutorial():
|
11
|
+
recognizer = GCGraml(
|
12
|
+
domain_name=PARKING,
|
13
|
+
env_name="Parking-S-14-PC-"
|
14
|
+
)
|
15
|
+
|
16
|
+
recognizer.domain_learning_phase(
|
17
|
+
[i for i in range(1,21)],
|
18
|
+
[(PPO, 200000)]
|
19
|
+
)
|
20
|
+
recognizer.goals_adaptation_phase(
|
21
|
+
dynamic_goals = ["1", "11", "21"]
|
22
|
+
# no need for expert sequence generation since GCRL is used
|
23
|
+
)
|
24
|
+
|
25
|
+
# TD3 is different from recognizer and expert algorithms, which are SAC #
|
26
|
+
actor = DeepRLAgent(domain_name="parking", problem_name="Parking-S-14-PC--GI-11-v0", algorithm=TD3, num_timesteps=400000)
|
27
|
+
actor.learn()
|
28
|
+
# sample is generated stochastically to simulate suboptimal behavior, noise is added to the actions values #
|
29
|
+
full_sequence = actor.generate_observation(
|
30
|
+
action_selection_method=stochastic_amplified_selection,
|
31
|
+
random_optimalism=True, # the noise that's added to the actions
|
32
|
+
)
|
33
|
+
|
34
|
+
partial_sequence = random_subset_with_order(full_sequence, (int)(0.5 * len(full_sequence)), is_consecutive=False)
|
35
|
+
closest_goal = recognizer.inference_phase(partial_sequence, ParkingProperty("Parking-S-14-PC--GI-11-v0").str_to_goal(), 0.5)
|
36
|
+
print(f"closest_goal returned by GRAML: {closest_goal}\nactual goal actor aimed towards: 11")
|
37
|
+
|
38
|
+
if __name__ == "__main__":
|
39
|
+
run_graml_parking_tutorial()
|
@@ -0,0 +1,39 @@
|
|
1
|
+
|
2
|
+
from stable_baselines3 import SAC, TD3
|
3
|
+
from gr_libs.environment.environment import POINT_MAZE, PointMazeProperty
|
4
|
+
from gr_libs.metrics.metrics import stochastic_amplified_selection
|
5
|
+
from gr_libs.ml.neural.deep_rl_learner import DeepRLAgent
|
6
|
+
from gr_libs.ml.utils.format import random_subset_with_order
|
7
|
+
from gr_libs.recognizer.graml.graml_recognizer import ExpertBasedGraml
|
8
|
+
|
9
|
+
def run_graml_point_maze_tutorial():
|
10
|
+
recognizer = ExpertBasedGraml(
|
11
|
+
domain_name=POINT_MAZE,
|
12
|
+
env_name="PointMaze-FourRoomsEnvDense-11x11"
|
13
|
+
)
|
14
|
+
|
15
|
+
recognizer.domain_learning_phase(
|
16
|
+
[(9,1), (9,9), (1,9), (3,3), (3,4), (8,2), (3,7), (2,8)],
|
17
|
+
[(SAC, 200000) for _ in range(8)]
|
18
|
+
)
|
19
|
+
|
20
|
+
recognizer.goals_adaptation_phase(
|
21
|
+
dynamic_goals = [(4,4), (7,3), (3,7)],
|
22
|
+
dynamic_train_configs=[(SAC, 200000) for _ in range(3)] # for expert sequence generation.
|
23
|
+
)
|
24
|
+
|
25
|
+
# TD3 is different from recognizer and expert algorithms, which are SAC #
|
26
|
+
actor = DeepRLAgent(domain_name="point_maze", problem_name="PointMaze-FourRoomsEnvDense-11x11-Goal-4x4", algorithm=TD3, num_timesteps=200000)
|
27
|
+
actor.learn()
|
28
|
+
# sample is generated stochastically to simulate suboptimal behavior, noise is added to the actions values #
|
29
|
+
full_sequence = actor.generate_observation(
|
30
|
+
action_selection_method=stochastic_amplified_selection,
|
31
|
+
random_optimalism=True, # the noise that's added to the actions
|
32
|
+
)
|
33
|
+
|
34
|
+
partial_sequence = random_subset_with_order(full_sequence, (int)(0.5 * len(full_sequence)))
|
35
|
+
closest_goal = recognizer.inference_phase(partial_sequence, PointMazeProperty("PointMaze-FourRoomsEnvDense-11x11-Goal-4x4").str_to_goal(), 0.5)
|
36
|
+
print(f"closest_goal returned by GRAML: {closest_goal}\nactual goal actor aimed towards: (4, 4)")
|
37
|
+
|
38
|
+
if __name__ == "__main__":
|
39
|
+
run_graml_point_maze_tutorial()
|
@@ -0,0 +1,34 @@
|
|
1
|
+
from gr_libs.environment.environment import QLEARNING
|
2
|
+
from gr_libs.metrics.metrics import stochastic_amplified_selection
|
3
|
+
from gr_libs.ml.tabular.tabular_q_learner import TabularQLearner
|
4
|
+
from gr_libs.ml.utils.format import random_subset_with_order
|
5
|
+
from gr_libs import Graql
|
6
|
+
|
7
|
+
def run_graql_minigrid_tutorial():
|
8
|
+
recognizer = Graql(
|
9
|
+
domain_name="minigrid",
|
10
|
+
env_name="MiniGrid-SimpleCrossingS13N4"
|
11
|
+
)
|
12
|
+
|
13
|
+
#Graql doesn't have a domain learning phase, so we skip it
|
14
|
+
|
15
|
+
recognizer.goals_adaptation_phase(
|
16
|
+
dynamic_goals = [(11,1), (11,11), (1,11)],
|
17
|
+
dynamic_train_configs=[(QLEARNING, 100000) for _ in range(3)] # for expert sequence generation.
|
18
|
+
)
|
19
|
+
# TD3 is different from recognizer and expert algorithms, which are SAC #
|
20
|
+
actor = TabularQLearner(domain_name="minigrid", problem_name="MiniGrid-SimpleCrossingS13N4-DynamicGoal-11x1-v0", algorithm=QLEARNING, num_timesteps=100000)
|
21
|
+
actor.learn()
|
22
|
+
# sample is generated stochastically to simulate suboptimal behavior, noise is added to the actions values #
|
23
|
+
full_sequence = actor.generate_observation(
|
24
|
+
action_selection_method=stochastic_amplified_selection,
|
25
|
+
random_optimalism=True, # the noise that's added to the actions
|
26
|
+
)
|
27
|
+
|
28
|
+
partial_sequence = random_subset_with_order(full_sequence, (int)(0.5 * len(full_sequence)), is_consecutive=False)
|
29
|
+
closest_goal = recognizer.inference_phase(partial_sequence, (11,1), 0.5)
|
30
|
+
print(f"closest_goal returned by Graql: {closest_goal}\nactual goal actor aimed towards: (11, 1)")
|
31
|
+
return closest_goal, (11,1)
|
32
|
+
|
33
|
+
if __name__ == "__main__":
|
34
|
+
run_graql_minigrid_tutorial()
|
@@ -1,32 +0,0 @@
|
|
1
|
-
name: Publish to PyPI
|
2
|
-
|
3
|
-
on:
|
4
|
-
push:
|
5
|
-
tags:
|
6
|
-
- "v*"
|
7
|
-
|
8
|
-
jobs:
|
9
|
-
build-and-publish:
|
10
|
-
runs-on: ubuntu-latest
|
11
|
-
|
12
|
-
steps:
|
13
|
-
- name: Check out the repository
|
14
|
-
uses: actions/checkout@v4
|
15
|
-
|
16
|
-
- name: Set up Python
|
17
|
-
uses: actions/setup-python@v4
|
18
|
-
with:
|
19
|
-
python-version: "3.11"
|
20
|
-
|
21
|
-
- name: Install build dependencies
|
22
|
-
run: |
|
23
|
-
python -m pip install --upgrade pip
|
24
|
-
pip install build twine
|
25
|
-
|
26
|
-
- name: Build the package
|
27
|
-
run: python -m build # Uses pyproject.toml instead of setup.py
|
28
|
-
|
29
|
-
- name: Publish to PyPI
|
30
|
-
env:
|
31
|
-
PYPY_API_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
|
32
|
-
run: python -m twine upload dist/* -u __token__ -p $PYPY_API_TOKEN
|