Showing 14 of 122 files from the diff.
Other files ignored by Codecov
LICENSE has changed.
HISTORY.rst has changed.
.travis.yml has changed.
docs/packages.rst has changed.
docs/conf.py has changed.
.flake8 is new.
mesa/__init__.py has changed.
README.rst has changed.
CONTRIBUTING.rst has changed.
setup.py has changed.

@@ -29,10 +29,16 @@
Loading
29 29
30 30
31 31
    """
32 +
32 33
    package_includes = ["d3.min.js", "PieChartModule.js"]
33 34
34 -
    def __init__(self, fields, canvas_height=500, canvas_width=500,
35 -
    data_collector_name="datacollector"):
35 +
    def __init__(
36 +
        self,
37 +
        fields,
38 +
        canvas_height=500,
39 +
        canvas_width=500,
40 +
        data_collector_name="datacollector",
41 +
    ):
36 42
        """
37 43
        Create a new line chart visualization.
38 44
@@ -51,8 +57,7 @@
Loading
51 57
52 58
        fields_json = json.dumps(self.fields)
53 59
        new_element = "new PieChartModule({}, {}, {})"
54 -
        new_element = new_element.format(fields_json, canvas_width,
55 -
                                         canvas_height)
60 +
        new_element = new_element.format(fields_json, canvas_width, canvas_height)
56 61
        self.js_code = "elements.push(" + new_element + ");"
57 62
58 63
    def render(self, model):

@@ -58,10 +58,17 @@
Loading
58 58
        template: "canvas_module.html" stores the module's HTML template.
59 59
60 60
    """
61 +
61 62
    package_includes = ["GridDraw.js", "CanvasModule.js", "InteractionHandler.js"]
62 63
63 -
    def __init__(self, portrayal_method, grid_width, grid_height,
64 -
                 canvas_width=500, canvas_height=500):
64 +
    def __init__(
65 +
        self,
66 +
        portrayal_method,
67 +
        grid_width,
68 +
        grid_height,
69 +
        canvas_width=500,
70 +
        canvas_height=500,
71 +
    ):
65 72
        """ Instantiate a new CanvasGrid.
66 73
67 74
        Args:
@@ -78,9 +85,9 @@
Loading
78 85
        self.canvas_width = canvas_width
79 86
        self.canvas_height = canvas_height
80 87
81 -
        new_element = ("new CanvasModule({}, {}, {}, {})"
82 -
            .format(self.canvas_width, self.canvas_height,
83 -
                self.grid_width, self.grid_height))
88 +
        new_element = "new CanvasModule({}, {}, {}, {})".format(
89 +
            self.canvas_width, self.canvas_height, self.grid_width, self.grid_height
90 +
        )
84 91
85 92
        self.js_code = "elements.push(" + new_element + ");"
86 93

@@ -39,13 +39,20 @@
Loading
39 39
        template: "canvas_module.html" stores the module's HTML template.
40 40
41 41
    """
42 +
42 43
    package_includes = ["HexDraw.js", "CanvasHexModule.js", "InteractionHandler.js"]
43 44
    portrayal_method = None  # Portrayal function
44 45
    canvas_width = 500
45 46
    canvas_height = 500
46 47
47 -
    def __init__(self, portrayal_method, grid_width, grid_height,
48 -
                 canvas_width=500, canvas_height=500):
48 +
    def __init__(
49 +
        self,
50 +
        portrayal_method,
51 +
        grid_width,
52 +
        grid_height,
53 +
        canvas_width=500,
54 +
        canvas_height=500,
55 +
    ):
49 56
        """ Instantiate a new CanvasGrid.
50 57
51 58
        Args:
@@ -62,9 +69,9 @@
Loading
62 69
        self.canvas_width = canvas_width
63 70
        self.canvas_height = canvas_height
64 71
65 -
        new_element = ("new CanvasHexModule({}, {}, {}, {})"
66 -
            .format(self.canvas_width, self.canvas_height,
67 -
                self.grid_width, self.grid_height))
72 +
        new_element = "new CanvasHexModule({}, {}, {}, {})".format(
73 +
            self.canvas_width, self.canvas_height, self.grid_width, self.grid_height
74 +
        )
68 75
69 76
        self.js_code = "elements.push(" + new_element + ");"
70 77

@@ -3,42 +3,44 @@
Loading
3 3
import click
4 4
from subprocess import call
5 5
6 -
PROJECT_PATH = click.Path(exists=True, file_okay=False, dir_okay=True, resolve_path=True)
7 -
COOKIECUTTER_DIR = 'mesa/cookiecutter-mesa'
6 +
PROJECT_PATH = click.Path(
7 +
    exists=True, file_okay=False, dir_okay=True, resolve_path=True
8 +
)
9 +
COOKIECUTTER_DIR = "mesa/cookiecutter-mesa"
8 10
SCRIPTS_DIR = os.path.dirname(os.path.abspath(__file__))
9 -
COOKIECUTTER_PATH = os.path.join(os.path.dirname(SCRIPTS_DIR),
10 -
                                 COOKIECUTTER_DIR)
11 +
COOKIECUTTER_PATH = os.path.join(os.path.dirname(SCRIPTS_DIR), COOKIECUTTER_DIR)
11 12
12 13
13 14
@click.group()
14 15
def cli():
15 -
    'Manage Mesa projects'
16 +
    "Manage Mesa projects"
16 17
    pass
17 18
18 19
19 20
@cli.command()
20 -
@click.argument('project', type=PROJECT_PATH, default='.')
21 +
@click.argument("project", type=PROJECT_PATH, default=".")
21 22
def runserver(project):
22 -
    '''Run mesa project PROJECT
23 +
    """Run mesa project PROJECT
23 24
24 25
    PROJECT is the path to the directory containing `run.py`, or the current
25 26
    directory if not specified.
26 -
    '''
27 +
    """
27 28
    sys.path.insert(0, project)
28 29
    os.chdir(project)
29 30
30 31
    with open("run.py") as f:
31 -
        code = compile(f.read(), "run.py", 'exec')
32 +
        code = compile(f.read(), "run.py", "exec")
32 33
        exec(code, {}, {})
33 34
34 35
35 36
@click.command()
36 -
@click.option('--no-input', is_flag=True,
37 -
              help='Do not prompt user for custom mesa model input.')
37 +
@click.option(
38 +
    "--no-input", is_flag=True, help="Do not prompt user for custom mesa model input."
39 +
)
38 40
def startproject(no_input):
39 -
    args = ['cookiecutter', COOKIECUTTER_PATH]
41 +
    args = ["cookiecutter", COOKIECUTTER_PATH]
40 42
    if no_input:
41 -
        args.append('--no-input')
43 +
        args.append("--no-input")
42 44
    call(args)
43 45
44 46

@@ -146,15 +146,17 @@
Loading
146 146
    def _record_agents(self, model):
147 147
        """ Record agents data in a mapping of functions and agents. """
148 148
        rep_funcs = self.agent_reporters.values()
149 -
        if all([hasattr(rep, 'attribute_name') for rep in rep_funcs]):
150 -
            prefix = ['model.schedule.steps', 'unique_id']
149 +
        if all([hasattr(rep, "attribute_name") for rep in rep_funcs]):
150 +
            prefix = ["model.schedule.steps", "unique_id"]
151 151
            attributes = [func.attribute_name for func in rep_funcs]
152 152
            get_reports = attrgetter(*prefix + attributes)
153 153
        else:
154 +
154 155
            def get_reports(agent):
155 156
                prefix = (agent.model.schedule.steps, agent.unique_id)
156 157
                reports = tuple(rep(agent) for rep in rep_funcs)
157 158
                return prefix + reports
159 +
158 160
        agent_records = map(get_reports, model.schedule.agents)
159 161
        return agent_records
160 162
@@ -210,13 +212,11 @@
Loading
210 212
        columns for tick and agent_id.
211 213
212 214
        """
