DFAST — 実装レポート / 2026-06-24

MAG / MAG-WGS 対応
実装レポート

mainブランチからの新規実装内容 — DDBJ ENV 提出サポート

5変更ファイル
2新規ファイル
46新規テスト
+220行追加

概要・背景

mainブランチでは project_type は読み込まれていたものの、gnm(complete ゲノム)の判定にのみ使われていました。MAG(Metagenome-Assembled Genome)や MAG-WGS に特有の DDBJ 提出要件(ENV division、MAG キーワード、isolate qualifier、metagenome_source など)はサポートされていませんでした。

本実装では mainブランチとの差分として以下を新規に追加・変更しました。

+
MAG / MAG-WGS の project_type 認識と complete フラグ
mag が complete=True を自動設定。project_type を GENOME_CONFIG に格納し、パイプライン全体に伝播。
+
ENV division と MAG キーワードの自動出力
MAG/MAG-WGS で DIVISION: ENV、KEYWORD: ENV / Metagenome Assembled Genome / MAG を自動追加。
+
isolate フィールドのサポート
metadata → GENOME_SOURCE_INFORMATION → Genome オブジェクト → source feature → ann ファイルまで isolate を一貫して伝播。
+
TSV 駆動の条件付きフィールド制御
required_for / excluded_for 列を追加。strain 除外・isolate/metagenome_source/environmental_sample 必須化をコード変更なしで制御。
✎
ff_definition の @@[strain]@@ → @@[isolate]@@ 切り替え
MAG/MAG-WGS では DEFINITION 行の識別子テンプレートを自動切り替え。
✔
boolean フィールドの render() 修正
environmental_sample(boolean 型)が値なしでも valueless qualifier として正しく出力されるよう render ロジックを修正。

project_type の認識と complete フラグ

config_util.py / genome.py

config_util.py の変更

dfc/utils/config_util.py
- keys = ["organism", "strain", "seq_names", "seq_types", "seq_topologies", "additional_modifiers"] + keys = ["organism", "strain", "isolate", "seq_names", "seq_types", "seq_topologies", "additional_modifiers"] - if project_type == "gnm": - complete = True + if project_type in ("gnm", "mag"): + complete = True + config.GENOME_CONFIG["project_type"] = project_type

genome.py の変更

dfc/genome.py
self.complete = config.GENOME_CONFIG.get("complete", False) +self.project_type = config.GENOME_CONFIG.get("project_type", "") +self.is_mag = self.project_type in ("mag", "mag-wgs") self.organism = config.GENOME_SOURCE_INFORMATION.get("organism", "") self.strain = config.GENOME_SOURCE_INFORMATION.get("strain", "") +self.isolate = config.GENOME_SOURCE_INFORMATION.get("isolate", "")
project_typecompleteis_mag
mag✔ True✔ True
mag-wgs— False✔ True
gnm✔ True— False
wgs— False— False

ENV division と MAG キーワード

metadata_util.py / genome.py

MAG/MAG-WGS では DDBJ の ENV division に提出するため、ann ファイルの COMMON エントリに専用のブロックを出力します。

WGS(変更なし)

COMMON エントリ
DATATYPEtype: WGS
KEYWORDkeyword: WGS
keyword: STANDARD_DRAFT

MAG-WGS(新規)

COMMON エントリ
DIVISIONdivision: ENV
KEYWORDkeyword: ENV
keyword: Metagenome Assembled Genome
keyword: MAG
DATATYPEtype: WGS
KEYWORDkeyword: WGS
keyword: STANDARD_DRAFT

GNM / complete(変更なし)

COMMON エントリ
(DATATYPE/KEYWORD なし)

MAG / complete(新規)

COMMON エントリ
DIVISIONdivision: ENV
KEYWORDkeyword: ENV
keyword: Metagenome Assembled Genome
keyword: MAG

data_file_division(GenBank/EMBL ファイル内部)も BCT から ENV に切り替わります(genome.py の add_source_information())。

isolate フィールドの追加

新規

mainブランチでは isolate はどこにも存在しませんでした。MAG 提出の識別子として strain の代わりに使うため、パイプライン全体に追加しました。

伝播経路

metadata ファイル → config_util → Genome.isolate → record.annotations → source feature qualifier → .ann ファイル

