Upgrade SymPy - #193
Open
FrederikSchnack wants to merge 19 commits into
Open
Upgrade SymPy#193FrederikSchnack wants to merge 19 commits into
FrederikSchnack wants to merge 19 commits into
Conversation
Delete the unmaintained old/ snapshots and bin/run_tests.sh. The script references test modules that no longer exist, so it advertises a broken workflow while the deleted snapshots duplicate history already preserved by Git.
Move pytest configuration and development dependencies into pyproject.toml, test installed packages across supported Python versions, and collect coverage as a CI artifact. Keep the tested SymPy upper bound in place while #106 tracks the compatibility work needed for current releases.
Delete the unreferenced 2019 roadmap, which describes removed APIs and work that has since been implemented. Active work is tracked through GitHub issues. Refs #181.
Separate test automation from documentation builds and run it for every pull request update.
Use the maintained Sphinx build layout while keeping documentation CI separate from the test matrix.
Publish strict Sphinx builds from master through GitHub Pages, matching the Psydac documentation workflow. Update project links and remove the obsolete Read the Docs configuration. Addresses #166.
Build the documentation when pull requests are opened, reopened, or synchronized, in addition to ready-for-review transitions.
Construct function symbols and differential forms through Symbol so that SymPy initializes their assumptions and free-symbol state. Keep their SymPDE metadata in structural identity without exposing non-Basic values through args. Refs #106
Keep the transformed IntAdd as a SymPy expression instead of wrapping it in a Python list. Modern SymPy strictly sympifies constructor postprocessor results and rejected the list while checking form linearity. Refs #106
Convert string, numeric, container, and optional metadata stored in custom Basic.args to SymPy objects. Restore the public Python values through properties so callers keep the existing API while traversal, printing, hashing, and substitution can safely inspect expression trees. Also preserve integer DifferentialForm dimensions and the historical name-based identity of function symbols. Refs #106
Raise the minimum dependency to SymPy 1.12 for supported Python versions and cap it below 1.15 until the next compatibility review. Keep the regular CI matrix on the newest allowed release and add a Python 3.11 job pinned to the minimum. Refs #106
Use maintained SymPy utilities and native metaclass syntax. The compatibility module remains temporarily available to the legacy package exports until the public API layer removes them.
Accept normalized SymPy arguments in topology, equation, tensor-form, and multipatch-mapping constructors. Preserve structural metadata during rebuilding and cover func/xreplace round trips with regression tests.
Give function spaces structural equality and include them in scalar and vector function hashes. Equal names in different spaces now remain distinct symbols instead of collapsing during SymPy simplification.
Restore the detailed multipatch orientation reference and connectivity examples that were removed while repairing the documentation build.
Keep the full multipatch connectivity notes while marking their example as a Python code block so strict documentation builds remain warning-free.
FrederikSchnack
added this pull request to stack #192
September 29, 2026 15:32
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Update SymPDE to support the maintained SymPy release range:
This PR addresses compatibility problems caused by stricter symbolic construction, traversal, reconstruction, hashing, and sympification behavior
in recent SymPy versions.
Closes #106.
Compatibility issues and fixes
1. Incorrect construction of custom
SymbolsubclassesScalarFunction,VectorFunction, andDifferentialFormwere constructed throughExpr.__new__orBasic.__new__instead of SymPy’sSymbolconstructor.Recent SymPy versions expect symbol subclasses to initialize Symbol-specific state, including assumptions, commutativity, and free-symbol behavior. Without this initialization:
free_symbolscould be incorrect;The affected objects are now constructed through
Symbol.__xnew__.SymPDE-specific metadata, such as the function space or differential-form degree and dimension, is included through
_hashable_contentrather than being passed as invalid raw symbol arguments.Regression tests verify:
free_symbols;2. Non-SymPy values stored in
Basic.argsSeveral SymPDE expression classes stored ordinary Python objects directly in their structural arguments, including:
None;Modern SymPy traverses, hashes, prints, sympifies, and reconstructs every object exposed through
Basic.args. Raw Python metadata could therefore cause failures during operations such as:A common structural-argument normalization layer was introduced:
Strobjects;Integer;Tupleobjects;Dictobjects;Nonevalues use a private SymPy-compatible sentinel.Matching restoration helpers convert these values back to their historical Python representation when accessed through public properties. This preserves the existing SymPDE API while keeping expression trees valid for SymPy.
The normalization is applied to objects including domains, boundaries, interfaces, equations, matrix elements, traces, one-dimensional forms, differential forms, and multipatch mappings.
3. Expressions could not be reconstructed from
funcandargsSymPy assumes that symbolic expressions can generally be rebuilt using:
This mechanism is used internally by substitution,
xreplace, simplification, and other tree transformations.A number of SymPDE constructors did not satisfy this contract because:
args;Constructors were updated to accept and restore normalized structural arguments. Reconstruction now retains information such as:
Regression tests now exercise both reconstruction and substitution:
4. Multipatch mappings used raw dictionaries as symbolic arguments
MultiPatchMappingpreviously placed a Python dictionary directly inBasic.argsand implemented a custom__hash__.Recent SymPy operations expect structural arguments themselves to be symbolic and reconstructible. This caused problems during hashing, replacement, and rebuilding.
The mapping dictionary is now stored structurally as a SymPy
Dict, while the publicmappingsproperty continues to return a regular Python dictionary. Hashing is derived from the normalized structural arguments instead of a separate custom implementation.Tests verify that multipatch mappings survive both reconstruction and
xreplace.5. Function symbols with the same name collapsed across spaces
Function symbols were primarily identified by their printed name. As a result, functions with the same name but belonging to different function spaces could compare as equal and collapse during SymPy simplification.
For example, an expression conceptually equivalent to:
could be simplified as though both functions were the same symbol.
Function spaces now define structural equality from their name, domain, shape, and kind. Scalar and vector function symbols include their function space in
_hashable_content.This ensures that:
6. Constructor postprocessing returned a Python list
The integral multiplication postprocessor wrapped a transformed
IntAddexpression in a Python list before passing it back toMul.Recent SymPy versions strictly sympify constructor-postprocessor results and reject this list during form-linearity checks.
The postprocessor now returns the transformed
IntAddexpression directly:IntAdd(...)instead of:
[IntAdd(...)]7. Legacy SymPy compatibility helpers were outdated
SymPDE carried local copies of compatibility utilities for:
is_sequence;These helpers were replaced with maintained functionality:
sympy.utilities.iterables.is_sequence;VectorFunctionhandling remains explicit where its indexed behavior differs from ordinary Python sequences.The compatibility module itself remains temporarily available because it is still exported by the legacy package namespace. It is removed by the subsequent public-API PR.
8. Domain subclasses were not printed correctly in LaTeX
The custom LaTeX printer only implemented
_print_Domain. Some reconstructed domain-related objects are subclasses ofBasicDomainrather thanDomain, causing modern SymPy’s printer dispatch to miss the custom representation.A
_print_BasicDomainimplementation was added so domain interiors and interfaces consistently render using their symbolic names.Regression tests cover multipatch interiors and interfaces.
Dependency and CI changes
1.5to1.12.1.15.3.11job pinned to SymPy1.12.The upper bound remains intentionally below SymPy
1.15until that release range receives a separate compatibility review.Validation
The test suite passes with the upgraded symbolic implementation:
New regression coverage includes:
free_symbolsbehavior;func(*args)reconstruction;xreplacesubstitutions;