Skip to content

Commit

Permalink
Change tskit_tools.MutationMetadata to "union typed" metadata.
Browse files Browse the repository at this point in the history
tskit_tools.decode_mutation_metadata allows for None

Add test of decoding empty/None metadata from msprime.mutate
(Tests only run on 3.7 or later due to issues with msprime < 1.0)
  • Loading branch information
molpopgen committed May 31, 2021
1 parent 31615ce commit 925e1ea
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 28 deletions.
60 changes: 35 additions & 25 deletions fwdpy11/tskit_tools/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import attr
import tskit

from .._fwdpy11 import Mutation, MutationVector
from .._fwdpy11 import Mutation
from ._flags import (INDIVIDUAL_IS_ALIVE, INDIVIDUAL_IS_FIRST_GENERATION,
INDIVIDUAL_IS_PRESERVED)

Expand Down Expand Up @@ -108,41 +108,51 @@ def decode_individual_metadata(tc: tskit.TableCollection):
return rv


def decode_mutation_metadata(tc: tskit.TableCollection) -> MutationVector:
def decode_mutation_metadata(
tc: tskit.TableCollection,
) -> typing.List[typing.Optional[Mutation]]:
"""
Decodes a :class:`tskit.MutationTable`.
Decodes metadata from a :class:`tskit.MutationTable`.
:param tc: A table collection
:type tc: :class:`tskit.TableCollection`
:returns: Mutations
:rtype: :class:`fwdpy11.MutationVector`
:rtype: list
.. versionadded:: 0.12.0
.. versionchanged:: 0.14.2
Return type is now a list, allowing
some elements to be `None`.
"""
mutations = MutationVector()
mutations = []
for m in tc.mutations:
md = m.metadata
if "esizes" not in md:
mutations.append(
Mutation(
pos=tc.sites.position[m.site],
s=md["s"],
h=md["h"],
g=md["origin"],
label=md["label"],
if md is not None:
if "esizes" not in md:
mutations.append(
Mutation(
pos=tc.sites.position[m.site],
s=md["s"],
h=md["h"],
g=md["origin"],
label=md["label"],
)
)
)
else:
mutations.append(
Mutation(
pos=tc.sites.position[m.site],
s=md["s"],
h=md["h"],
g=md["origin"],
esizes=md["esizes"],
heffects=md["heffects"],
label=md["label"],
else:
mutations.append(
Mutation(
pos=tc.sites.position[m.site],
s=md["s"],
h=md["h"],
g=md["origin"],
esizes=md["esizes"],
heffects=md["heffects"],
label=md["label"],
)
)
)
else:
mutations.append(None)
return mutations
2 changes: 1 addition & 1 deletion fwdpy11/tskit_tools/metadata_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@
MutationMetadata = tskit.metadata.MetadataSchema(
{
"codec": "struct",
"type": "object",
"type": ["object", "null"],
"name": "Mutation metadata",
"properties": {
"s": {"type": "number", "binaryFormat": "d"},
Expand Down
14 changes: 12 additions & 2 deletions tests/test_metadata_roundtrips_via_simulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@

import json

import fwdpy11
import msprime
import numpy as np
import pytest

import fwdpy11


@pytest.fixture
def pdict(request):
Expand Down Expand Up @@ -55,6 +55,8 @@ def inception():
@pytest.mark.parametrize("pdict", [{"simlen": 10}], indirect=["pdict"])
@pytest.mark.parametrize("pop", [{"N": 100, "L": 1}], indirect=["pop"])
def test_metadata_roundtrip_single_sim(rng, pdict, pop):
import sys

params = fwdpy11.ModelParams(**pdict)

r = fwdpy11.RandomAncientSamples(seed=42, samplesize=2, timepoints=[3])
Expand All @@ -63,6 +65,14 @@ def test_metadata_roundtrip_single_sim(rng, pdict, pop):

ts = pop.dump_tables_to_tskit()

if sys.version_info.minor > 6:
# FIXME: this is a hack to avoid the test failing with msprime < 1.0
# add neutral mutations w/no metadata
ts = msprime.mutate(ts, rate=1.0, random_seed=654321)
# bulk decode the mutation metadata, which is all None
mutation_md = fwdpy11.tskit_tools.decode_mutation_metadata(ts.tables)
assert all([i is None for i in mutation_md])

assert len(ts.tables.individuals) == pop.N + 2
first = 0
preserved = 0
Expand Down

0 comments on commit 925e1ea

Please sign in to comment.