diff --git a/.dockerignore b/.dockerignore index a4a9eef..ad5f338 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,2 +1,4 @@ **/soil_output .* +__pycache__ +*.pyc diff --git a/CHANGELOG.md b/CHANGELOG.md index 0eacd81..9ab7ee2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.14.6] +### Fixed +* Bug with newer versions of networkx (0.24) where the Graph.node attribute has been removed. We have updated our calls, but the code in nxsim is not under our control, so we have pinned the networkx version until that issue is solved. +### Changed +* Explicit yaml.SafeLoader to avoid deprecation warnings when using yaml.load. It should not break any existing setups, but we could move to the FullLoader in the future if needed. + ## [0.14.4] ### Fixed * Bug in `agent.get_agents()` when `state_id` is passed as a string. The tests have been modified accordingly. diff --git a/requirements.txt b/requirements.txt index 6b278a0..ae7b426 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ nxsim>=0.1.2 simpy -networkx>=2.0 +networkx>=2.0,<2.4 numpy matplotlib pyyaml>=5.1 diff --git a/soil/VERSION b/soil/VERSION index 3393b5f..66fb941 100644 --- a/soil/VERSION +++ b/soil/VERSION @@ -1 +1 @@ -0.14.4 +0.14.6 \ No newline at end of file diff --git a/soil/analysis.py b/soil/analysis.py index 25e2782..4183a62 100644 --- a/soil/analysis.py +++ b/soil/analysis.py @@ -20,7 +20,7 @@ def _read_data(pattern, *args, from_csv=False, process_args=None, **kwargs): process_args = {} for folder in glob.glob(pattern): config_file = glob.glob(join(folder, '*.yml'))[0] - config = yaml.load(open(config_file)) + config = yaml.load(open(config_file), Loader=yaml.SafeLoader) df = None if from_csv: for trial_data in sorted(glob.glob(join(folder, @@ -133,7 +133,7 @@ def get_count(df, *keys): def get_value(df, *keys, aggfunc='sum'): if keys: df = df[list(keys)] - return df.groupby(axis=1, level=0).agg(aggfunc, axis=1) + return df.groupby(axis=1, level=0).agg(aggfunc) def plot_all(*args, **kwargs): diff --git a/soil/environment.py b/soil/environment.py index 1341ca7..a0b3d7d 100644 --- a/soil/environment.py +++ b/soil/environment.py @@ -87,7 +87,7 @@ class Environment(nxsim.NetworkEnvironment): @property def network_agents(self): for i in self.G.nodes(): - node = self.G.node[i] + node = self.G.nodes[i] if 'agent' in node: yield node['agent'] @@ -212,12 +212,12 @@ class Environment(nxsim.NetworkEnvironment): return self[key] if key in self else default def get_agent(self, agent_id): - return self.G.node[agent_id]['agent'] + return self.G.nodes[agent_id]['agent'] def get_agents(self, nodes=None): if nodes is None: return list(self.agents) - return [self.G.node[i]['agent'] for i in nodes] + return [self.G.nodes[i]['agent'] for i in nodes] def dump_csv(self, f): with utils.open_or_reuse(f, 'w') as f: @@ -231,9 +231,9 @@ class Environment(nxsim.NetworkEnvironment): # Workaround for geometric models # See soil/soil#4 for node in G.nodes(): - if 'pos' in G.node[node]: - G.node[node]['viz'] = {"position": {"x": G.node[node]['pos'][0], "y": G.node[node]['pos'][1], "z": 0.0}} - del (G.node[node]['pos']) + if 'pos' in G.nodes[node]: + G.nodes[node]['viz'] = {"position": {"x": G.nodes[node]['pos'][0], "y": G.nodes[node]['pos'][1], "z": 0.0}} + del (G.nodes[node]['pos']) nx.write_gexf(G, f, version="1.2draft") diff --git a/soil/web/__init__.py b/soil/web/__init__.py index 4586238..2339288 100644 --- a/soil/web/__init__.py +++ b/soil/web/__init__.py @@ -118,9 +118,9 @@ class SocketHandler(tornado.websocket.WebSocketHandler): elif msg['type'] == 'download_gexf': G = self.trials[ int(msg['data']) ].history_to_graph() for node in G.nodes(): - if 'pos' in G.node[node]: - G.node[node]['viz'] = {"position": {"x": G.node[node]['pos'][0], "y": G.node[node]['pos'][1], "z": 0.0}} - del (G.node[node]['pos']) + if 'pos' in G.nodes[node]: + G.nodes[node]['viz'] = {"position": {"x": G.nodes[node]['pos'][0], "y": G.nodes[node]['pos'][1], "z": 0.0}} + del (G.nodes[node]['pos']) writer = nx.readwrite.gexf.GEXFWriter(version='1.2draft') writer.add_graph(G) self.write_message({'type': 'download_gexf', @@ -130,9 +130,9 @@ class SocketHandler(tornado.websocket.WebSocketHandler): elif msg['type'] == 'download_json': G = self.trials[ int(msg['data']) ].history_to_graph() for node in G.nodes(): - if 'pos' in G.node[node]: - G.node[node]['viz'] = {"position": {"x": G.node[node]['pos'][0], "y": G.node[node]['pos'][1], "z": 0.0}} - del (G.node[node]['pos']) + if 'pos' in G.nodes[node]: + G.nodes[node]['viz'] = {"position": {"x": G.nodes[node]['pos'][0], "y": G.nodes[node]['pos'][1], "z": 0.0}} + del (G.nodes[node]['pos']) self.write_message({'type': 'download_json', 'filename': self.config['name'] + '_trial_' + str(msg['data']), 'data': nx.node_link_data(G) }) @@ -271,4 +271,4 @@ def main(): parser.add_argument('--verbose', '-v', help='verbose mode', action='store_true') args = parser.parse_args() - run(name=args.name, port=(args.port[0] if isinstance(args.port, list) else args.port), verbose=args.verbose) \ No newline at end of file + run(name=args.name, port=(args.port[0] if isinstance(args.port, list) else args.port), verbose=args.verbose) diff --git a/tests/test_main.py b/tests/test_main.py index cf3ddc9..28fd81f 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -186,7 +186,7 @@ class TestMain(TestCase): with utils.timer('serializing'): serial = s.to_yaml() with utils.timer('recovering'): - recovered = yaml.load(serial) + recovered = yaml.load(serial, Loader=yaml.SafeLoader) with utils.timer('deleting'): del recovered['topology'] assert config == recovered @@ -240,7 +240,7 @@ class TestMain(TestCase): env[0, 0, 'testvalue'] = 'start' env[0, 10, 'testvalue'] = 'finish' nG = env.history_to_graph() - values = nG.node[0]['attr_testvalue'] + values = nG.nodes[0]['attr_testvalue'] assert ('start', 0, 10) in values assert ('finish', 10, None) in values