source エントリの source 行

dfc/genome.py — add_source_information()
-source = self.organism + " strain " + self.strain if self.strain else self.organism +if self.is_mag: + source = self.organism + " isolate " + self.isolate if self.isolate else self.organism +else: + source = self.organism + " strain " + self.strain if self.strain else self.organism
ℹ
非 MAG でも isolate が使える: isolate は required_for=mag,mag-wgs ですが、値が設定されている場合は WGS/GNM でも出力されます(should_render の「値ありなら常に出力」ルールによる)。

TSV 駆動の条件付きフィールド制御

新規アーキテクチャ

mainブランチでは MetadataField に project_type の概念が一切なく、EX_SOURCE の出力は field.value or field.mss_required の単純な条件でした。本実装では TSV の 2 列拡張と 4 つの新メソッドでこれを置き換えます。

metadata_definition.tsv への追加フィールド

フィールドtypefeaturemss_requiredrequired_for(新)excluded_for(新)
strain(既存)stringsource TRUE—mag,mag-wgs
isolate ★新規stringsource FALSEmag,mag-wgs—
metagenome_source ★新規stringEX_SOURCE FALSEmag,mag-wgs—
environmental_sample ★新規booleanEX_SOURCE FALSEmag,mag-wgs—

MetadataField に追加したメソッド

def is_required_for(self, project_type: str) -> bool:
    return project_type in self.required_for

def is_excluded_for(self, project_type: str) -> bool:
    return project_type in self.excluded_for

def effective_required(self, project_type: str) -> bool:
    if project_type in self.excluded_for: return False
    if project_type in self.required_for:  return True
    return self.mss_required

def should_render(self, project_type: str) -> bool:
    if project_type in self.excluded_for: return False
    if self.value:                          return True
    return self.effective_required(project_type)

render_ex_source() の変更

dfc/utils/metadata_util.py
-def render_ex_source(self): +def render_ex_source(self, project_type: str = ""): RET = [] for field in self.fields.values(): if field.feature == "source" and field.entry == "EX_SOURCE": - if field.value or field.mss_required: - RET += field.render() + if field.should_render(project_type): + rows = field.render() + if rows: + RET += rows + else: # boolean で値なし → valueless placeholder + RET.append(["", "", "", field.qualifier, ""])

get_field_definition() — 新規追加

genome.py から source feature 生成時に TSV 定義を参照するためのモジュールレベルキャッシュ関数。TSV を一度だけ読み込みます。

# module level
_FIELD_DEF_CACHE: "dict | None" = None

def get_field_definition(name: str):
    global _FIELD_DEF_CACHE
    if _FIELD_DEF_CACHE is None:
        _FIELD_DEF_CACHE = {}
        # TSV を一度だけ読み込んでキャッシュ
        ...
    return _FIELD_DEF_CACHE.get(name)

ff_definition の切り替え

ddbj_submission.py

mainブランチでは ff_definition は常に @@[strain]@@ を使っていました。MAG/MAG-WGS では @@[isolate]@@ に切り替わります。

dfc/utils/ddbj_submission.py — create_ff_definiton()
-def create_ff_definiton(seq_rank, plasmid): +def create_ff_definiton(seq_rank, plasmid, project_type=""): assert seq_rank in ["complete", "scaffold", "contig"] + identifier = "@@[isolate]@@" if project_type in ("mag", "mag-wgs") else "@@[strain]@@" if seq_rank == "complete": if plasmid: - ff_definition = "@@[organism]@@ @@[strain]@@ plasmid @@[plasmid]@@ DNA, complete sequence" + ff_definition = f"@@[organism]@@ {identifier} plasmid @@[plasmid]@@ DNA, complete sequence" - ff_definition = "@@[organism]@@ @@[strain]@@ DNA, complete genome" + ff_definition = f"@@[organism]@@ {identifier} DNA, complete genome" - ff_definition = "@@[organism]@@ @@[strain]@@ DNA, @@[submitter_seqid]@@" + ff_definition = f"@@[organism]@@ {identifier} DNA, @@[submitter_seqid]@@"
project_typeff_definition テンプレート
mag@@[organism]@@ @@[isolate]@@ DNA, complete genome
mag-wgs@@[organism]@@ @@[isolate]@@ DNA, @@[submitter_seqid]@@
gnm@@[organism]@@ @@[strain]@@ DNA, complete genome
wgs@@[organism]@@ @@[strain]@@ DNA, @@[submitter_seqid]@@

