Replace isort, flake8, pycln and pyupgrade by ruff. [Ruff](https://github.com/charliermarsh/ruff) is getting popular lately, and I really like the idea of having a single tool for Python lining instead of N which currently exist. Also written in Rust which is a good use case for this.

 It's supposed to have equivalent functionality, to the ones we are using. The fact that major projects are adopting it is a good sign (see list in their readme).  There are also a few extra options in their readme that look interesting and that we could enable (without having to install yet another plugin)

We won't gain much speed-wise: previously isort, flake8 (which itself is an abstraction over pycodestyle and pyflakes), pycln and pyupgrade  on all files was around 1s, and now it's 20ms. But with mypy taking 10s, it makes mostly no difference.
Still it makes the overall linting configuration easier to maintain.


If we go forward with this, I imagine a changelog is not needed? 

[tool.mypy]
python_version = "3.10"
mypy_path = ["src/py", "pyodide-build"]
show_error_codes = true
warn_unreachable = true
enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"]
plugins = ["pydantic.mypy"]

# Strict checks
warn_unused_configs = true
check_untyped_defs = true
disallow_any_generics = true
disallow_subclassing_any = false
disallow_untyped_calls = false
disallow_untyped_defs = false
disallow_incomplete_defs = true
disallow_untyped_decorators = true
no_implicit_optional = true
warn_redundant_casts = true
warn_unused_ignores = true
warn_return_any = false
no_implicit_reexport = true
strict_equality = true

[[tool.mypy.overrides]]
module = [
  "_pyodide_core",
  "docutils.parsers.rst",
  "js",
  "pyodide_js",
  "ruamel.yaml",
  "matplotlib.*",
  "PIL.*",
  "virtualenv",
  "termcolor",
  "test",
  "tomllib",
  "tomli",
  "typer",
]
ignore_missing_imports = true

[tool.pycln]
all = true

[tool.isort]
profile = "black"
known_first_party = [
  "pyodide",
  "pyodide_js",
  "micropip",
  "pyodide_build",
  "_pyodide",
  "js",
]
known_third_party = [
  "build",
]

[tool.pyodide]

[tool.mypy]
python_version = "3.10"
mypy_path = ["src/py", "pyodide-build"]
show_error_codes = true
warn_unreachable = true
enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"]
plugins = ["pydantic.mypy"]

# Strict checks
warn_unused_configs = true
check_untyped_defs = true
disallow_any_generics = true
disallow_subclassing_any = false
disallow_untyped_calls = false
disallow_untyped_defs = false
disallow_incomplete_defs = true
disallow_untyped_decorators = true
no_implicit_optional = true
warn_redundant_casts = true
warn_unused_ignores = true
warn_return_any = false
no_implicit_reexport = true
strict_equality = true

[[tool.mypy.overrides]]
module = [
  "_pyodide_core",
  "docutils.parsers.rst",
  "js",
  "pyodide_js",
  "ruamel.yaml",
  "matplotlib.*",
  "PIL.*",
  "virtualenv",
  "termcolor",
  "test",
  "tomllib",
  "tomli",
  "typer",
]
ignore_missing_imports = true

[tool.ruff]
select = [
  "E",     # pycodestyles
  "W",     # pycodestyles
  "F",     # pyflakes
  "B0",    # bugbear (all B0* checks enabled by default)
  "B904",  # bugbear (Within an except clause, raise exceptions with raise ... from err)
  "B905",  # bugbear (zip() without an explicit strict= parameter set.)
  "UP",    # pyupgrade
  "I",     # isort
  "PGH",   # pygrep-hooks
]
# Remove E999 once pattern matching is supported
# https://github.com/charliermarsh/ruff/issues/282
ignore = ["E402", "E501", "E731", "E741", "E999"]
target-version = "py311"

[tool.ruff.per-file-ignores]
"src/py/_pyodide/_base.py" = [
  "PGH001",  # No builtin `eval()` allowed
]
"src/tests/test_typeconversions.py" = [
  "PGH001",  # No builtin `eval()` allowed
]


[tool.ruff.isort]
known-first-party = [
  "pyodide",
  "pyodide_js",
  "micropip",
  "pyodide_build",
  "_pyodide",
  "js",
]
known-third-party = [
  "build",
]

[tool.ruff.flake8-bugbear]
extend-immutable-calls = ["typer.Argument", "typer.Option"]

[tool.pyodide]
