{"id":255,"library":"iniconfig","title":"iniconfig","description":"iniconfig is a minimal, read-only INI-file parser maintained under the pytest-dev umbrella. It preserves section and key order, supports multi-line values, strips `#` comments from structure (not inline values in <2.3), raises `ParseError` with accurate line numbers, and rejects duplicate section names. Current stable version is 2.3.0, released 2024. Release cadence is irregular but healthy, driven by pytest ecosystem needs.","status":"active","version":"2.3.0","language":"python","source_language":"en","source_url":"https://github.com/pytest-dev/iniconfig","tags":["ini","config","configuration","parser","pytest","settings"],"install":[{"cmd":"pip install iniconfig","lang":"bash","label":"pip"}],"dependencies":[],"imports":[{"note":"Top-level module import; IniConfig is the only public class. Also available as `from iniconfig import IniConfig`.","symbol":"IniConfig","correct":"import iniconfig\nini = iniconfig.IniConfig('example.ini')"},{"note":"Pass raw INI text via the `data` keyword argument; path is required positionally but ignored when data is provided — pass a sentinel or empty string.","symbol":"IniConfig (from string)","correct":"import iniconfig\nini = iniconfig.IniConfig(path=None, data='[s]\\nk=v\\n')"},{"note":"IniConfig.parse() was added in 2.3.0 and strips inline comments and handles Unicode whitespace. IniConfig() itself still does NOT strip inline comments.","wrong":"iniconfig.IniConfig('f.ini')  # inline comments NOT stripped before 2.3","symbol":"IniConfig.parse (2.3+)","correct":"from iniconfig import IniConfig\nresult = IniConfig.parse('[s]\\nk=v # comment\\n')"},{"note":"Raised on malformed INI input (duplicate sections, bad syntax). Must be imported explicitly.","symbol":"ParseError","correct":"from iniconfig import ParseError"}],"quickstart":{"code":"import iniconfig\n\nINI_TEXT = \"\"\"\n[database]\nhost = localhost\nport = 5432\nnames = foo,bar\n\n[app]\ndebug = true\n\"\"\"\n\n# Parse from a string (no file needed)\nini = iniconfig.IniConfig(\"-\", data=INI_TEXT)\n\n# Direct access — raises KeyError if key/section missing\nhost = ini[\"database\"][\"host\"]          # 'localhost'\n\n# Safe access with default + optional converter\nport = ini.get(\"database\", \"port\", 5432, int)          # 5432 (int)\nnames = ini.get(\"database\", \"names\", [], lambda x: x.split(\",\"))  # ['foo', 'bar']\nmissing = ini.get(\"database\", \"user\", \"root\")           # 'root'\n\n# Membership check\nassert \"database\" in ini\nassert \"ghost\" not in ini\n\n# Iterate sections\nfor section in ini:\n    print(section.name, list(section.items()))\n\n# Catch parse errors\ntry:\n    bad = iniconfig.IniConfig(\"-\", data=\"[dup]\\n[dup]\\n\")\nexcept iniconfig.ParseError as exc:\n    print(f\"Parse failed: {exc}\")\n","lang":"python","description":"Parse an INI config from a string, access values, use .get() for safe access with a default and optional converter."},"warnings":[{"fix":"Use iniconfig==1.1.1 for Python < 3.10 environments, or upgrade the interpreter.","message":"v2.0.0 dropped Python 2 and older Python 3 (< 3.7) support and changed the packaging. The API surface stayed compatible, but pip will refuse to install 2.x on Python < 3.10 (requires_python >=3.10 as of 2.3.0).","severity":"breaking","affected_versions":"<2.0.0"},{"fix":"Ensure each section name appears exactly once in the INI source before parsing.","message":"Duplicate section names raise ParseError. Unlike stdlib configparser, iniconfig does NOT merge duplicates — the second occurrence is an error, not a silent override.","severity":"breaking","affected_versions":"all"},{"fix":"Use IniConfig.parse() (added in 2.3.0) which does strip inline comments, or strip manually: value.split('#')[0].strip().","message":"Inline comments (e.g. `key = value # comment`) are NOT stripped by IniConfig() — the raw string including `# comment` is returned as the value. This differed silently from the README example in versions 2.0–2.2.","severity":"gotcha","affected_versions":"1.x – 2.2.x"},{"fix":"Use ini.get(section, key, default) instead of direct bracket access for any optional key.","message":"ini['section']['key'] raises KeyError — not returning None — when the section or key is absent. There is no .get() short-circuit on the section-level dict.","severity":"gotcha","affected_versions":"all"},{"fix":"Use stdlib configparser or a different library (e.g. configupdater) if you need to write or round-trip INI files.","message":"iniconfig is READ-ONLY. There is no write-back, set(), or save() method. Attempts to assign to ini['section']['key'] will raise TypeError or silently do nothing depending on the internal namedtuple/mapping type.","severity":"gotcha","affected_versions":"all"},{"fix":"Replace `py.iniconfig` with `import iniconfig` and `iniconfig.IniConfig(...)`.","message":"The old py.iniconfig path (from the `py` / pylib package) was the predecessor of this standalone package. Any code doing `import py; py.iniconfig.IniConfig(...)` is using a long-deprecated shim.","severity":"deprecated","affected_versions":"py<2.0"},{"fix":"Always supply a non-None path: `IniConfig('-', data=my_string)`.","message":"IniConfig constructor requires a path as its first positional argument even when parsing from a string via the `data=` kwarg. Passing `None` raises TypeError; pass a placeholder string like '-' or '<string>' instead.","severity":"gotcha","affected_versions":"all"}],"env_vars":null,"last_verified":"2026-05-12T12:23:41.601Z","next_check":"2026-06-25T00:00:00.000Z","problems":[{"fix":"pip install iniconfig","cause":"The 'iniconfig' package is not installed in your Python environment.","error":"ModuleNotFoundError: No module named 'iniconfig'"},{"fix":"Ensure your .ini file starts with a valid section header, e.g., `[section_name]`, and all subsequent sections are correctly defined. All content must belong to a section.","cause":"The INI file being parsed contains content before the first section header, or a section header is malformed or missing where expected.","error":"iniconfig.ParseError: <filename>:<line_number>: no section header defined"},{"fix":"Verify that the file path is correct and the .ini file exists at that location. Use an absolute path or ensure the file is in the current working directory or a correctly referenced path.","cause":"The path provided to `iniconfig.IniConfig()` does not point to an existing .ini file.","error":"FileNotFoundError: [Errno 2] No such file or directory: '<file_path>'"},{"fix":"Check the exact spelling and existence of the section and key in your .ini file. Use the `.get()` method (e.g., `ini.get('section', 'key')` or `ini['section'].get('key')`) to safely retrieve values, which allows for a default return value if the key/section is not found, preventing a KeyError.","cause":"You are attempting to access a section or a key within a section using dictionary-style access (`ini['section']` or `ini['section']['key']`) that does not exist in the parsed INI configuration.","error":"KeyError: 'section_name' (or 'key_name')"}],"ecosystem":"pypi","meta_description":null,"install_score":100,"install_tag":"verified","quickstart_score":80,"quickstart_tag":"verified","pypi_latest":null,"install_checks":{"last_tested":"2026-05-12","tag":"verified","tag_description":"installs cleanly on critical runtimes, fast import, recently tested","results":[{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.01,"mem_mb":0.5,"disk_size":"17.8M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.01,"mem_mb":0.5,"disk_size":"18M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.02,"mem_mb":0.7,"disk_size":"19.7M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.02,"mem_mb":0.7,"disk_size":"20M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.01,"mem_mb":0.6,"disk_size":"11.5M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.01,"mem_mb":0.6,"disk_size":"12M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.01,"mem_mb":0.7,"disk_size":"11.2M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.01,"mem_mb":0.5,"disk_size":"12M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.01,"mem_mb":0.5,"disk_size":"17.3M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.01,"mem_mb":0.5,"disk_size":"18M"}]},"quickstart_checks":{"last_tested":"2026-04-23","tag":"verified","tag_description":"quickstart runs on critical runtimes, recently tested","results":[{"runtime":"python:3.10-alpine","exit_code":0},{"runtime":"python:3.10-slim","exit_code":0},{"runtime":"python:3.11-alpine","exit_code":0},{"runtime":"python:3.11-slim","exit_code":0},{"runtime":"python:3.12-alpine","exit_code":0},{"runtime":"python:3.12-slim","exit_code":0},{"runtime":"python:3.13-alpine","exit_code":0},{"runtime":"python:3.13-slim","exit_code":0},{"runtime":"python:3.9-alpine","exit_code":0},{"runtime":"python:3.9-slim","exit_code":0}]}}