213 -
        all_records = itertools.chain.from_iterable(
214 -
            self._agent_records.values())
215 +
        all_records = itertools.chain.from_iterable(self._agent_records.values())
215 216
        rep_names = [rep_name for rep_name in self.agent_reporters]
216 217
217 218
        df = pd.DataFrame.from_records(
218 -
            data=all_records,
219 -
            columns=["Step", "AgentID"] + rep_names,
219 +
            data=all_records, columns=["Step", "AgentID"] + rep_names,
220 220
        )
221 221
        df = df.set_index(["Step", "AgentID"])
222 222
        return df

@@ -44,6 +44,7 @@
Loading
44 44
    (This is explicitly meant to replicate the scheduler in MASON).
45 45
46 46
    """
47 +
47 48
    def __init__(self, model: Model) -> None:
48 49
        """ Create a new, empty BaseScheduler. """
49 50
        self.model = model
@@ -109,6 +110,7 @@
Loading
109 110
    Assumes that all agents have a step(model) method.
110 111
111 112
    """
113 +
112 114
    def step(self) -> None:
113 115
        """ Executes the step of all agents, one at a time, in
114 116
        random order.
@@ -128,6 +130,7 @@
Loading
128 130
    apply them yet. advance() then applies the changes.
129 131
130 132
    """
133 +
131 134
    def step(self) -> None:
132 135
        """ Step all agents, then advance them. """
133 136
        agent_keys = list(self._agents.keys())
