개발자 가이드
이 가이드는 PhyloForester에 기여하거나 기능을 확장하려는 개발자를 위한 문서예요.
아키텍처 개요
PhyloForester는 계층화된 아키텍처를 따라요:
┌─────────────────────────────┐
│ PhyloForester.py │ Main Application
│ (Qt Main Window) │
└──────────────┬──────────────┘
│
┌──────────────┴──────────────┐
│ PfDialog.py │ Dialog Layer
│ (UI Components) │
└──────────────┬──────────────┘
│
┌──────────────┴──────────────┐
│ PfModel.py │ Data Model Layer
│ (Peewee ORM) │
└──────────────┬──────────────┘
│
┌──────────────┴──────────────┐
│ PfUtils.py │ Utility Layer
│ (Helpers, Parsers) │
└─────────────────────────────┘
핵심 컴포넌트
PhyloForester.py (메인 애플리케이션)
PhyloForesterMainWindow: 메인 윈도우 클래스트리 뷰 관리
시그널/슬롯 연결
메뉴 및 툴바 설정
PfModel.py (데이터베이스 모델)
PfProject: 프로젝트 모델PfDatamatrix: 데이터매트릭스 모델PfAnalysis: 분석 모델PfTree: 트리 모델PfPackage: 외부 소프트웨어 메타데이터
PfDialog.py (다이얼로그)
ProjectDialog: 프로젝트 속성DatamatrixDialog: 데이터매트릭스 에디터AnalysisDialog: 분석 설정AnalysisViewer: 결과 뷰어TreeViewer: 트리 시각화
PfUtils.py (유틸리티)
PhyloDatafile: 데이터 가져오기/내보내기PhyloTreefile: 트리 파싱파일 형식 파서 (Nexus, Phylip, TNT)
조상 상태 복원을 위한 Fitch 알고리즘
개발 환경 설정
사전 요구사항
Python 3.9+
Git
Qt5 개발 라이브러리 (PyQt5용)
저장소 복제
git clone https://github.com/jikhanjung/PhyloForester.git
cd PhyloForester
가상 환경 생성
python -m venv venv
# Windows
venv\\Scripts\\activate
# macOS/Linux
source venv/bin/activate
의존성 설치
# Runtime dependencies
pip install -r requirements.txt
# Development dependencies
pip install -r requirements-ci.txt
소스에서 실행
python PhyloForester.py
코드 구조
데이터 저장소
런타임 상태는 self.data_storage 딕셔너리에 저장돼요:
data_storage = {
'project': {
<project_id>: {
'object': <PfProject instance>,
'widget': <QWidget>,
'tree_item': <QStandardItem>,
'datamatrix': {} # nested datamatrices
}
},
'datamatrix': {
<datamatrix_id>: {
'object': <PfDatamatrix instance>,
'widget': <QWidget>,
'tree_item': <QStandardItem>,
'analysis': {} # nested analyses
}
},
'analysis': {
<analysis_id>: {
'object': <PfAnalysis instance>,
'widget': <QWidget>,
'tree_item': <QStandardItem>
}
}
}
이를 통해 중복된 데이터베이스 쿼리를 방지하고 UI 일관성을 유지해요.
데이터베이스 스키마
class PfProject(BaseModel):
name = CharField()
description = TextField(null=True)
class PfDatamatrix(BaseModel):
project = ForeignKeyField(PfProject, backref='datamatrices')
name = CharField()
datamatrix_json = TextField() # JSON serialized matrix
taxa_list_json = TextField() # JSON serialized taxa names
character_list_json = TextField() # JSON serialized characters
class PfAnalysis(BaseModel):
datamatrix = ForeignKeyField(PfDatamatrix, backref='analyses')
name = CharField()
analysis_type = CharField() # 'Parsimony', 'ML', 'Bayesian'
status = CharField() # 'READY', 'RUNNING', 'COMPLETED', etc.
parameters_json = TextField()
class PfTree(BaseModel):
analysis = ForeignKeyField(PfAnalysis, backref='trees')
tree_newick = TextField()
tree_options_json = TextField()
테스트 실행
PhyloForester는 테스트에 pytest를 사용해요.
모든 테스트 실행
pytest tests/ -v
특정 테스트 파일 실행
pytest tests/test_utils.py -v
커버리지와 함께 실행
pytest tests/ --cov=. --cov-report=html
커버리지 보고서 보기: htmlcov/index.html
테스트 카테고리
테스트는 카테고리별로 마크되어 있어요:
@pytest.mark.unit: 유닛 테스트@pytest.mark.model: 데이터베이스/모델 테스트@pytest.mark.dialog: UI/다이얼로그 테스트
특정 카테고리 실행:
pytest -m unit
코드 품질
린팅
PhyloForester는 린팅에 Ruff를 사용해요:
ruff check .
자동 수정:
ruff check . --fix
코드 스타일
PEP 8 가이드라인을 따라요
의미 있는 변수명을 사용해요
공개 함수/클래스에 docstring을 추가해요
함수를 집중되고 짧게 유지해요
타입 힌트
실용적인 곳에 타입 힌트를 사용해요:
def parse_nexus_file(filepath: str) -> Dict[str, Any]:
"""Parse a Nexus format file.
Args:
filepath: Path to Nexus file
Returns:
Dictionary with parsed data
"""
pass
기여하기
워크플로우
저장소를 포크해요
기능 브랜치를 생성해요:
git checkout -b feature/my-feature변경사항을 만들고 커밋해요:
git commit -m "Add my feature"브랜치에 푸시해요:
git push origin feature/my-featureGitHub에서 풀 리퀘스트를 생성해요
커밋 메시지
컨벤셔널 커밋을 따라요:
feat:: 새로운 기능fix:: 버그 수정docs:: 문서 변경refactor:: 코드 리팩토링test:: 테스트 추가/변경chore:: 유지보수 작업
예시:
feat: Add support for FASTA format import
- Implement FASTA parser in PfUtils
- Add FASTA to import dialog options
- Add tests for FASTA parsing
풀 리퀘스트 가이드라인
풀 리퀘스트가 무엇을 하는지 설명해요
관련된 이슈를 참조해요
새로운 기능에 대한 테스트를 포함해요
필요한 경우 문서를 업데이트해요
CI 테스트가 통과하는지 확인해요
문서 빌드
Sphinx를 설치해요:
pip install -r docs/requirements.txt
HTML 문서를 빌드해요:
cd docs
sphinx-build -b html . _build/html
보기: docs/_build/html/index.html
변경 시 자동 재빌드:
sphinx-autobuild docs docs/_build/html
실행 파일 빌드
PhyloForester는 독립 실행 파일을 빌드하기 위해 PyInstaller를 사용해요.
빌드 스크립트
build.py 스크립트를 사용해요:
python build.py
자동으로 다음을 수행해요:
수동 PyInstaller
또는 PyInstaller를 직접 사용해요:
pyinstaller PhyloForester.spec
플랫폼별 참고사항
Windows:
.exe파일을 생성해요선택적으로 Inno Setup 설치 프로그램을 생성해요
대상 시스템에 Visual C++ 재배포 패키지가 필요해요
macOS:
.app번들을 생성해요배포를 위해 코드 서명이 필요할 수 있어요
DMG 이미지를 위해 ``create-dmg``를 사용해요
Linux:
독립 실행 파일을 생성해요
Qt5 라이브러리를 함께 배포해야 할 수 있어요
배포를 위해 AppImage를 고려해요
버전 관리
PhyloForester는 시맨틱 버저닝(semver)을 사용해요.
버전 업데이트
manage_version.py 스크립트를 사용해요:
# Increment patch (0.1.0 -> 0.1.1)
python manage_version.py patch
# Increment minor (0.1.0 -> 0.2.0)
python manage_version.py minor
# Increment major (0.1.0 -> 1.0.0)
python manage_version.py major
# Start pre-release (0.1.0 -> 0.2.0-alpha.1)
python manage_version.py preminor
스크립트는 다음을 수행해요:
릴리스 프로세스
버전 업데이트:
python manage_version.py minor릴리스 노트로 ``CHANGELOG.md``를 업데이트해요
변경사항을 커밋해요
GitHub에 푸시해요:
git push origin main태그를 생성하고 푸시해요:
git push origin v0.2.0GitHub Actions가 자동으로 빌드하고 릴리스해요
CI/CD 파이프라인
PhyloForester는 CI/CD에 GitHub Actions를 사용해요.
워크플로우
test.yml - 자동화된 테스트
푸시/풀 리퀘스트 시 실행돼요
Python 3.9, 3.10, 3.11을 테스트해요
코드 커버리지를 측정해요
린터를 실행해요
build.yml - 빌드 아티팩트
main에 푸시 시 실행돼요
Windows/macOS/Linux를 빌드해요
빌드 아티팩트를 업로드해요
build.py스크립트를 사용해요
release.yml - 자동화된 릴리스
git 태그 (v*.*.*)에서 트리거돼요
먼저 테스트를 실행해요
모든 플랫폼을 빌드해요
GitHub 릴리스를 생성해요
설치 프로그램/패키지를 업로드해요
수동 릴리스
GitHub Actions UI를 사용해요:
Actions → Manual Release로 이동해요
“Run workflow”를 클릭해요
버전 번호를 입력해요
사전 릴리스/초안 옵션을 선택해요
“Run workflow”를 클릭해요
기능 추가
새로운 분석 유형 추가
새로운 가져오기 형식 추가
UI 확장
커스텀 위젯은 다음을 따라야 해요:
예시:
class CustomTableView(QTableView):
cellChanged = pyqtSignal(int, int, str)
def __init__(self, parent=None):
super().__init__(parent)
# Custom initialization
def custom_method(self):
# Custom functionality
self.cellChanged.emit(row, col, value)
디버깅
로깅
PhyloForester는 Python의 logging 모듈을 사용해요:
import logging
logger = logging.getLogger(__name__)
logger.debug("Debug message")
logger.info("Info message")
logger.warning("Warning message")
logger.error("Error message")
PyQt 디버깅
Qt 경고를 활성화해요:
export QT_DEBUG_PLUGINS=1
python PhyloForester.py
데이터베이스 검사
SQLite 브라우저를 사용해요:
sqlite3 ~/PaleoBytes/PhyloForester/PhyloForester.db
또는 DB Browser for SQLite (GUI)를 사용해요
리소스
PyQt5 문서: https://www.riverbankcomputing.com/static/Docs/PyQt5/
Peewee ORM: http://docs.peewee-orm.com/
Pytest: https://docs.pytest.org/
Sphinx: https://www.sphinx-doc.org/