[build-system]
requires = [
    "Cython>=0.29.23",
    # Building against NPY2 will support both NPY1 and NPY2
    # https://numpy.org/devdocs/dev/depending_on_numpy.html#build-time-dependency
    "numpy>=2.1.0",
    "setuptools>=65.0.0",
]
build-backend = "setuptools.build_meta"


[project]
name = "pymatgen"
authors = [{ name = "Pymatgen Development Team", email = "shyue@nus.edu.sg" }]
maintainers = [
    { name = "Matthew Horton", email = "m.k.horton@gmail.com" },
    { name = "Shyue Ping Ong", email = "shyue@nus.edu.sg" },
]
description = """
Python Materials Genomics is a robust materials analysis code that defines core object representations for structures
and molecules with support for many electronic structure codes. It is currently the core analysis code powering the
Materials Project (https://materialsproject.org)."""
readme = "README.md"
requires-python = ">=3.11"
keywords = [
    "ABINIT",
    "VASP",
    "analysis",
    "crystal",
    "diagrams",
    "electronic",
    "gaussian",
    "materials",
    "nwchem",
    "phase",
    "project",
    "qchem",
    "science",
    "structure",
]
license = { text = "MIT" }
classifiers = [
    "Development Status :: 4 - Beta",
    "Intended Audience :: Science/Research",
    "License :: OSI Approved :: MIT License",
    "Operating System :: OS Independent",
    "Programming Language :: Python :: 3",
    "Programming Language :: Python :: 3.11",
    "Programming Language :: Python :: 3.12",
    "Programming Language :: Python :: 3.13",
    "Programming Language :: Python :: 3.14",
    "Topic :: Scientific/Engineering :: Chemistry",
    "Topic :: Scientific/Engineering :: Information Analysis",
    "Topic :: Scientific/Engineering :: Physics",
    "Topic :: Software Development :: Libraries :: Python Modules",
]
dependencies = [
    "pymatgen-core>=2026.3.9"
]
version = "2026.3.23"

[project.urls]
Homepage = "https://pymatgen.org"
Documentation = "https://pymatgen.org"
Repository = "https://github.com/materialsproject/pymatgen"
Issues = "https://github.com/materialsproject/pymatgen/issues"
Pypi = "https://pypi.org/project/pymatgen"

[project.optional-dependencies]
abinit = ["netcdf4>=1.7.2"]
ase = ["ase>=3.23.0"]
matcalc = [
    "matcalc>=0.4.0; python_version<'3.13'",
    "matgl>=2.0.4; python_version<'3.13'",
]
mlp = ["matgl>=2.0.4 ; python_version<'3.13'"]
numba = ["numba>=0.55"]
numpy-v1 = ["numpy>=1.25.0,<2"] # Test NP1 on Windows (quite buggy ATM)
optional = [
    "pymatgen[abinit,ase,matcalc,mlp,tblite,zeopp]",
    "beautifulsoup4",
    "pymatgen-analysis-alloys",
    # PR4347: BoltzTraP2 needs to bump cmake version for spglib build
    # "BoltzTraP2>=24.9.4",
    "chemview>=0.6",
    "f90nml>=1.1.2",
    "galore>=0.6.1",
    "h5py>=3.11.0",
    "hiphive>=1.3.1",
    "jarvis-tools>=2020.7.14",
    "phonopy>=2.33.3",
    "seekpath>=2.0.1",
]
prototypes = ["pyxtal>=1.0", "pymatgen[symmetry]"]
# moyopy[interface] includes ase
symmetry = ["moyopy[interface]>=0.3", "spglib>=2.5"]
# tblite only support Python 3.12+ through conda-forge
# https://github.com/tblite/tblite/issues/175
tblite = ["tblite[ase]>=0.3.0; platform_system=='Linux' and python_version<'3.12'"]
vis = ["vtk>=9.6.0"]
zeopp = ["pyzeo; platform_system != 'Windows'"]  # Note: requires Voro++ and Zeo++ to be installed