@@ -151,6 +154,7 @@
Loading
151 154
    increments of 1 / (# of stages), meaning that 1 step = 1 unit of time.
152 155
153 156
    """
157 +
154 158
    def __init__(
155 159
        self,
156 160
        model: Model,

@@ -12,19 +12,27 @@
Loading
12 12
class NetworkModule(VisualizationElement):
13 13
    package_includes = []
14 14
15 -
    def __init__(self, portrayal_method, canvas_height=500, canvas_width=500, library='sigma'):
16 -
        library_types = ['sigma', 'd3']
15 +
    def __init__(
16 +
        self, portrayal_method, canvas_height=500, canvas_width=500, library="sigma"
17 +
    ):
18 +
        library_types = ["sigma", "d3"]
17 19
        if library not in library_types:
18 -
            raise ValueError("Invalid javascript library type. Expected one of: %s" % library_types)
20 +
            raise ValueError(
21 +
                "Invalid javascript library type. Expected one of: %s" % library_types
22 +
            )
19 23
20 -
        NetworkModule.package_includes = ["NetworkModule_sigma.js", "sigma.min.js"] if library == 'sigma' else [
21 -
            "NetworkModule_d3.js", "d3.min.js"]
24 +
        NetworkModule.package_includes = (
25 +
            ["NetworkModule_sigma.js", "sigma.min.js"]
26 +
            if library == "sigma"
27 +
            else ["NetworkModule_d3.js", "d3.min.js"]
28 +
        )
22 29
23 30
        self.portrayal_method = portrayal_method
24 31
        self.canvas_height = canvas_height
25 32
        self.canvas_width = canvas_width
26 -
        new_element = ("new NetworkModule({}, {})".
27 -
                       format(self.canvas_width, self.canvas_height))
33 +
        new_element = "new NetworkModule({}, {})".format(
34 +
            self.canvas_width, self.canvas_height
35 +
        )
28 36
        self.js_code = "elements.push(" + new_element + ");"
29 37
30 38
    def render(self, model):

@@ -41,6 +41,7 @@
Loading
41 41
                    in the order they are added.
42 42
43 43
    """
44 +
44 45
    def __init__(self, model):
45 46
        """ Create a new Text Visualization object. """
46 47
        self.model = model
@@ -78,6 +79,7 @@
Loading
78 79
79 80
class TextData(TextElement):
80 81
    """ Prints the value of one particular variable from the base model. """
82 +
81 83
    def __init__(self, model, var_name):
82 84
        """ Create a new data renderer. """
83 85
        self.model = model
@@ -98,6 +100,7 @@
Loading
98 100
        grid: The underlying grid object.
99 101
100 102
    """
103 +
101 104
    grid = None
102 105
103 106
    def __init__(self, grid, converter):
@@ -119,8 +122,8 @@
Loading
119 122
            for x in range(self.grid.width):
120 123
                c = self.grid[y][x]
121 124
                if c is None:
122 -
                    viz += ' '
125 +
                    viz += " "
123 126
                else:
124 127
                    viz += self.converter(c)
125 -
            viz += '\n'
128 +
            viz += "\n"
126 129
        return viz

@@ -18,10 +18,13 @@
Loading
18 18
19 19
import numpy as np
20 20
21 -
from typing import Iterable, Iterator, List, Optional, Set, Tuple, Union
21 +
from typing import Any, Dict, Iterable, Iterator, List, Optional, Set, Tuple, Union
22 22
from .agent import Agent
23 +
23 24
Coordinate = Tuple[int, int]
24 25
GridContent = Union[Optional[Agent], Set[Agent]]
26 +
# used in ContinuousSpace
27 +
FloatCoordinate = Union[Tuple[float, float], np.ndarray]
25 28
26 29
27 30
def accept_tuple_argument(wrapped_function):
@@ -31,7 +34,7 @@
Loading
31 34
32 35
    """
33 36
34 -
    def wrapper(*args):
37 +
    def wrapper(*args: Any):
35 38
        if isinstance(args[1], tuple) and len(args[1]) == 2:
36 39
            return wrapped_function(args[0], [args[1]])
37 40
        else:
@@ -96,8 +99,7 @@
Loading
96 99
            self.grid.append(col)
97 100
98 101
        # Add all cells to the empties list.
99 -
        self.empties = set(itertools.product(
100 -
            *(range(self.width), range(self.height))))
102 +
        self.empties = set(itertools.product(*(range(self.width), range(self.height))))
101 103
102 104
    @staticmethod
103 105
    def default_val() -> None:
@@ -120,7 +122,9 @@
Loading
120 122
            for col in range(self.height):
121 123
                yield self.grid[row][col], row, col  # agent, x, y
122 124
123 -
    def neighbor_iter(self, pos: Coordinate, moore: bool = True) -> Iterator[GridContent]:
125 +
    def neighbor_iter(
126 +
        self, pos: Coordinate, moore: bool = True
127 +
    ) -> Iterator[GridContent]:
124 128
        """ Iterate over position neighbors.
125 129
126 130
        Args:
@@ -132,8 +136,13 @@
Loading
132 136
        neighborhood = self.iter_neighborhood(pos, moore=moore)
133 137
        return self.iter_cell_list_contents(neighborhood)
134 138
135 -
    def iter_neighborhood(self, pos: Coordinate, moore: bool,
136 -
                          include_center: bool = False, radius: int = 1) -> Iterator[Coordinate]:
139 +
    def iter_neighborhood(
140 +
        self,
141 +
        pos: Coordinate,
142 +
        moore: bool,
143 +
        include_center: bool = False,
144 +
        radius: int = 1,
145 +
    ) -> Iterator[Coordinate]:
137 146
        """ Return an iterator over cell coordinates that are in the
138 147
        neighborhood of a certain point.
139 148
@@ -164,7 +173,9 @@
Loading
164 173
                if not moore and abs(dx) + abs(dy) > radius:
165 174
                    continue
166 175
                # Skip if not a torus and new coords out of bounds.
167 -
                if not self.torus and (not (0 <= dx + x < self.width) or not (0 <= dy + y < self.height)):
176 +
                if not self.torus and (
177 +
                    not (0 <= dx + x < self.width) or not (0 <= dy + y < self.height)
178 +
                ):
168 179
                    continue
169 180
170 181
                px, py = self.torus_adj((x + dx, y + dy))
@@ -178,8 +189,13 @@
Loading
178 189
                    coordinates.add(coords)
179 190
                    yield coords
180 191
181 -
    def get_neighborhood(self, pos: Coordinate, moore: bool,
182 -
                         include_center: bool = False, radius: int = 1) -> List[Coordinate]:
192 +
    def get_neighborhood(
193 +
        self,
194 +
        pos: Coordinate,
195 +
        moore: bool,
196 +
        include_center: bool = False,
197 +
        radius: int = 1,
198 +
    ) -> List[Coordinate]:
183 199
        """ Return a list of cells that are in the neighborhood of a
184 200
        certain point.
185 201
@@ -201,8 +217,13 @@
Loading
201 217
        """
202 218
        return list(self.iter_neighborhood(pos, moore, include_center, radius))
203 219
204 -
    def iter_neighbors(self, pos: Coordinate, moore: bool,
205 -
                       include_center: bool = False, radius: int = 1) -> Iterator[GridContent]:
220 +
    def iter_neighbors(
221 +
        self,
222 +
        pos: Coordinate,
223 +
        moore: bool,
224 +
        include_center: bool = False,
225 +
        radius: int = 1,
226 +
    ) -> Iterator[GridContent]:
206 227
        """ Return an iterator over neighbors to a certain point.
207 228
208 229
        Args:
@@ -222,12 +243,16 @@
Loading
222 243
            (8 and 4 if not including the center).
223 244
224 245
        """
225 -
        neighborhood = self.iter_neighborhood(
226 -
            pos, moore, include_center, radius)
246 +
        neighborhood = self.iter_neighborhood(pos, moore, include_center, radius)
227 247
        return self.iter_cell_list_contents(neighborhood)
228 248
229 -
    def get_neighbors(self, pos: Coordinate, moore: bool,
230 -
                      include_center: bool = False, radius: int = 1) -> List[Coordinate]:
249 +
    def get_neighbors(
250 +
        self,
251 +
        pos: Coordinate,
252 +
        moore: bool,
253 +
        include_center: bool = False,
254 +
        radius: int = 1,
255 +
    ) -> List[Coordinate]:
231 256
        """ Return a list of neighbors to a certain point.
232 257
233 258
        Args:
@@ -247,8 +272,7 @@
Loading
247 272
            (8 and 4 if not including the center).
248 273
249 274
        """
250 -
        return list(self.iter_neighbors(
251 -
            pos, moore, include_center, radius))
275 +
        return list(self.iter_neighbors(pos, moore, include_center, radius))
252 276
253 277
    def torus_adj(self, pos: Coordinate) -> Coordinate:
254 278
        """ Convert coordinate, handling torus looping. """
@@ -269,7 +293,9 @@
Loading
269 293
        return x < 0 or x >= self.width or y < 0 or y >= self.height
270 294
271 295
    @accept_tuple_argument
272 -
    def iter_cell_list_contents(self, cell_list: Iterable[Coordinate]) -> Iterator[GridContent]:
296 +
    def iter_cell_list_contents(
297 +
        self, cell_list: Iterable[Coordinate]
298 +
    ) -> Iterator[GridContent]:
273 299
        """
274 300
        Args:
275 301
            cell_list: Array-like of (x, y) tuples, or single tuple.
@@ -278,11 +304,12 @@
Loading
278 304
            An iterator of the contents of the cells identified in cell_list
279 305
280 306
        """
281 -
        return (
282 -
            self[x][y] for x, y in cell_list if not self.is_cell_empty((x, y)))
307 +
        return (self[x][y] for x, y in cell_list if not self.is_cell_empty((x, y)))
283 308
284 309
    @accept_tuple_argument
285 -
    def get_cell_list_contents(self, cell_list: Iterable[Coordinate]) -> List[GridContent]:
310 +
    def get_cell_list_contents(
311 +
        self, cell_list: Iterable[Coordinate]
312 +
    ) -> List[GridContent]:
286 313
        """
287 314
        Args:
288 315
            cell_list: Array-like of (x, y) tuples, or single tuple.
@@ -351,11 +378,15 @@
Loading
351 378
        from warnings import warn
352 379
        import random
353 380
354 -
        warn(("`find_empty` is being phased out since it uses the global "
355 -
              "`random` instead of the model-level random-number generator. "
356 -
              "Consider replacing it with having a model or agent object "
357 -
              "explicitly pick one of the grid's list of empty cells."),
358 -
             DeprecationWarning)
381 +
        warn(
382 +
            (
383 +
                "`find_empty` is being phased out since it uses the global "
384 +
                "`random` instead of the model-level random-number generator. "
385 +
                "Consider replacing it with having a model or agent object "
386 +
                "explicitly pick one of the grid's list of empty cells."
387 +
            ),
388 +
            DeprecationWarning,
389 +
        )
359 390
360 391
        if self.exists_empty_cells():
361 392
            pos = random.choice(sorted(self.empties))
@@ -370,6 +401,7 @@
Loading
370 401
371 402
class SingleGrid(Grid):
372 403
    """ Grid where each cell contains exactly at most one object. """
404 +
373 405
    empties = set()  # type: Set[Coordinate]
374 406
375 407
    def __init__(self, width: int, height: int, torus: bool) -> None:
@@ -382,7 +414,9 @@
Loading
382 414
        """
383 415
        super().__init__(width, height, torus)
384 416
385 -
    def position_agent(self, agent, x="random", y="random"):
417 +
    def position_agent(
418 +
        self, agent: Agent, x: Union[int, str] = "random", y: Union[int, str] = "random"
419 +
    ) -> None:
386 420
        """ Position an agent on the grid.
387 421
        This is used when first placing agents! Use 'move_to_empty()'
388 422
        when you want agents to jump to an empty cell.
@@ -429,7 +463,7 @@
Loading
429 463
    """
430 464
431 465
    @staticmethod
432 -
    def default_val():
466 +
    def default_val() -> Set[Agent]:
433 467
        """ Default value for new cell elements. """
434 468
        return set()
435 469
@@ -447,7 +481,9 @@
Loading
447 481
            self.empties.add(pos)
448 482
449 483
    @accept_tuple_argument
450 -
    def iter_cell_list_contents(self, cell_list):
484 +
    def iter_cell_list_contents(
485 +
        self, cell_list: Iterable[Coordinate]
486 +
    ) -> Iterator[GridContent]:
451 487
        """
452 488
        Args:
453 489
            cell_list: Array-like of (x, y) tuples, or single tuple.
@@ -457,7 +493,8 @@
Loading
457 493
458 494
        """
459 495
        return itertools.chain.from_iterable(
460 -
            self[x][y] for x, y in cell_list if not self.is_cell_empty((x, y)))
496 +
            self[x][y] for x, y in cell_list if not self.is_cell_empty((x, y))
497 +
        )