出力ファイル名の生成

ddbj_submission.py

mainブランチでは常に biosample_strain パターンでファイル名を生成していました。MAG では strain を使わないため、isolate を使うよう変更しました。

dfc/utils/ddbj_submission.py — get_file_prefix()
- strain = self.genome.strain - if bio_sample_id and strain: - return bio_sample_id + "_" + strain + if getattr(self.genome, "is_mag", False): + identifier = self.genome.isolate + else: + identifier = self.genome.strain + if bio_sample_id and identifier: + return bio_sample_id + "_" + identifier
条件ファイル名
MAG + biosample あり + isolate ありSAMDxxxxxxxx_MAG-001.ann
MAG + biosample のみSAMDxxxxxxxx.ann
WGS + biosample あり + strain ありSAMDxxxxxxxx_strain.ann
いずれも未指定mss.ann

boolean フィールドの render() 修正

metadata_util.py

mainブランチでは boolean フィールドの render() は値が "NO" 以外のとき valueless qualifier を出力する実装でした。environmental_sample=TRUE のときは動作しましたが、値が空(未指定)のときは [] を返すため、MAG のプレースホルダー出力ができませんでした。

dfc/utils/metadata_util.py — MetadataField.render()
+ if self.type == "boolean": + if str(self.value).lower() in ("yes", "true"): + RET.append(["", "", "", self.qualifier, ""]) + return RET # 値なしのときは [] を返す(render_ex_source 側でフォロー) if self.value == "" or self.value == []: RET.append(["", "", "", self.qualifier, ""]) - elif self.type == "boolean" and self.value: - if self.value != "NO": - RET.append(["", "", "", self.qualifier, ""])
⚠
render() が [] を返したとき、render_ex_source() 側で should_render() が True なら valueless placeholder 行を追加するフォールバックを実装しています。これにより environmental_sample は値なしでも MAG 提出時に必ず出力されます。

テスト

新規 46 件
46
総テスト数(全 PASS)
0
失敗・エラー

テストカテゴリ

カテゴリ内容件数
MetadataField 単体 should_render、effective_required、is_excluded_for 等の動作確認 約 12
TSV パース required_for/excluded_for 列の読み込み確認、後方互換性 約 6
render_ex_source MAG/WGS での各フィールド出力確認、boolean valueless 出力 約 8
genome source features strain 除外・isolate プレースホルダー・WGS での isolate 出力 約 8
render_common_entry MAG/MAG-WGS の DIVISION・KEYWORD ブロック出力確認 約 4
DDBJ 提出ファイル生成 create_ff_definiton の @@[isolate]@@ 切り替え、ファイル名生成 約 8

変更ファイル一覧

変更 dfc/utils/config_util.py isolate を GENOME_SOURCE_INFORMATION に追加。mag を complete=True に。project_type を GENOME_CONFIG に格納。
変更 dfc/utils/metadata_util.py MetadataField に required_for/excluded_for と 4 メソッド追加。TSV パーサー拡張。render_common_entry(project_type) で ENV/MAG キーワード出力。render_ex_source(project_type) TSV 駆動化。get_field_definition() 追加。boolean render 修正。
変更 dfc/utils/metadata_definition.tsv 列 10/11(required_for/excluded_for)追加。isolate/metagenome_source/environmental_sample 3 行を新規追加。strain に excluded_for=mag,mag-wgs 設定。
変更 dfc/genome.py self.project_type/self.is_mag/self.isolate 追加。add_source_information() で ENV division・isolate 対応。add_source_features() を TSV 駆動に変更。
変更 dfc/utils/ddbj_submission.py is_mag パラメータ廃止・project_type 統一。create_ff_definiton で @@[isolate]@@ 切り替え。get_file_prefix() で isolate 使用。ENV division JSON 変換対応。
新規 tests/test_mag.py MAG/MAG-WGS 対応の専用テストファイル。46 件すべて PASS。
新規 example/sample.metadata.mag*.txt MAG・MAG-WGS 用サンプルメタデータファイル(full / nofill / min の各バリエーション)。