diff --git a/.codecov.yml b/.codecov.yml
deleted file mode 100644
index 69cb760..0000000
--- a/.codecov.yml
+++ /dev/null
@@ -1,1 +0,0 @@
-comment: false
diff --git a/.coveragerc b/.coveragerc
deleted file mode 100644
index e61ef82..0000000
--- a/.coveragerc
+++ /dev/null
@@ -1,7 +0,0 @@
-[report]
-omit =
-    setup.py
-    gerrychain/__main__.py
-    gerrychain/_version.py
-    gerrychain/vendor/*
-    tests/*
diff --git a/MANIFEST.in b/MANIFEST.in
deleted file mode 100644
index 964bbf3..0000000
--- a/MANIFEST.in
+++ /dev/null
@@ -1,2 +0,0 @@
-include versioneer.py
-include gerrychain/_version.py
diff --git a/conda.recipe/meta.yaml b/conda.recipe/meta.yaml
deleted file mode 100644
index 2839b69..0000000
--- a/conda.recipe/meta.yaml
+++ /dev/null
@@ -1,37 +0,0 @@
-{% set data = load_setup_py_data() %}
-
-package:
-  name: gerrychain
-  version: {{ data['version'] }}
-
-source:
-  path: ..
-
-build:
-  script: python setup.py install --single-version-externally-managed --record=record.txt
-
-requirements:
-  build:
-    - python
-    - setuptools
-  run:
-    - python
-    # force openblas over mkl to make download size smaller.  Note that this precludes using mkl_random
-    - nomkl
-    # dependencies are defined in setup.py
-    {% for dep in data['install_requires'] %}
-    - {{ dep.lower() }}
-    {% endfor %}
-
-test:
-  source_files:
-    - tests
-  requires:
-    - pytest
-    - pytest-cov
-  commands:
-    - pytest tests
-
-about:
-  home: https://github.com/mggg/GerryChain
-  summary: Exploration of districting plans for gerrymandering analysis using MCMC
diff --git a/gerrychain/chain.py b/gerrychain/chain.py
index 93b812e..c74f57d 100644
--- a/gerrychain/chain.py
+++ b/gerrychain/chain.py
@@ -10,13 +10,13 @@ class MarkovChain:
 
     .. code-block:: python
 
-        chain = MarkovChain(proposal, is_valid, accept, initial_state)
+        chain = MarkovChain(proposal, constraints, accept, initial_state, total_steps)
         for state in chain:
             # Do whatever you want - print output, compute scores, ...
 
     """
 
-    def __init__(self, proposal, constraints, accept, initial_state, total_steps=1000):
+    def __init__(self, proposal, constraints, accept, initial_state, total_steps):
         """
         :param proposal: Function proposing the next state from the current state.
         :param constraints: A function with signature ``Partition -> bool`` determining whether
@@ -78,6 +78,9 @@ class MarkovChain:
     def __len__(self):
         return self.total_steps
 
+    def __repr__(self):
+        return "<MarkovChain [{} steps]>".format(len(self))
+
     def with_progress_bar(self):
         from tqdm.auto import tqdm
 
diff --git a/gerrychain/graph/graph.py b/gerrychain/graph/graph.py
index 4d1089a..bc1620a 100644
--- a/gerrychain/graph/graph.py
+++ b/gerrychain/graph/graph.py
@@ -18,6 +18,9 @@ class Graph(networkx.Graph):
     to save and load graphs as JSON files.
     """
 
+    def __repr__(self):
+        return "<Graph [{} nodes, {} edges]>".format(len(self.nodes), len(self.edges))
+
     @classmethod
     def from_json(cls, json_file):
         """Load a graph from a JSON file in the NetworkX json_graph format.
diff --git a/gerrychain/grid.py b/gerrychain/grid.py
index 459529a..a6f4602 100644
--- a/gerrychain/grid.py
+++ b/gerrychain/grid.py
@@ -3,9 +3,16 @@ import math
 import networkx
 
 from gerrychain.partition import Partition
-from gerrychain.updaters import (Tally, boundary_nodes, cut_edges,
-                                 cut_edges_by_part, exterior_boundaries,
-                                 interior_boundaries, perimeter, polsby_popper)
+from gerrychain.updaters import (
+    Tally,
+    boundary_nodes,
+    cut_edges,
+    cut_edges_by_part,
+    exterior_boundaries,
+    interior_boundaries,
+    perimeter,
+)
+from gerrychain.metrics import polsby_popper
 
 
 class Grid(Partition):
diff --git a/gerrychain/metrics/__init__.py b/gerrychain/metrics/__init__.py
new file mode 100644
index 0000000..2a7ec48
--- /dev/null
+++ b/gerrychain/metrics/__init__.py
@@ -0,0 +1,2 @@
+from .compactness import polsby_popper
+from .partisan import *
diff --git a/gerrychain/metrics/compactness.py b/gerrychain/metrics/compactness.py
new file mode 100644
index 0000000..42f1f8f
--- /dev/null
+++ b/gerrychain/metrics/compactness.py
@@ -0,0 +1,17 @@
+import math
+
+
+def compute_polsby_popper(area, perimeter):
+    try:
+        return 4 * math.pi * area / perimeter ** 2
+    except ZeroDivisionError:
+        return math.nan
+
+
+def polsby_popper(partition):
+    return {
+        part: compute_polsby_popper(
+            partition["area"][part], partition["perimeter"][part]
+        )
+        for part in partition.parts
+    }
diff --git a/gerrychain/scores.py b/gerrychain/metrics/partisan.py
similarity index 100%
rename from gerrychain/scores.py
rename to gerrychain/metrics/partisan.py
diff --git a/gerrychain/partition/assignment.py b/gerrychain/partition/assignment.py
index fd4f967..66ed42a 100644
--- a/gerrychain/partition/assignment.py
+++ b/gerrychain/partition/assignment.py
@@ -28,6 +28,9 @@ class Assignment(Mapping):
                 raise TypeError("Level sets must be frozensets")
         self.parts = parts
 
+    def __repr__(self):
+        return "<Assignment [{} keys, {} parts]>".format(len(self), len(self.parts))
+
     def __iter__(self):
         return self.keys()
 
diff --git a/gerrychain/partition/partition.py b/gerrychain/partition/partition.py
index f263e5e..2c8c86e 100644
--- a/gerrychain/partition/partition.py
+++ b/gerrychain/partition/partition.py
@@ -70,7 +70,7 @@ class Partition:
     def __repr__(self):
         number_of_parts = len(self)
         s = "s" if number_of_parts > 1 else ""
-        return "Partition of a graph into {} part{}".format(number_of_parts, s)
+        return "<{} [{} part{}]>".format(self.__class__.__name__, number_of_parts, s)
 
     def __len__(self):
         return len(self.parts)
diff --git a/gerrychain/updaters/__init__.py b/gerrychain/updaters/__init__.py
index 9961c9b..e4acb69 100644
--- a/gerrychain/updaters/__init__.py
+++ b/gerrychain/updaters/__init__.py
@@ -1,6 +1,11 @@
-from .compactness import (boundary_nodes, exterior_boundaries,
-                          exterior_boundaries_as_a_set, flips,
-                          interior_boundaries, perimeter, polsby_popper)
+from .compactness import (
+    boundary_nodes,
+    exterior_boundaries,
+    exterior_boundaries_as_a_set,
+    flips,
+    interior_boundaries,
+    perimeter,
+)
 from .county_splits import CountySplit, county_splits
 from .cut_edges import cut_edges, cut_edges_by_part
 from .election import Election
@@ -9,7 +14,6 @@ from .tally import DataTally, Tally
 
 __all__ = [
     "flows_from_changes",
-    "polsby_popper",
     "county_splits",
     "cut_edges",
     "cut_edges_by_part",
diff --git a/gerrychain/updaters/compactness.py b/gerrychain/updaters/compactness.py
index 3ea9c11..4ea6f7e 100644
--- a/gerrychain/updaters/compactness.py
+++ b/gerrychain/updaters/compactness.py
@@ -1,70 +1,73 @@
 import collections
-import math
 
 from .flows import on_flow
 from .cut_edges import on_edge_flow
 
 
-def compute_polsby_popper(area, perimeter):
-    try:
-        return 4 * math.pi * area / perimeter**2
-    except ZeroDivisionError:
-        return math.nan
-
-
-def polsby_popper(partition):
-    return {part: compute_polsby_popper(partition['area'][part], partition['perimeter'][part])
-            for part in partition.parts}
-
-
-def boundary_nodes(partition, alias='boundary_nodes'):
+def boundary_nodes(partition, alias="boundary_nodes"):
     if partition.parent:
         return partition.parent[alias]
-    return {node for node in partition.graph.nodes if partition.graph.nodes[node]['boundary_node']}
+    return {
+        node
+        for node in partition.graph.nodes
+        if partition.graph.nodes[node]["boundary_node"]
+    }
 
 
 def initialize_exterior_boundaries_as_a_set(partition):
     part_boundaries = collections.defaultdict(set)
-    for node in partition['boundary_nodes']:
+    for node in partition["boundary_nodes"]:
         part_boundaries[partition.assignment[node]].add(node)
     return part_boundaries
 
 
-@on_flow(initialize_exterior_boundaries_as_a_set, alias='exterior_boundaries_as_a_set')
+@on_flow(initialize_exterior_boundaries_as_a_set, alias="exterior_boundaries_as_a_set")
 def exterior_boundaries_as_a_set(partition, previous, inflow, outflow):
-    graph_boundary = partition['boundary_nodes']
+    graph_boundary = partition["boundary_nodes"]
     return (previous | (inflow & graph_boundary)) - outflow
 
 
 def initialize_exterior_boundaries(partition):
-    graph_boundary = partition['boundary_nodes']
+    graph_boundary = partition["boundary_nodes"]
     boundaries = collections.defaultdict(lambda: 0)
     for node in graph_boundary:
         part = partition.assignment[node]
-        boundaries[part] += partition.graph.nodes[node]['boundary_perim']
+        boundaries[part] += partition.graph.nodes[node]["boundary_perim"]
     return boundaries
 
 
-@on_flow(initialize_exterior_boundaries, alias='exterior_boundaries')
+@on_flow(initialize_exterior_boundaries, alias="exterior_boundaries")
 def exterior_boundaries(partition, previous, inflow, outflow):
-    graph_boundary = partition['boundary_nodes']
-    added_perimeter = sum(partition.graph.nodes[node]['boundary_perim']
-                          for node in inflow & graph_boundary)
-    removed_perimeter = sum(partition.graph.nodes[node]['boundary_perim']
-                            for node in outflow & graph_boundary)
+    graph_boundary = partition["boundary_nodes"]
+    added_perimeter = sum(
+        partition.graph.nodes[node]["boundary_perim"]
+        for node in inflow & graph_boundary
+    )
+    removed_perimeter = sum(
+        partition.graph.nodes[node]["boundary_perim"]
+        for node in outflow & graph_boundary
+    )
     return previous + added_perimeter - removed_perimeter
 
 
 def initialize_interior_boundaries(partition):
-    return {part: sum(partition.graph.edges[edge]['shared_perim']
-                      for edge in partition['cut_edges_by_part'][part])
-            for part in partition.parts}
+    return {
+        part: sum(
+            partition.graph.edges[edge]["shared_perim"]
+            for edge in partition["cut_edges_by_part"][part]
+        )
+        for part in partition.parts
+    }
 
 
-@on_edge_flow(initialize_interior_boundaries, alias='interior_boundaries')
+@on_edge_flow(initialize_interior_boundaries, alias="interior_boundaries")
 def interior_boundaries(partition, previous, new_edges, old_edges):
-    added_perimeter = sum(partition.graph.edges[edge]['shared_perim'] for edge in new_edges)
-    removed_perimeter = sum(partition.graph.edges[edge]['shared_perim'] for edge in old_edges)
+    added_perimeter = sum(
+        partition.graph.edges[edge]["shared_perim"] for edge in new_edges
+    )
+    removed_perimeter = sum(
+        partition.graph.edges[edge]["shared_perim"] for edge in old_edges
+    )
     return previous + added_perimeter - removed_perimeter
 
 
@@ -78,8 +81,8 @@ def perimeter_of_part(partition, part):
     Requires that 'boundary_perim' be a node attribute, 'shared_perim' be an edge
     attribute, 'cut_edges' be an updater, and 'exterior_boundaries' be an updater.
     """
-    exterior_perimeter = partition['exterior_boundaries'][part]
-    interior_perimeter = partition['interior_boundaries'][part]
+    exterior_perimeter = partition["exterior_boundaries"][part]
+    interior_perimeter = partition["interior_boundaries"][part]
 
     return exterior_perimeter + interior_perimeter
 
diff --git a/setup.cfg b/setup.cfg
index 5b2ab82..67d4008 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -7,7 +7,7 @@ exclude = build,gerrychain/_version.py,tests,conda.recipe,.git,versioneer.py,ben
 norecursedirs= .* *.egg* build dist conda.recipe
 addopts =
     --ignore setup.py
-    --ignore run_test.py
+    --cov=gerrychain
     --cov-report term-missing
     --tb native
     --strict
@@ -26,3 +26,12 @@ parentdir_prefix = gerrychain-
 
 [bdist_wheel]
 universal=1
+
+[coverage:report]
+omit =
+    setup.py
+    versioneer.py
+    gerrychain/__main__.py
+    gerrychain/_version.py
+    gerrychain/vendor/*
+    tests/*

Reorganize metrics
We have `polsby_popper`, etc. in `gerrychain.updaters` and all of our partisan scores in `gerrychain.scores`. I propose that we create a `gerrychain.metrics` module with both the partisan and compactness scores (and any other metrics).

This should make it easier for a user to find what they're looking for, and maybe easier to document since the usages are analogous.
diff --git a/tests/test_bounds.py b/tests/constraints/test_bounds.py
similarity index 100%
rename from tests/test_bounds.py
rename to tests/constraints/test_bounds.py
diff --git a/tests/test_contiguity.py b/tests/constraints/test_contiguity.py
similarity index 100%
rename from tests/test_contiguity.py
rename to tests/constraints/test_contiguity.py
diff --git a/tests/test_validity.py b/tests/constraints/test_validity.py
similarity index 100%
rename from tests/test_validity.py
rename to tests/constraints/test_validity.py
diff --git a/tests/metrics/test_compactness.py b/tests/metrics/test_compactness.py
new file mode 100644
index 0000000..fb8d2a9
--- /dev/null
+++ b/tests/metrics/test_compactness.py
@@ -0,0 +1,8 @@
+import math
+from gerrychain.metrics.compactness import compute_polsby_popper
+
+
+def test_polsby_popper_returns_nan_when_perimeter_is_0():
+    area = 10
+    perimeter = 0
+    assert compute_polsby_popper(area, perimeter) is math.nan
diff --git a/tests/test_scores.py b/tests/metrics/test_partisan.py
similarity index 66%
rename from tests/test_scores.py
rename to tests/metrics/test_partisan.py
index 19de232..9efcbe4 100644
--- a/tests/test_scores.py
+++ b/tests/metrics/test_partisan.py
@@ -1,21 +1,28 @@
 import pytest
 from unittest.mock import MagicMock
-from gerrychain.scores import (efficiency_gap, wasted_votes, mean_median,
-                               partisan_bias, partisan_gini)
+from gerrychain.metrics import (
+    efficiency_gap,
+    wasted_votes,
+    mean_median,
+    partisan_bias,
+    partisan_gini,
+)
 from gerrychain.updaters.election import ElectionResults
 
 
 @pytest.fixture
 def mock_election():
     election = MagicMock()
-    election.parties = ['B', 'A']
+    election.parties = ["B", "A"]
 
-    return ElectionResults(election,
-    {
-        'B': {1: 5, 2: 60, 3: 25, 4: 55, 5: 55},
-        'A': {1: 95, 2: 40, 3: 75, 4: 45, 5: 45}
-    },
-    [1, 2, 3, 4, 5])
+    return ElectionResults(
+        election,
+        {
+            "B": {1: 5, 2: 60, 3: 25, 4: 55, 5: 55},
+            "A": {1: 95, 2: 40, 3: 75, 4: 45, 5: 45},
+        },
+        [1, 2, 3, 4, 5],
+    )
 
 
 def test_efficiency_gap(mock_election):
@@ -24,8 +31,13 @@ def test_efficiency_gap(mock_election):
 
 
 def test_wasted_votes(mock_election):
-    result = [wasted_votes(mock_election.totals_for_party['A'][i],
-                           mock_election.totals_for_party['B'][i]) for i in range(1, 6)]
+    result = [
+        wasted_votes(
+            mock_election.totals_for_party["A"][i],
+            mock_election.totals_for_party["B"][i],
+        )
+        for i in range(1, 6)
+    ]
     assert result == [(45, 5), (40, 10), (25, 25), (45, 5), (45, 5)]
 
 
@@ -43,12 +55,14 @@ def test_mean_median_has_right_value(mock_election):
     assert abs(mm - 0.15) < 0.00001
 
 
-def test_signed_partisan_scores_are_positive_if_first_party_has_advantage(mock_election):
+def test_signed_partisan_scores_are_positive_if_first_party_has_advantage(
+    mock_election
+):
     eg = efficiency_gap(mock_election)
     mm = mean_median(mock_election)
     pb = partisan_bias(mock_election)
 
-    assert (eg > 0 and mm > 0 and pb > 0)
+    assert eg > 0 and mm > 0 and pb > 0
 
 
 def test_partisan_bias_has_right_value(mock_election):
diff --git a/tests/partition/test_assignment.py b/tests/partition/test_assignment.py
index bdbe7e5..61227e2 100644
--- a/tests/partition/test_assignment.py
+++ b/tests/partition/test_assignment.py
@@ -105,3 +105,7 @@ def test_get_assignment_with_series():
     assignment = get_assignment(series)
     assert isinstance(assignment, Assignment)
     assert assignment == {1: 1, 2: 2, 3: 1, 4: 2}
+
+
+def test_repr(assignment):
+    assert repr(assignment) == "<Assignment [3 keys, 2 parts]>"
diff --git a/tests/partition/test_partition.py b/tests/partition/test_partition.py
index bc3f328..6b44a41 100644
--- a/tests/partition/test_partition.py
+++ b/tests/partition/test_partition.py
@@ -136,3 +136,7 @@ def districtr_plan_file():
         with open(filename, "w") as f:
             json.dump(districtr_plan, f)
         yield filename
+
+
+def test_repr(example_partition):
+    assert repr(example_partition) == "<Partition [2 parts]>"
diff --git a/tests/test_chain.py b/tests/test_chain.py
index b49b4f7..3910df2 100644
--- a/tests/test_chain.py
+++ b/tests/test_chain.py
@@ -74,3 +74,15 @@ def test_chain_only_yields_accepted_states():
 
     for state in chain:
         assert accept(state), "The chain yielded a non-accepted state"
+
+
+def test_repr():
+    chain = MarkovChain(
+        proposal=lambda x: None,
+        constraints=[],
+        accept=lambda x: True,
+        initial_state=None,
+        total_steps=100,
+    )
+
+    assert repr(chain) == "<MarkovChain [100 steps]>"
diff --git a/tests/updaters/test_perimeters.py b/tests/updaters/test_perimeters.py
index 3d049b2..05c1f15 100644
--- a/tests/updaters/test_perimeters.py
+++ b/tests/updaters/test_perimeters.py
@@ -1,13 +1,10 @@
-import math
 from collections import defaultdict
 
 from gerrychain import MarkovChain
 from gerrychain.accept import always_accept
-from gerrychain.constraints import (no_vanishing_districts,
-                                    single_flip_contiguous)
+from gerrychain.constraints import no_vanishing_districts, single_flip_contiguous
 from gerrychain.grid import Grid
 from gerrychain.proposals import propose_random_flip
-from gerrychain.updaters.compactness import compute_polsby_popper
 
 
 def setup():
@@ -132,8 +129,3 @@ def test_perimeter_match_naive_perimeter_at_every_step():
         expected = expected_perimeter(state)
         assert expected == state["perimeter"]
 
-
-def test_polsby_popper_returns_nan_when_perimeter_is_0():
-    area = 10
-    perimeter = 0
-    assert compute_polsby_popper(area, perimeter) is math.nan

pip install -e .[dev]
parse_log_pytest
requirements.txt
pytest pytest-cov pytest-xdist pytest-mock pytest-asyncio pytest
apt-get update apt-get install -y gcc
3.7
requirements/base.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
attrs==24.2.0
certifi @ file:///croot/certifi_1671487769961/work/certifi
click==8.1.8
click-plugins==1.1.1
cligj==0.7.2
coverage==7.2.7
cycler==0.11.0
exceptiongroup==1.2.2
execnet==2.0.2
fiona==1.9.6
fonttools==4.38.0
geopandas==0.10.2
-e git+https://github.com/mggg/GerryChain.git@cada0b7f5759fbe55e3753d6193ab5a6828bb1c0#egg=gerrychain
importlib-metadata==6.7.0
iniconfig==2.0.0
kiwisolver==1.4.5
matplotlib==3.5.3
networkx==2.6.3
numpy==1.21.6
packaging==24.0
pandas==1.3.5
Pillow==9.5.0
pluggy==1.2.0
pyparsing==3.1.4
pyproj==3.2.1
pytest==7.4.4
pytest-asyncio==0.21.2
pytest-cov==4.1.0
pytest-mock==3.11.1
pytest-xdist==3.5.0
python-dateutil==2.9.0.post0
pytz==2025.2
shapely==2.0.7
six==1.17.0
tomli==2.0.1
typing_extensions==4.7.1
zipp==3.15.0

name: GerryChain
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2022.12.7=py37h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - pip=22.3.1=py37h06a4308_0
  - python=3.7.16=h7a1cb2a_0
  - readline=8.2=h5eee18b_0
  - setuptools=65.6.3=py37h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.38.4=py37h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - attrs==24.2.0
      - click==8.1.8
      - click-plugins==1.1.1
      - cligj==0.7.2
      - coverage==7.2.7
      - cycler==0.11.0
      - exceptiongroup==1.2.2
      - execnet==2.0.2
      - fiona==1.9.6
      - fonttools==4.38.0
      - geopandas==0.10.2
      - importlib-metadata==6.7.0
      - iniconfig==2.0.0
      - kiwisolver==1.4.5
      - matplotlib==3.5.3
      - networkx==2.6.3
      - numpy==1.21.6
      - packaging==24.0
      - pandas==1.3.5
      - pillow==9.5.0
      - pluggy==1.2.0
      - pyparsing==3.1.4
      - pyproj==3.2.1
      - pytest==7.4.4
      - pytest-asyncio==0.21.2
      - pytest-cov==4.1.0
      - pytest-mock==3.11.1
      - pytest-xdist==3.5.0
      - python-dateutil==2.9.0.post0
      - pytz==2025.2
      - shapely==2.0.7
      - six==1.17.0
      - tomli==2.0.1
      - typing-extensions==4.7.1
      - zipp==3.15.0
prefix: /opt/conda/envs/GerryChain

tests/constraints/test_bounds.py::TestWithinPercent::test_within_percent_fails_when_deviation_too_large tests/constraints/test_bounds.py::TestWithinPercent::test_within_percent_fails_when_expected tests/constraints/test_bounds.py::TestWithinPercent::test_within_percent_fails_when_expected2 tests/constraints/test_bounds.py::TestLowerBound::test_fails_values_below_bound tests/constraints/test_bounds.py::TestLowerBound::test_passes_values_above_bound tests/constraints/test_bounds.py::TestLowerBound::test_bound_allows_equality tests/constraints/test_bounds.py::TestLowerBound::test_has_informative_repr tests/constraints/test_bounds.py::TestUpperBound::test_passes_values_below_bound tests/constraints/test_bounds.py::TestUpperBound::test_fails_values_above_bound tests/constraints/test_bounds.py::TestUpperBound::test_bound_allows_equality tests/constraints/test_bounds.py::TestUpperBound::test_has_informative_repr tests/constraints/test_contiguity.py::test_contiguous_components tests/constraints/test_validity.py::test_contiguous_with_contiguity_no_flips_is_true tests/constraints/test_validity.py::test_contiguous_with_contiguity_flips_is_true tests/constraints/test_validity.py::test_discontiguous_with_contiguous_no_flips_is_false tests/constraints/test_validity.py::test_discontiguous_with_single_flip_contiguous_no_flips_is_false tests/constraints/test_validity.py::test_discontiguous_with_contiguous_bfs_no_flips_is_false tests/constraints/test_validity.py::test_discontiguous_with_contiguous_flips_is_false tests/constraints/test_validity.py::test_discontiguous_with_contiguous_bfs_flips_is_false tests/constraints/test_validity.py::test_districts_within_tolerance_returns_false_if_districts_are_not_within_tolerance tests/constraints/test_validity.py::test_districts_within_tolerance_returns_true_if_districts_are_within_tolerance tests/constraints/test_validity.py::test_self_configuring_lower_bound_always_allows_the_first_argument_it_gets tests/constraints/test_validity.py::test_validator_raises_TypeError_if_constraint_returns_non_boolean tests/constraints/test_validity.py::test_no_vanishing_districts_works tests/metrics/test_compactness.py::test_polsby_popper_returns_nan_when_perimeter_is_0 tests/metrics/test_partisan.py::test_efficiency_gap tests/metrics/test_partisan.py::test_wasted_votes tests/metrics/test_partisan.py::test_signed_partisan_scores_point_the_same_way tests/metrics/test_partisan.py::test_mean_median_has_right_value tests/metrics/test_partisan.py::test_signed_partisan_scores_are_positive_if_first_party_has_advantage tests/metrics/test_partisan.py::test_partisan_bias_has_right_value tests/metrics/test_partisan.py::test_partisan_gini_has_right_value tests/partition/test_assignment.py::TestAssignment::test_assignment_can_be_updated tests/partition/test_assignment.py::TestAssignment::test_assignment_copy_does_not_copy_the_node_sets tests/partition/test_assignment.py::TestAssignment::test_to_series tests/partition/test_assignment.py::TestAssignment::test_to_dict tests/partition/test_assignment.py::TestAssignment::test_has_get_method_like_a_dict tests/partition/test_assignment.py::TestAssignment::test_raises_keyerror_for_missing_nodes tests/partition/test_assignment.py::TestAssignment::test_can_update_parts tests/partition/test_assignment.py::TestAssignment::test_implements_Mapping_abc tests/partition/test_assignment.py::TestAssignment::test_assignment_raises_if_a_key_has_two_assignments tests/partition/test_assignment.py::TestAssignment::test_assignment_can_be_instantiated_from_series tests/partition/test_assignment.py::test_get_assignment_accepts_assignment tests/partition/test_assignment.py::test_get_assignment_raises_typeerror_for_unexpected_input tests/partition/test_assignment.py::test_get_assignment_with_series tests/partition/test_assignment.py::test_repr tests/partition/test_partition.py::test_Partition_can_be_flipped tests/partition/test_partition.py::test_Partition_misnamed_vertices_raises_keyerror tests/partition/test_partition.py::test_Partition_unlabelled_vertices_raises_keyerror tests/partition/test_partition.py::test_Partition_knows_cut_edges_K3 tests/partition/test_partition.py::test_propose_random_flip_proposes_a_partition tests/partition/test_partition.py::test_Partition_parts_is_a_dictionary_of_parts_to_nodes tests/partition/test_partition.py::test_Partition_has_subgraphs tests/partition/test_partition.py::test_Partition_caches_subgraphs tests/partition/test_partition.py::test_partition_implements_getattr_for_updater_access tests/partition/test_partition.py::test_can_be_created_from_a_districtr_file tests/partition/test_partition.py::test_from_districtr_plan_raises_if_id_column_missing tests/partition/test_partition.py::test_repr tests/test_chain.py::test_MarkovChain_runs_only_total_steps_times tests/test_chain.py::test_MarkovChain_returns_the_initial_state_first tests/test_chain.py::test_chain_only_yields_accepted_states tests/test_chain.py::test_repr tests/updaters/test_perimeters.py::test_perimeter_handles_flips_with_a_simple_grid tests/updaters/test_perimeters.py::test_interior_perimeter_handles_flips_with_a_simple_grid tests/updaters/test_perimeters.py::test_cut_edges_by_part_handles_flips_with_a_simple_grid tests/updaters/test_perimeters.py::test_cut_edges_by_part_agrees_with_cut_edges_on_a_simple_grid tests/updaters/test_perimeters.py::test_tally_handles_flips_for_a_simple_grid tests/updaters/test_perimeters.py::test_perimeter_match_naive_perimeter_at_every_step
gerrychain/grid.py gerrychain/metrics/__init__.py MANIFEST.in conda.recipe/meta.yaml .codecov.yml gerrychain/partition/assignment.py gerrychain/updaters/compactness.py gerrychain/graph/graph.py setup.cfg .coveragerc gerrychain/metrics/compactness.py gerrychain/updaters/__init__.py gerrychain/chain.py gerrychain/partition/partition.py gerrychain/scores.py
gerrychain/grid.py gerrychain/metrics/__init__.py MANIFEST.in conda.recipe/meta.yaml .codecov.yml gerrychain/partition/assignment.py gerrychain/updaters/compactness.py gerrychain/graph/graph.py setup.cfg .coveragerc gerrychain/metrics/partisan.py gerrychain/metrics/compactness.py gerrychain/updaters/__init__.py gerrychain/chain.py gerrychain/partition/partition.py