461 498
462 499
463 500
class HexGrid(Grid):
@@ -479,8 +516,9 @@
Loading
479 516
480 517
    """
481 518
482 -
    def iter_neighborhood(self, pos,
483 -
                          include_center=False, radius=1):
519 +
    def iter_neighborhood(
520 +
        self, pos: Coordinate, include_center: bool = False, radius: int = 1
521 +
    ) -> Iterator[Coordinate]:
484 522
        """ Return an iterator over cell coordinates that are in the
485 523
        neighborhood of a certain point.
486 524
@@ -498,12 +536,12 @@
Loading
498 536
499 537
        """
500 538
501 -
        def torus_adj_2d(pos):
539 +
        def torus_adj_2d(pos: Coordinate) -> Coordinate:
502 540
            return (pos[0] % self.width, pos[1] % self.height)
503 541
504 542
        coordinates = set()
505 543
506 -
        def find_neighbors(pos, radius):
544 +
        def find_neighbors(pos: Coordinate, radius: int) -> None:
507 545
            x, y = pos
508 546
509 547
            """
@@ -518,16 +556,14 @@
Loading
518 556
                adjacent.append(pos)
519 557
520 558
            if x % 2 == 0:
521 -
                adjacent += [(x - 1, y + 1), (x - 1, y),
522 -
                             (x + 1, y + 1), (x + 1, y)]
559 +
                adjacent += [(x - 1, y + 1), (x - 1, y), (x + 1, y + 1), (x + 1, y)]
523 560
            else:
524 -
                adjacent += [(x - 1, y), (x - 1, y - 1),
525 -
                             (x + 1, y), (x + 1, y - 1)]
561 +
                adjacent += [(x - 1, y), (x - 1, y - 1), (x + 1, y), (x + 1, y - 1)]
526 562
527 563
            if self.torus is False:
528 564
                adjacent = list(
529 -
                    filter(lambda coords:
530 -
                           not self.out_of_bounds(coords), adjacent))
565 +
                    filter(lambda coords: not self.out_of_bounds(coords), adjacent)
566 +
                )
531 567
            else:
532 568
                adjacent = [torus_adj_2d(coord) for coord in adjacent]
533 569
@@ -544,7 +580,7 @@
Loading
544 580
        for i in coordinates:
545 581
            yield i
546 582
547 -
    def neighbor_iter(self, pos):
583 +
    def neighbor_iter(self, pos: Coordinate) -> Iterator[GridContent]:
548 584
        """ Iterate over position neighbors.
549 585
550 586
        Args:
@@ -554,8 +590,9 @@
Loading
554 590
        neighborhood = self.iter_neighborhood(pos)
555 591
        return self.iter_cell_list_contents(neighborhood)
556 592
557 -
    def get_neighborhood(self, pos,
558 -
                         include_center=False, radius=1):
593 +
    def get_neighborhood(
594 +
        self, pos: Coordinate, include_center: bool = False, radius: int = 1
595 +
    ) -> List[Coordinate]:
559 596
        """ Return a list of cells that are in the neighborhood of a
560 597
        certain point.
561 598
@@ -572,8 +609,9 @@
Loading
572 609
        """
573 610
        return list(self.iter_neighborhood(pos, include_center, radius))
574 611
575 -
    def iter_neighbors(self, pos,
576 -
                       include_center=False, radius=1):
612 +
    def iter_neighbors(
613 +
        self, pos: Coordinate, include_center: bool = False, radius: int = 1
614 +
    ) -> Iterator[GridContent]:
577 615
        """ Return an iterator over neighbors to a certain point.
578 616
579 617
        Args:
@@ -587,12 +625,12 @@
Loading
587 625
            An iterator of non-None objects in the given neighborhood
588 626
589 627
        """
590 -
        neighborhood = self.iter_neighborhood(
591 -
            pos, include_center, radius)
628 +
        neighborhood = self.iter_neighborhood(pos, include_center, radius)
592 629
        return self.iter_cell_list_contents(neighborhood)
593 630
594 -
    def get_neighbors(self, pos,
595 -
                      include_center=False, radius=1):
631 +
    def get_neighbors(
632 +
        self, pos: Coordinate, include_center: bool = False, radius: int = 1
633 +
    ) -> List[Coordinate]:
596 634
        """ Return a list of neighbors to a certain point.
597 635
598 636
        Args:
@@ -606,8 +644,7 @@
Loading
606 644
            A list of non-None objects in the given neighborhood
607 645
608 646
        """
609 -
        return list(self.iter_neighbors(
610 -
            pos, include_center, radius))
647 +
        return list(self.iter_neighbors(pos, include_center, radius))
611 648
612 649
613 650
class ContinuousSpace:
@@ -618,9 +655,17 @@
Loading
618 655
    to store agent objects, to speed up neighborhood lookups.
619 656
620 657
    """
658 +
621 659
    _grid = None
622 660
623 -
    def __init__(self, x_max, y_max, torus, x_min=0, y_min=0):
661 +
    def __init__(
662 +
        self,
663 +
        x_max: float,
664 +
        y_max: float,
665 +
        torus: bool,
666 +
        x_min: float = 0,
667 +
        y_min: float = 0,
668 +
    ) -> None:
624 669
        """ Create a new continuous space.
625 670
626 671
        Args:
@@ -642,10 +687,10 @@
Loading
642 687
        self.torus = torus
643 688
644 689
        self._agent_points = None
645 -
        self._index_to_agent = {}
646 -
        self._agent_to_index = {}
690 +
        self._index_to_agent = {}  # type: Dict[int, Agent]
691 +
        self._agent_to_index = {}  # type: Dict[Agent, int]
647 692
648 -
    def place_agent(self, agent, pos):
693 +
    def place_agent(self, agent: Agent, pos: FloatCoordinate) -> None:
649 694
        """ Place a new agent in the space.
650 695
651 696
        Args:
@@ -662,7 +707,7 @@
Loading
662 707
        self._agent_to_index[agent] = self._agent_points.shape[0] - 1
663 708
        agent.pos = pos
664 709
665 -
    def move_agent(self, agent, pos):
710 +
    def move_agent(self, agent: Agent, pos: FloatCoordinate) -> None:
666 711
        """ Move an agent from its current position to a new position.
667 712
668 713
        Args:
@@ -676,7 +721,7 @@
Loading
676 721
        self._agent_points[idx, 1] = pos[1]
677 722
        agent.pos = pos
678 723
679 -
    def remove_agent(self, agent):
724 +
    def remove_agent(self, agent: Agent) -> None:
680 725
        """ Remove an agent from the simulation.
681 726
682 727
        Args:
@@ -697,7 +742,9 @@
Loading
697 742
        del self._index_to_agent[max_idx]
698 743
        agent.pos = None
699 744
700 -
    def get_neighbors(self, pos, radius, include_center=True):
745 +
    def get_neighbors(
746 +
        self, pos: FloatCoordinate, radius: float, include_center: bool = True
747 +
    ) -> List[GridContent]:
701 748
        """ Get all objects within a certain radius.
702 749
703 750
        Args:
@@ -714,11 +761,15 @@
Loading
714 761
            deltas = np.minimum(deltas, self.size - deltas)
715 762
        dists = deltas[:, 0] ** 2 + deltas[:, 1] ** 2
716 763
717 -
        idxs, = np.where(dists <= radius ** 2)
718 -
        neighbors = [self._index_to_agent[x] for x in idxs if include_center or dists[x] > 0]
764 +
        (idxs,) = np.where(dists <= radius ** 2)
765 +
        neighbors = [
766 +
            self._index_to_agent[x] for x in idxs if include_center or dists[x] > 0
767 +
        ]
719 768
        return neighbors
720 769
721 -
    def get_heading(self, pos_1, pos_2):
770 +
    def get_heading(
771 +
        self, pos_1: FloatCoordinate, pos_2: FloatCoordinate
772 +
    ) -> FloatCoordinate:
722 773
        """ Get the heading angle between two points, accounting for toroidal space.
723 774
724 775
        Args:
@@ -734,7 +785,7 @@
Loading
734 785
            heading = tuple(heading)
735 786
        return heading
736 787
737 -
    def get_distance(self, pos_1, pos_2):
788 +
    def get_distance(self, pos_1: FloatCoordinate, pos_2: FloatCoordinate) -> float:
738 789
        """ Get the distance between two point, accounting for toroidal space.
739 790
740 791
        Args:
@@ -751,7 +802,7 @@
Loading
751 802
            dy = min(dy, self.height - dy)
752 803
        return np.sqrt(dx * dx + dy * dy)
753 804
754 -
    def torus_adj(self, pos):
805 +
    def torus_adj(self, pos: FloatCoordinate) -> FloatCoordinate:
755 806
        """ Adjust coordinates to handle torus looping.
756 807
757 808
        If the coordinate is out-of-bounds and the space is toroidal, return
@@ -774,28 +825,27 @@
Loading
774 825
            else:
775 826
                return np.array((x, y))
776 827
777 -
    def out_of_bounds(self, pos):
828 +
    def out_of_bounds(self, pos: FloatCoordinate) -> bool:
778 829
        """ Check if a point is out of bounds. """
779 830
        x, y = pos
780 -
        return (x < self.x_min or x >= self.x_max or
781 -
                y < self.y_min or y >= self.y_max)
831 +
        return x < self.x_min or x >= self.x_max or y < self.y_min or y >= self.y_max
782 832
783 833
784 834
class NetworkGrid:
785 835
    """ Network Grid where each node contains zero or more agents. """
786 836
787 -
    def __init__(self, G):
837 +
    def __init__(self, G: Any) -> None:
788 838
        self.G = G
789 839
        for node_id in self.G.nodes:
790 -
            G.nodes[node_id]['agent'] = list()
840 +
            G.nodes[node_id]["agent"] = list()
791 841
792 -
    def place_agent(self, agent, node_id):
842 +
    def place_agent(self, agent: Agent, node_id: int) -> None:
793 843
        """ Place a agent in a node. """
794 844
795 845
        self._place_agent(agent, node_id)
796 846
        agent.pos = node_id
797 847
798 -
    def get_neighbors(self, node_id, include_center=False):
848 +
    def get_neighbors(self, node_id: int, include_center: bool = False) -> List[int]:
799 849
        """ Get all adjacent nodes """
800 850
801 851
        neighbors = list(self.G.neighbors(node_id))
@@ -804,33 +854,37 @@
Loading
804 854
805 855
        return neighbors
806 856
807 -
    def move_agent(self, agent, node_id):
857 +
    def move_agent(self, agent: Agent, node_id: int) -> None:
808 858
        """ Move an agent from its current node to a new node. """
809 859
810 860
        self._remove_agent(agent, agent.pos)
811 861
        self._place_agent(agent, node_id)
812 862
        agent.pos = node_id
813 863
814 -
    def _place_agent(self, agent, node_id):
864 +
    def _place_agent(self, agent: Agent, node_id: int) -> None:
815 865
        """ Place the agent at the correct node. """
816 866
817 -
        self.G.nodes[node_id]['agent'].append(agent)
867 +
        self.G.nodes[node_id]["agent"].append(agent)
818 868
819 -
    def _remove_agent(self, agent, node_id):
869 +
    def _remove_agent(self, agent: Agent, node_id: int) -> None:
820 870
        """ Remove an agent from a node. """
821 871
822 -
        self.G.nodes[node_id]['agent'].remove(agent)
872 +
        self.G.nodes[node_id]["agent"].remove(agent)
823 873
824 -
    def is_cell_empty(self, node_id):
874 +
    def is_cell_empty(self, node_id: int) -> bool:
825 875
        """ Returns a bool of the contents of a cell. """
826 -
        return not self.G.nodes[node_id]['agent']
876 +
        return not self.G.nodes[node_id]["agent"]
827 877
828 -
    def get_cell_list_contents(self, cell_list):
878 +
    def get_cell_list_contents(self, cell_list: List[int]) -> List[GridContent]:
829 879
        return list(self.iter_cell_list_contents(cell_list))
830 880
831 -
    def get_all_cell_contents(self):
881 +
    def get_all_cell_contents(self) -> List[GridContent]:
832 882
        return list(self.iter_cell_list_contents(self.G))
833 883
834 -
    def iter_cell_list_contents(self, cell_list):
835 -
        list_of_lists = [self.G.nodes[node_id]['agent'] for node_id in cell_list if not self.is_cell_empty(node_id)]