[project.scripts]
pmg = "pymatgen.cli.pmg:main"
feff_plot_cross_section = "pymatgen.cli.feff_plot_cross_section:main"
feff_plot_dos = "pymatgen.cli.feff_plot_dos:main"
get_environment = "pymatgen.cli.get_environment:main"

[tool.setuptools]
include-package-data = false

[tool.setuptools.packages.find]
where = ["src"]
include = ["pymatgen", "pymatgen.*"]

[tool.setuptools.package-data]
"pymatgen.analysis" = ["*.csv", "*.json", "*.yaml"]
"pymatgen.analysis.chemenv" = [
    "coordination_environments/coordination_geometries_files/*.json",
    "coordination_environments/coordination_geometries_files/*.txt",
    "coordination_environments/strategy_files/ImprovedConfidenceCutoffDefaultParameters.json",
]
"pymatgen.analysis.structure_prediction" = ["*.yaml", "data/*.json"]
"pymatgen.analysis.diffraction" = ["*.json"]
"pymatgen.analysis.magnetism" = ["default_magmoms.yaml"]
"pymatgen.analysis.prototypes" = ["*.json.gz"]
"pymatgen.analysis.solar" = ["am1.5G.dat"]
"pymatgen.analysis.compatibility" = ["*.json.gz", "*.yaml", "data/*.json"]
"pymatgen" = ["py.typed"]
"pymatgen.io.lobster" = ["lobster_basis/*.yaml", "future/lobster_basis/*.yaml"]
"pymatgen.vis" = ["*.yaml"]

[tool.cibuildwheel.linux]
archs = ["auto64"]
skip = ["*musllinux*"]
before-all = "ln -s /usr/lib64/libgfortran.so.5 /usr/lib64/libgfortran.so.3"

[tool.cibuildwheel.macos]
repair-wheel-command = "delocate-wheel --require-archs {delocate_archs} -w {dest_dir} -v {wheel} --ignore-missing-dependencies"

[tool.ruff]
line-length = 120
output-format = "concise"

[tool.ruff.lint]
select = ["ALL"]
ignore = [
    # Rule families
    "ANN", # flake8-annotations (not ready, require types for ALL args)
    "ARG", # Check for unused function arguments
    "BLE", # General catch of Exception
    "C90", # Check for functions with a high McCabe complexity
    "COM", # flake8-commas (conflict with line wrapper)
    "CPY", # Missing copyright notice at top of file (need preview mode)
    "EM", # Format nice error messages
    "ERA", # Check for commented-out code
    "FIX", # Check for FIXME, TODO and other developer notes
    "G", # Validate logging format strings
    "INP", # Ban PEP-420 implicit namespace packages
    "N", # PEP8-naming (many var/arg names are intended)
    "PTH", # Prefer pathlib over os.path
    "SLF", # Access "private" class members
    "T20", # Check for print/pprint
    "TD", # TODO tags related

    # Single rules
    "B023", # Function definition does not bind loop variable
    "B904", # Within an except clause, raise exceptions with ...
    "C408", # unnecessary-collection-call
    "D105", # Missing docstring in magic method
    "D205", # One blank line required between summary line and description
    "D212", # Multi-line docstring summary should start at the first line
    "FBT001", # Boolean-typed positional argument in function definition
    "FBT002", # Boolean default positional argument in function
    "PD011", # (A lot of false positive on non-Pandas objects)
    "PERF203", # Use of try-except in for/while loop
    "PLC0415",  # `import` should be at the top-level of a file
    "PLR0911", # Too many return statements
    "PLR0912", # Too many branches
    "PLR0913", # Too many arguments
    "PLR0915", # Too many statements
    "PLR1702", # Too many nested blocks
    "PLR2004", # Magic-value-comparison TODO: fix this
    "PLW1641", # eq-without-hash TODO: fix this
    "PLW2901", # Outer for loop variable overwritten by inner assignment target
    "PT013", # Incorrect import of pytest
    "RUF043", # Pattern passed to `match=` contains metacharacters but is neither escaped nor raw
    "S110", # Log for try-except-pass
    "S112", # Log for try-except-continue
    "S311", # Use random module for cryptographic purposes
    "S314", # Replace xml with defusedxml to avoid XML attacks
    "S603", # Check source for use of "subprocess" call
    "S607", # Start process with relative path
    "SIM105", # Use contextlib.suppress() instead of try-except-pass
    "SIM905", # Split static strings
    "TRY003", # Avoid specifying long messages outside the exception class
    "TRY300", # Check for return statements in try blocks
    "TRY301", # Check for raise statements within try blocks
]
pydocstyle.convention = "google"
isort.required-imports = ["from __future__ import annotations"]
isort.split-on-trailing-comma = false
isort.known-first-party = ["pymatgen"]

