content: [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 = "ongsp@ucsd.edu" }]
  maintainers = [
      { name = "Matthew Horton", email = "m.k.horton@gmail.com" },
      { name = "Shyue Ping Ong", email = "ongsp@ucsd.edu" },
  ]
  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.10"
  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.10",
      "Programming Language :: Python :: 3.11",
      "Programming Language :: Python :: 3.12",
      "Programming Language :: Python :: 3.13",
      "Topic :: Scientific/Engineering :: Chemistry",
      "Topic :: Scientific/Engineering :: Information Analysis",
      "Topic :: Scientific/Engineering :: Physics",
      "Topic :: Software Development :: Libraries :: Python Modules",
  ]
  dependencies = [
      "bibtexparser>=1.4.0",
      "joblib>=1",
      "matplotlib>=3.8",
      "monty>=2025.1.9",
      "networkx>=2.7", # PR4116
      # NumPy documentation suggests pinning the current major version as the C API is used
      # https://numpy.org/devdocs/dev/depending_on_numpy.html#runtime-dependency-version-ranges
      "numpy>=1.25.0,<3",
      "orjson>=3.10,<4",
      "palettable>=3.3.3",
      "pandas>=2",
      "plotly>=5.0.0",
      "requests>=2.30",
      "ruamel.yaml>=0.17.0",
      "scipy>=1.13.0",
      # scipy<1.14.1 is incompatible with NumPy 2.0 on Windows
      # https://github.com/scipy/scipy/issues/21052
      "scipy>=1.14.1; platform_system == 'Windows'",
      "spglib>=2.5",
      "sympy>=1.3", # PR #4116
      "tabulate>=0.9",
      "tqdm>=4.60",
      "uncertainties>=3.1.4",
  ]
  version = "2025.6.14"
  
  [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"]
  # TODO: `fdint` seems not maintained anymore and cannot be installed
  # with `uv` on Python 3.10 as build-time dependency was not declared
  # https://github.com/scott-maddox/fdint/issues/21
  # electronic_structure = ["fdint>=2.0.2"]
  matcalc = [
      "matcalc>=0.4.0; python_version<'3.13'",
      "matgl>=1.2.7; python_version<'3.13'",
  ]
  mlp = ["matgl>=1.2.7 ; 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>=6.0.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.entries" = ["*.json.gz", "*.yaml", "data/*.json"]
  "pymatgen.core" = ["*.json", "*.json.gz"]
  "pymatgen" = ["py.typed"]
  "pymatgen.io.vasp" = ["*.json", "*.json.bz2", "*.json.gz", "*.yaml"]
  "pymatgen.io.feff" = ["*.yaml"]
  "pymatgen.io.cp2k" = ["*.yaml"]
  "pymatgen.io.lobster" = ["lobster_basis/*.yaml"]
  "pymatgen.command_line" = ["*"]
  "pymatgen.util" = ["*.json", "structures/*.json"]
  "pymatgen.vis" = ["*.yaml"]
  "pymatgen.io.lammps" = ["CoeffsDataType.yaml", "templates/*.template"]
  "pymatgen.symmetry" = ["*.json", "*.sqlite", "*.yaml"]
  
  [tool.pdm.dev-dependencies]
  lint = ["mypy>=1.10.0", "pre-commit>=3.7.1", "ruff>=0.4.9"]
  test = ["pytest-cov>=5.0.0", "pytest-split>=0.9.0", "pytest>=8.2.2","pytest-xdist>=3.0.0"]
  
  [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"
  filterwarnings = [
      # NOTE: the LAST matching option would be used
      "ignore::UserWarning", # 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",
      "def __repr__",
      "except ImportError:",
      "if TYPE_CHECKING:",
      "if self.debug:",
      "if settings.DEBUG",
      "pragma: no cover",
      "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,
  tests/io/lammps/test_inputs.py,
  dev_scripts/periodic_table_resources/elemental_properties.yaml,
  """
  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",
      "jupyter>=1.1.1",
      "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",
  ]
  