884 +
    def iter_cell_list_contents(self, cell_list: List[int]) -> List[GridContent]:
885 +
        list_of_lists = [
886 +
            self.G.nodes[node_id]["agent"]
887 +
            for node_id in cell_list
888 +
            if not self.is_cell_empty(node_id)
889 +
        ]
836 890
        return [item for sublist in list_of_lists for item in sublist]

@@ -22,8 +22,10 @@
Loading
22 22
23 23
24 24
class ParameterError(TypeError):
25 -
    MESSAGE = ('parameters must map a name to a value. '
26 -
               'These names did not match paramerets: {}')
25 +
    MESSAGE = (
26 +
        "parameters must map a name to a value. "
27 +
        "These names did not match paramerets: {}"
28 +
    )
27 29
28 30
    def __init__(self, bad_names):
29 31
        self.bad_names = bad_names
@@ -33,8 +35,10 @@
Loading
33 35
34 36
35 37
class VariableParameterError(ParameterError):
36 -
    MESSAGE = ('variable_parameters must map a name to a sequence of values. '
37 -
               'These parameters were given with non-sequence values: {}')
38 +
    MESSAGE = (
39 +
        "variable_parameters must map a name to a sequence of values. "
40 +
        "These parameters were given with non-sequence values: {}"
41 +
    )
38 42
39 43
    def __init__(self, bad_names):
40 44
        super().__init__(bad_names)
@@ -51,10 +55,18 @@
Loading
51 55
    run. To get step by step data, simply have a reporter store the model's
52 56
    entire DataCollector object.
53 57
    """
54 -
    def __init__(self, model_cls, parameters_list=None,
55 -
                 fixed_parameters=None, iterations=1, max_steps=1000,
56 -
                 model_reporters=None, agent_reporters=None,
57 -
                 display_progress=True):
58 +
59 +
    def __init__(
60 +
        self,
61 +
        model_cls,
62 +
        parameters_list=None,
63 +
        fixed_parameters=None,
64 +
        iterations=1,
65 +
        max_steps=1000,
66 +
        model_reporters=None,
67 +
        agent_reporters=None,
68 +
        display_progress=True,
69 +
    ):
58 70
        """ Create a new BatchRunner for a given model with the given
59 71
        parameters.
60 72
@@ -205,15 +217,14 @@
Loading
205 217
        collected.
206 218
207 219
        """
208 -
        return self._prepare_report_table(self.agent_vars,
209 -
                                          extra_cols=['AgentId'])
220 +
        return self._prepare_report_table(self.agent_vars, extra_cols=["AgentId"])
210 221
211 222
    def _prepare_report_table(self, vars_dict, extra_cols=None):
212 223
        """
213 224
        Creates a dataframe from collected records and sorts it using 'Run'
214 225
        column as a key.
215 226
        """
216 -
        extra_cols = ['Run'] + (extra_cols or [])
227 +
        extra_cols = ["Run"] + (extra_cols or [])
217 228
        index_cols = set()
218 229
        for params in self.parameters_list:
219 230
            index_cols |= params.keys()
@@ -228,7 +239,7 @@
Loading
228 239
        df = pd.DataFrame(records)
229 240
        rest_cols = set(df.columns) - set(index_cols)
230 241
        ordered = df[index_cols + list(sorted(rest_cols))]
231 -
        ordered.sort_values(by='Run', inplace=True)
242 +
        ordered.sort_values(by="Run", inplace=True)
232 243
        if self._include_fixed:
233 244
            for param in self.fixed_parameters.keys():
234 245
                val = self.fixed_parameters[param]
@@ -242,8 +253,9 @@
Loading
242 253
# This is kind of a useless class, but it does carry the 'source' parameters with it
243 254
class ParameterProduct:
244 255
    def __init__(self, variable_parameters):
245 -
        self.param_names, self.param_lists = \
246 -
            zip(*(copy.deepcopy(variable_parameters)).items())
256 +
        self.param_names, self.param_lists = zip(
257 +
            *(copy.deepcopy(variable_parameters)).items()
258 +
        )
247 259
        self._product = product(*self.param_lists)
248 260
249 261
    def __iter__(self):
@@ -257,8 +269,9 @@
Loading
257 269
# distributions, only lists.
258 270
class ParameterSampler:
259 271
    def __init__(self, parameter_lists, n, random_state=None):
260 -
        self.param_names, self.param_lists = \
261 -
            zip(*(copy.deepcopy(parameter_lists)).items())
272 +
        self.param_names, self.param_lists = zip(
273 +
            *(copy.deepcopy(parameter_lists)).items()
274 +
        )
262 275
        self.n = n
263 276
        if random_state is None:
264 277
            self.random_state = random.Random()
@@ -274,7 +287,12 @@
Loading
274 287
    def __next__(self):
275 288
        self.count += 1
276 289
        if self.count <= self.n:
277 -
            return dict(zip(self.param_names, [self.random_state.choice(l) for l in self.param_lists]))
290 +
            return dict(
291 +
                zip(
292 +
                    self.param_names,
293 +
                    [self.random_state.choice(p_list) for p_list in self.param_lists],
294 +
                )
295 +
            )
278 296
        raise StopIteration()
279 297
280 298
@@ -290,10 +308,18 @@
Loading
290 308
    entire DataCollector object.
291 309
292 310
    """
293 -
    def __init__(self, model_cls, variable_parameters=None,
294 -
                 fixed_parameters=None, iterations=1, max_steps=1000,
295 -
                 model_reporters=None, agent_reporters=None,
296 -
                 display_progress=True):
311 +
312 +
    def __init__(
313 +
        self,
314 +
        model_cls,
315 +
        variable_parameters=None,
316 +
        fixed_parameters=None,
317 +
        iterations=1,
318 +
        max_steps=1000,
319 +
        model_reporters=None,
320 +
        agent_reporters=None,
321 +
        display_progress=True,
322 +
    ):
297 323
        """ Create a new BatchRunner for a given model with the given
298 324
        parameters.
299 325
@@ -325,16 +351,24 @@
Loading
325 351
            display_progress: Display progresss bar with time estimation?
326 352
327 353
        """
328 -
        super().__init__(model_cls, ParameterProduct(variable_parameters),
329 -
                     fixed_parameters, iterations, max_steps,
330 -
                     model_reporters, agent_reporters,
331 -
                     display_progress)
354 +
        super().__init__(
355 +
            model_cls,
356 +
            ParameterProduct(variable_parameters),
357 +
            fixed_parameters,
358 +
            iterations,
359 +
            max_steps,
360 +
            model_reporters,
361 +
            agent_reporters,
362 +
            display_progress,
363 +
        )
332 364
333 365
334 366
class MPSupport(Exception):
335 367
    def __str__(self):
336 -
        return ("BatchRunnerMP depends on pathos, which is either not "
337 -
               "installed, or the path can not be found. ")