[tool.ruff.format]
docstring-code-format = true

[tool.ruff.lint.per-file-ignores]
"__init__.py" = ["F401"] # unused-import
"tests/**" = [
    "ANN201", # missing-return-type-undocumented-public-function
    "D", # pydocstyle
    "PLR2004", # magic-value-comparison
    "PLR6301", # no-self-use
    "S101", # Use of `assert`
    "S301", # Use of `pickle.load`
]
"src/pymatgen/analysis/*" = ["D"]
"src/pymatgen/io/*" = ["D"]
"dev_scripts/*" = ["D"]

[tool.pytest.ini_options]
# addopts = "-n auto --durations=30 --quiet -r xXs --color=yes --import-mode=importlib"
addopts = "--durations=30 --quiet -r xXs --color=yes --import-mode=importlib"
filterwarnings = [
    # NOTE: the LAST matching option would be used
    "ignore::UserWarning",
]

[tool.coverage.run]
parallel = true
omit = [
    "pymatgen/cli/feff_*.py",
    "pymatgen/cli/pmg_config.py",
    "pymatgen/cli/pmg_plot.py",
    "pymatgen/cli/pmg_potcar.py",
    "pymatgen/dao.py",
]

[tool.coverage.report]
exclude_also = [
    "@deprecated",
    "except ImportError:",
    "raise NotImplementedError",
    "show_plot",
]

[tool.mypy]
mypy_path = "src"
ignore_missing_imports = true
namespace_packages = true
no_implicit_optional = false
disable_error_code = ["annotation-unchecked", "override", "operator", "attr-defined", "union-attr", "call-overload", "index"]
exclude = ['src/pymatgen/analysis', 'src/pymatgen/io/cp2k', 'src/pymatgen/io/lammps']

[[tool.mypy.overrides]]
module = ["requests.*", "tabulate.*", "monty.*", "matplotlib.*"]
ignore_missing_imports = true

[tool.codespell]
# TODO: un-ignore "ist/nd/ot/ontop/CoO" once support file-level ignore with pattern
# https://github.com/codespell-project/codespell/issues/3673
ignore-words-list = """Nd, Te, titel, Mater, nax,
Hart, Lew, Rute, atomate,
ist, nd, ot, ontop, CoO
"""
# TODO: un-skip lammps/test_inputs.py once support block ignore with pattern
# https://github.com/codespell-project/codespell/issues/3381
skip = """*.json,
src/pymatgen/analysis/chemenv/coordination_environments/coordination_geometries_files/allcg.txt,
"""
check-filenames = true

[tool.pyright]
typeCheckingMode = "off"
reportPossiblyUnboundVariable = true
reportUnboundVariable = true
reportMissingImports = false
reportMissingModuleSource = false
reportInvalidTypeForm = false
exclude = ["**/tests"]

[tool.uv]
# TODO: remove `docs` once doc generation is automated
default-groups = ["dev", "test", "lint", "docs"]

[dependency-groups]
dev = [
    "invoke>=2.2.0",
    "openai>=2.2.0",
    "pre-commit>=4.2.0",
]
test = [
    "pytest>=8.3.5",
    "pytest-cov>=6.0.0",
    "pytest-split>=0.10.0",
    "pytest-xdist>=3.0.0"
]
lint = [
    "mypy>=1.15.0",
    "pyright>=1.1.398",
    "ruff>=0.11.3",
]
docs = [
  "sphinx>=8.1.3",
  "sphinx-rtd-theme>=3.0.2",
  "sphinx-markdown-builder>=0.6.8",
]
