From a99e2cdc5d19083ffd2ef01a60832bbaf037ffcc Mon Sep 17 00:00:00 2001 From: ChrisRackauckas-Claude Date: Mon, 15 Jun 2026 10:16:07 -0400 Subject: [PATCH 1/4] Fix QA group dispatch: pass QA via the `qa` kwarg, not `groups` The canonicalization conversion (#154) placed the QA group inside the `groups` Dict, but SciMLTesting's `run_tests` routes `GROUP="QA"` through a dedicated `elseif group == "QA"` branch that consumes the `qa` keyword argument and short-circuits before the `groups` table is ever consulted. With `qa` unset, that branch throws ArgumentError: run_tests: GROUP="QA" was requested but no `qa` body was provided so the QA CI job failed on master before loading FEniCS. Moving the QA spec to the `qa` kwarg (matching the documented SciMLTesting form) makes `GROUP="QA"` reach the QA body, while `all = ["Core"]` keeps QA out of the default `GROUP="All"`/local `]test` run as before. Co-Authored-By: Chris Rackauckas Co-Authored-By: Claude Opus 4.8 (1M context) --- test/runtests.jl | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index b5c4068..6bb824f 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -5,11 +5,9 @@ run_tests(; # body (core.jl) rather than as independent per-file groups, so it is passed # explicitly instead of being discovered as a folder. core = joinpath(@__DIR__, "core.jl"), - groups = Dict( - "QA" => (; - env = joinpath(@__DIR__, "qa"), - body = joinpath(@__DIR__, "qa", "qa.jl"), - ), + qa = (; + env = joinpath(@__DIR__, "qa"), + body = joinpath(@__DIR__, "qa", "qa.jl"), ), # The original ran only the Core body for the default GROUP="All"; QA ran only # when explicitly selected (it exited early before loading FEniCS). From 59cf4a60b0855b54165a9ef482266e1aa78af732 Mon Sep 17 00:00:00 2001 From: ChrisRackauckas-Claude Date: Tue, 16 Jun 2026 08:15:19 -0400 Subject: [PATCH 2/4] ci: re-trigger against SciML/.github v1.15.1 Verify the scoped GitHub-hosted runner routing (SciML/.github #97) now sends this repo's apt-packages/container legs to ubuntu-24.04. Co-Authored-By: Chris Rackauckas Co-Authored-By: Claude Opus 4.8 (1M context) From 85a709b7ce93674226c5768184e535c383993fe2 Mon Sep 17 00:00:00 2001 From: ChrisRackauckas-Claude Date: Tue, 16 Jun 2026 08:43:41 -0400 Subject: [PATCH 3/4] Fix FEniCS package-quality (QA) failures surfaced by the QA group The QA group now actually runs FEniCS's own Aqua/JET checks, surfacing six pre-existing package-quality issues. Fix the real causes: - Type piracy + Base.write method ambiguity: `write(path, solution, time::Number)` extended `Base.write` with no FEniCS-owned argument type, which is piracy and also clashed with `Base.write(::IO, x1, xs...)`. Stop importing `write` from Base so `write`/`store` are FEniCS-owned functions (still exported); behavior unchanged. - Undefined export: `export fenicsclass` referenced a nonexistent binding; the macro is `@fenicsclass`. Export the macro. - JET no-matching-method: `Argument(V, number)` lowered to `Argument(::Any, ::Any, ::Nothing)` because `part::StringOrSymbol` cannot accept its own `nothing` default. Widen to `Union{StringOrSymbol, Nothing}`. - Stale dependency: ProgressMeter was declared but unused (only a dead `@require ... using ProgressMeter` no-op). Drop it from deps, compat, and the no-op __init__ block. - deps_compat: add a `[compat]` entry for the LinearAlgebra stdlib. Co-Authored-By: Chris Rackauckas Co-Authored-By: Claude Opus 4.8 (1M context) --- Project.toml | 3 +-- src/FEniCS.jl | 7 ++----- src/jfem.jl | 2 +- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/Project.toml b/Project.toml index 5ecd8e7..020f25c 100644 --- a/Project.toml +++ b/Project.toml @@ -4,7 +4,6 @@ version = "1.2.0" [deps] LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" -ProgressMeter = "92933f4c-e287-5a05-a399-4b506db050ca" PyCall = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0" Requires = "ae029012-a4dd-5104-9daa-d747884805df" SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b" @@ -12,9 +11,9 @@ SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b" [compat] ADTypes = "1" ExplicitImports = "1" +LinearAlgebra = "1" OrdinaryDiffEq = "6, 7" OrdinaryDiffEqSDIRK = "1, 2" -ProgressMeter = "1.2" PyCall = "1.90" Requires = "0.5, 1.0" SafeTestsets = "0.1, 1" diff --git a/src/FEniCS.jl b/src/FEniCS.jl index 65d8cd7..df05100 100644 --- a/src/FEniCS.jl +++ b/src/FEniCS.jl @@ -21,9 +21,6 @@ const mshr = PyCall.PyNULL() function __init__() @require PyPlot = "d330b81b-6aea-500a-939a-2ce795aea3ee" include("jplot.jl") - @require ProgressMeter = "92933f4c-e287-5a05-a399-4b506db050ca" begin - using ProgressMeter - end copy!(fenics, pyimport_conda("fenics", "fenics=2019.1.0", "conda-forge")) copy!(ufl, pyimport_conda("ufl", "ufl=2019.1.0", "conda-forge")) include_mshr && copy!(mshr, pyimport_conda("mshr", "mshr=2019.1.0", "conda-forge")) @@ -41,7 +38,7 @@ function __init__() end #the below code is an adaptation of aleadev.FEniCS.jl import Base: size, length, show, *, +, -, /, ^, sin, cos, tan, asin, acos, atan, exp, log, - repr, div, sqrt, split, write + repr, div, sqrt, split import SpecialFunctions: besseli, besselj, besselk, bessely export besseli, besselj, besselk, bessely @@ -68,7 +65,7 @@ macro fenicsclass(name::Symbol, base1::Symbol = :fenicsobject) end ) end -export fenicsclass +export @fenicsclass @enum LOGLEVEL begin CRITICAL = 50 diff --git a/src/jfem.jl b/src/jfem.jl index 80ab1e1..619cf14 100644 --- a/src/jfem.jl +++ b/src/jfem.jl @@ -17,7 +17,7 @@ end export FunctionSpace, VectorFunctionSpace @fenicsclass Expression -function Argument(V, number, part::StringOrSymbol = nothing) +function Argument(V, number, part::Union{StringOrSymbol, Nothing} = nothing) return Expression(fenics.Argument(V.pyobject, number, part = part)) end TrialFunction(V::FunctionSpace) = Expression(fenics.TrialFunction(V.pyobject)) From f70877a8fc93c6534fe1ba3171831738fbd70eb6 Mon Sep 17 00:00:00 2001 From: ChrisRackauckas-Claude Date: Tue, 16 Jun 2026 09:13:09 -0400 Subject: [PATCH 4/4] Keep write/store as Base.write extension; fix piracy+ambiguity via arg types The prior commit removed `write` from the `Base` import to kill the type piracy, but that made `FEniCS.write` a distinct exported binding that clashed with the exported `Base.write` ("both FEniCS and Base export write"), breaking the Core examples (tutorial8/9: `UndefVarError: write`). Restore `import Base: ...write` so `write` stays a single function, and fix the two QA findings on it through argument types instead: - Type piracy: `write` now takes `solution::fenicsobject` (a FEniCS-owned type), so the method is owned by FEniCS rather than pirating Base. The unused, unavoidably-piratical `write(::Any, ::PyObject, ::Number)` overload is dropped (use `store` for raw vectors like `vector(u)`). - Method ambiguity: type `path::PyObject` (what `XDMFFile`/`TimeSeries` return), which is disjoint from `Base.write(::IO, ...)` and `write(::AbstractString, ...)`, removing both ambiguities. `store` is FEniCS-owned (not a Base function), so its overloads are not piracy; `path::PyObject` is added there too for symmetry/correctness. Co-Authored-By: Chris Rackauckas Co-Authored-By: Claude Opus 4.8 (1M context) --- src/FEniCS.jl | 2 +- src/jsolve.jl | 15 ++++++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/FEniCS.jl b/src/FEniCS.jl index df05100..48e9eb2 100644 --- a/src/FEniCS.jl +++ b/src/FEniCS.jl @@ -38,7 +38,7 @@ function __init__() end #the below code is an adaptation of aleadev.FEniCS.jl import Base: size, length, show, *, +, -, /, ^, sin, cos, tan, asin, acos, atan, exp, log, - repr, div, sqrt, split + repr, div, sqrt, split, write import SpecialFunctions: besseli, besselj, besselk, bessely export besseli, besselj, besselk, bessely diff --git a/src/jsolve.jl b/src/jsolve.jl index a9b1785..691bb26 100644 --- a/src/jsolve.jl +++ b/src/jsolve.jl @@ -142,11 +142,16 @@ TimeSeries(path::StringOrSymbol) = fenics.TimeSeries(path) retrieve(timeseries, placeholder, time) = timeseries.retrieve(placeholder, time) export TimeSeries, retrieve -write(path, solution, time::Number) = path.write(solution.pyobject, time) -write(path, solution::PyObject, time::Number) = path.write(solution, time) - -store(path, solution, time::Number) = path.store(solution.pyobject, time) -store(path, solution::PyObject, time::Number) = path.store(solution, time) +# `write` extends `Base.write`. Typing `solution::fenicsobject` keeps this from +# being type piracy (a FEniCS-owned argument), and typing `path::PyObject` (the +# value returned by `XDMFFile`/`TimeSeries`) keeps it from being ambiguous with +# `Base.write(::IO, ...)` / `write(::AbstractString, ...)`. A raw-`PyObject` +# solution is unused; use `store` (a FEniCS-owned function) for raw vectors such +# as `vector(u)`. +write(path::PyObject, solution::fenicsobject, time::Number) = path.write(solution.pyobject, time) + +store(path::PyObject, solution, time::Number) = path.store(solution.pyobject, time) +store(path::PyObject, solution::PyObject, time::Number) = path.store(solution, time) export write, store