368 +
        return (
369 +
            "BatchRunnerMP depends on pathos, which is either not "
370 +
            "installed, or the path can not be found. "
371 +
        )
338 372
339 373
340 374
class BatchRunnerMP(BatchRunner):
@@ -370,10 +404,14 @@
Loading
370 404
                param_values = all_param_values[i]
371 405
                for _ in range(self.iterations):
372 406
                    # make a new process and add it to the queue
373 -
                    job_queue.append(self.pool.uimap(self.run_iteration,
374 -
                                                     (kwargs,),
375 -
                                                     (param_values,),
376 -
                                                     (next(run_count),)))
407 +
                    job_queue.append(
408 +
                        self.pool.uimap(
409 +
                            self.run_iteration,
410 +
                            (kwargs,),
411 +
                            (param_values,),
412 +
                            (next(run_count),),
413 +
                        )
414 +
                    )
377 415
            # empty the queue
378 416
            results = []
379 417
            for task in job_queue:

@@ -42,10 +42,16 @@
Loading
42 42
        the same way that "Color" is currently.
43 43
44 44
    """
45 +
45 46
    package_includes = ["Chart.min.js", "ChartModule.js"]
46 47
47 -
    def __init__(self, series, canvas_height=200, canvas_width=500,
48 -
                 data_collector_name="datacollector"):
48 +
    def __init__(
49 +
        self,
50 +
        series,
51 +
        canvas_height=200,
52 +
        canvas_width=500,
53 +
        data_collector_name="datacollector",
54 +
    ):
49 55
        """
50 56
        Create a new line chart visualization.
51 57
@@ -64,8 +70,7 @@
Loading
64 70
65 71
        series_json = json.dumps(self.series)
66 72
        new_element = "new ChartModule({}, {},  {})"
67 -
        new_element = new_element.format(series_json, canvas_width,
68 -
                                         canvas_height)
73 +
        new_element = new_element.format(series_json, canvas_width, canvas_height)
69 74
        self.js_code = "elements.push(" + new_element + ");"
70 75
71 76
    def render(self, model):

@@ -30,9 +30,16 @@
Loading
30 30
31 31
    package_includes = ["d3.min.js", "BarChartModule.js"]
32 32
33 -
    def __init__(self, fields, scope="model", sorting="none",
34 -
                sort_by="none", canvas_height=400,
35 -
                canvas_width=800, data_collector_name="datacollector"):
33 +
    def __init__(
34 +
        self,
35 +
        fields,
36 +
        scope="model",
37 +
        sorting="none",
38 +
        sort_by="none",
39 +
        canvas_height=400,
40 +
        canvas_width=800,
41 +
        data_collector_name="datacollector",
42 +
    ):
36 43
        """
37 44
        Create a new bar chart visualization.
38 45
@@ -58,8 +65,9 @@
Loading
58 65
59 66
        fields_json = json.dumps(self.fields)
60 67
        new_element = "new BarChartModule({}, {}, {}, '{}', '{}')"
61 -
        new_element = new_element.format(fields_json, canvas_width, canvas_height,
62 -
                                        sorting, sort_by)
68 +
        new_element = new_element.format(
69 +
            fields_json, canvas_width, canvas_height, sorting, sort_by
70 +
        )
63 71
        self.js_code = "elements.push(" + new_element + ")"
64 72
65 73
    def render(self, model):
@@ -67,9 +75,9 @@
Loading
67 75
        data_collector = getattr(model, self.data_collector_name)
68 76
69 77
        if self.scope == "agent":
70 -
            df = data_collector.get_agent_vars_dataframe().astype('float')
78 +
            df = data_collector.get_agent_vars_dataframe().astype("float")
71 79
            latest_step = df.index.levels[0][-1]
72 -
            labelStrings = [f['Label'] for f in self.fields]
80 +
            labelStrings = [f["Label"] for f in self.fields]
73 81
            dict = df.loc[latest_step].T.loc[labelStrings].to_dict()
74 82
            current_values = list(dict.values())
75 83

@@ -1,4 +1,3 @@
Loading
1 -
2 1
class UserSettableParameter:
3 2
    """ A class for providing options to a visualization for a given parameter.
4 3
@@ -36,19 +35,26 @@
Loading
36 35
        static_text = UserSettableParameter('static_text', value="This is a descriptive textbox")
37 36
     """
38 37
39 -
    NUMBER = 'number'
40 -
    CHECKBOX = 'checkbox'
41 -
    CHOICE = 'choice'
42 -
    SLIDER = 'slider'
43 -
    STATIC_TEXT = 'static_text'
38 +
    NUMBER = "number"
39 +
    CHECKBOX = "checkbox"
40 +
    CHOICE = "choice"
41 +
    SLIDER = "slider"
42 +
    STATIC_TEXT = "static_text"
44 43
45 44
    TYPES = (NUMBER, CHECKBOX, CHOICE, SLIDER, STATIC_TEXT)
46 45
47 46
    _ERROR_MESSAGE = "Missing or malformed inputs for '{}' Option '{}'"
48 47
49 48
    def __init__(
50 -
        self, param_type=None, name='', value=None, min_value=None, max_value=None,
51 -
            step=1, choices=list(), description=None
49 +
        self,
50 +
        param_type=None,
51 +
        name="",
52 +
        value=None,
53 +
        min_value=None,
54 +
        max_value=None,
55 +
        step=1,
56 +
        choices=list(),
57 +
        description=None,
52 58
    ):
53 59
        if param_type not in self.TYPES:
54 60
            raise ValueError("{} is not a valid Option type".format(param_type))
@@ -69,7 +75,9 @@
Loading
69 75
            valid = not (self.value is None)
70 76
71 77
        elif self.param_type == self.SLIDER:
72 -
            valid = not (self.value is None or self.min_value is None or self.max_value is None)
78 +
            valid = not (
79 +
                self.value is None or self.min_value is None or self.max_value is None
80 +
            )
73 81
74 82
        elif self.param_type == self.CHOICE:
75 83
            valid = not (self.value is None or len(self.choices) == 0)
@@ -97,11 +105,15 @@
Loading
97 105
                self._value = self.max_value
98 106
        elif self.param_type == self.CHOICE:
99 107
            if self._value not in self.choices:
100 -
                print("Selected choice value not in available choices, selected first choice from 'choices' list")
108 +
                print(
109 +
                    "Selected choice value not in available choices, selected first choice from 'choices' list"
110 +
                )
101 111
                self._value = self.choices[0]
102 112
103 113
    @property
104 114
    def json(self):
105 115
        result = self.__dict__.copy()
106 -
        result['value'] = result.pop('_value')  # Return _value as value, value is the same
116 +
        result["value"] = result.pop(
117 +
            "_value"
118 +
        )  # Return _value as value, value is the same
107 119
        return result

@@ -131,7 +131,7 @@
Loading
131 131
132 132
    package_includes = []
133 133
    local_includes = []
134 -
    js_code = ''
134 +
    js_code = ""
135 135
    render_args = {}
136 136
137 137
    def __init__(self):
@@ -149,6 +149,7 @@
Loading
149 149
        """
150 150
        return "<b>VisualizationElement goes here</b>."
151 151
152 +
152 153
# =============================================================================
153 154
# Actual Tornado code starts here:
154 155
@@ -160,33 +161,33 @@
Loading
160 161
        elements = self.application.visualization_elements
161 162
        for i, element in enumerate(elements):
162 163
            element.index = i
163 -
        self.render("modular_template.html", port=self.application.port,
164 -
                    model_name=self.application.model_name,
165 -
                    description=self.application.description,
166 -
                    package_includes=self.application.package_includes,
167 -
                    local_includes=self.application.local_includes,
168 -
                    scripts=self.application.js_code)
164 +
        self.render(
165 +
            "modular_template.html",
166 +
            port=self.application.port,
167 +
            model_name=self.application.model_name,
168 +
            description=self.application.description,
169 +
            package_includes=self.application.package_includes,
170 +
            local_includes=self.application.local_includes,
171 +
            scripts=self.application.js_code,
172 +
        )
169 173
170 174
171 175
class SocketHandler(tornado.websocket.WebSocketHandler):
172 176
    """ Handler for websocket. """
177 +
173 178
    def open(self):
174 179
        if self.application.verbose:
175 180
            print("Socket opened!")
176 -
        self.write_message({
177 -
            "type": "model_params",
178 -
            "params": self.application.user_params
179 -
        })
181 +
        self.write_message(
182 +
            {"type": "model_params", "params": self.application.user_params}
183 +
        )
180 184
181 185
    def check_origin(self, origin):
182 186
        return True
183 187
184 188
    @property
185 189
    def viz_state_message(self):
186 -
        return {
187 -
            "type": "viz_state",
188 -
            "data": self.application.render_model()
189 -
        }
190 +
        return {"type": "viz_state", "data": self.application.render_model()}
190 191
191 192
    def on_message(self, message):
192 193
        """ Receiving a message from the websocket, parse, and act accordingly.
@@ -213,7 +214,9 @@
Loading
213 214
214 215
            # Is the param editable?
215 216
            if param in self.application.user_params:
216 -
                if isinstance(self.application.model_kwargs[param], UserSettableParameter):
217 +
                if isinstance(
218 +
                    self.application.model_kwargs[param], UserSettableParameter
219 +
                ):
217 220
                    self.application.model_kwargs[param].value = value
218 221
                else:
219 222
                    self.application.model_kwargs[param] = value
@@ -225,29 +228,35 @@
Loading
225 228
226 229
class ModularServer(tornado.web.Application):
227 230
    """ Main visualization application. """
231 +
228 232
    verbose = True
229 233
230 234
    port = 8521  # Default port to listen on
231 235
    max_steps = 100000
232 236
233 237
    # Handlers and other globals:
234 -
    page_handler = (r'/', PageHandler)
235 -
    socket_handler = (r'/ws', SocketHandler)
236 -
    static_handler = (r'/static/(.*)', tornado.web.StaticFileHandler,
237 -
                      {"path": os.path.dirname(__file__) + "/templates"})
238 -
    local_handler = (r'/local/(.*)', tornado.web.StaticFileHandler,
239 -
                     {"path": ''})
238 +
    page_handler = (r"/", PageHandler)
239 +
    socket_handler = (r"/ws", SocketHandler)
240 +
    static_handler = (
241 +
        r"/static/(.*)",
242 +
        tornado.web.StaticFileHandler,
243 +
        {"path": os.path.dirname(__file__) + "/templates"},
244 +
    )
245 +
    local_handler = (r"/local/(.*)", tornado.web.StaticFileHandler, {"path": ""})
240 246
241 247
    handlers = [page_handler, socket_handler, static_handler, local_handler]
242 248
243 -
    settings = {"debug": True,
244 -
                "autoreload": False,
245 -
                "template_path": os.path.dirname(__file__) + "/templates"}
249 +
    settings = {
250 +
        "debug": True,
251 +
        "autoreload": False,
252 +
        "template_path": os.path.dirname(__file__) + "/templates",
253 +
    }
246 254
247 -
    EXCLUDE_LIST = ('width', 'height',)
255 +
    EXCLUDE_LIST = ("width", "height")
248 256
249 -
    def __init__(self, model_cls, visualization_elements, name="Mesa Model",
250 -
                 model_params={}):
257 +
    def __init__(
258 +
        self, model_cls, visualization_elements, name="Mesa Model", model_params={}
259 +
    ):
251 260
        """ Create a new visualization server with the given elements. """
252 261
        # Prep visualization elements:
253 262
        self.visualization_elements = visualization_elements
@@ -264,8 +273,8 @@
Loading
264 273
        # Initializing the model
265 274
        self.model_name = name
266 275
        self.model_cls = model_cls
267 -
        self.description = 'No description available'
268 -
        if hasattr(model_cls, 'description'):
276 +
        self.description = "No description available"
277 +
        if hasattr(model_cls, "description"):
269 278
            self.description = model_cls.description
270 279
        elif model_cls.__doc__ is not None:
271 280
            self.description = model_cls.__doc__
@@ -291,7 +300,9 @@
Loading
291 300
        model_params = {}
292 301
        for key, val in self.model_kwargs.items():
293 302
            if isinstance(val, UserSettableParameter):
294 -
                if val.param_type == 'static_text':    # static_text is never used for setting params
303 +
                if (
304 +
                    val.param_type == "static_text"
305 +
                ):  # static_text is never used for setting params
295 306
                    continue
296 307
                model_params[key] = val.value
297 308
            else:
@@ -314,8 +325,8 @@
Loading
314 325
        """ Run the app. """
315 326
        if port is not None:
316 327
            self.port = port
317 -
        url = 'http://127.0.0.1:{PORT}'.format(PORT=self.port)
318 -
        print('Interface starting at {url}'.format(url=url))
328 +
        url = "http://127.0.0.1:{PORT}".format(PORT=self.port)
329 +
        print("Interface starting at {url}".format(url=url))
319 330
        self.listen(self.port)
320 331
        if open_browser:
321 332
            webbrowser.open(url)
Files Coverage
mesa 84.72%
Project Totals (17 files) 84.72%
1745.4
TRAVIS_PYTHON_VERSION=3.8
TRAVIS_OS_NAME=linux
1745.1
TRAVIS_PYTHON_VERSION=3.5
TRAVIS_OS_NAME=linux
1745.3
TRAVIS_PYTHON_VERSION=3.7
TRAVIS_OS_NAME=linux

No yaml found.

Create your codecov.yml to customize your Codecov experience

Sunburst
The inner-most circle is the entire project, moving away from the center are folders then, finally, a single file. The size and color of each slice is representing the number of statements and the coverage, respectively.
Icicle
The top section represents the entire project. Proceeding with folders and finally individual files. The size and color of each slice is representing the number of statements and the coverage, respectively.
Grid
Each block represents a single file in the project. The size and color of each block is represented by the number of statements and the coverage, respectively.
Loading