# Installing legacy FEniCS: Compatibility of ufl\_legacy 2022 with FEniCS 2019

**URL:** <https://fenicsproject.discourse.group/t/installing-legacy-fenics-compatibility-of-ufl-legacy-2022-with-fenics-2019/18163>\
**Category:** installation\
**Tags:** ufl\
**Created:** [August 28, 2025, 11:50pm UTC](https://fenicsproject.discourse.group/t/installing-legacy-fenics-compatibility-of-ufl-legacy-2022-with-fenics-2019/18163 "2025-08-28T23:50:18Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![rojin\_anbar](https://yyz2.discourse-cdn.com/free1/user_avatar/fenicsproject.discourse.group/rojin_anbar/32/8812_2.png) [@rojin\_anbar](https://fenicsproject.discourse.group/u/rojin_anbar)\
**Post date:** [August 28, 2025, 11:50pm UTC](https://fenicsproject.discourse.group/t/installing-legacy-fenics-compatibility-of-ufl-legacy-2022-with-fenics-2019/18163/1 "2025-08-28T23:50:18Z")

</div>

Hi everyone,

I’m setting up **legacy FEniCS 2019.1** on a new HPC system using Apptainer containers. I need to remain on the legacy stack because several other codes I use depend on it, so migrating to FEniCSx isn’t an option right now.

I installed `fenics-ufl-legacy` (version 2022.3.0) with pip, since it is described as the compatible package for legacy FEniCS. A simple `import ufl_legacy` test works fine. Direct imports from the legacy package also work:

```auto
apptainer exec --containall ~/fenics-legacy-updated.sif python3 -c "from ufl_legacy.tensors import ListTensor; print('UFL ok')"

```

However, many of my scripts import from **`ufl.*`**. To accommodate them, I tried aliasing `ufl_legacy` to `ufl`. That succeeds for light, top-level symbols, but importing the **tensors** module fails:

```auto
apptainer exec --containall ~/fenics-legacy-updated.sif python3 -c "import sys; import ufl_legacy as ufl; sys.modules['ufl']=ufl; from ufl.tensors import ListTensor; print('UFL ok')"

```

**Error:**

```auto
  File "/usr/lib/python3/dist-packages/ufl_legacy/tensors.py", line 25, in <module>
    class ListTensor(Operator):
  File "/usr/lib/python3/dist-packages/ufl_legacy/core/ufl_type.py", line 370, in _ufl_type_decorator_
    check_type_traits_consistency(cls)
  File "/usr/lib/python3/dist-packages/ufl_legacy/core/ufl_type.py", line 132, in check_type_traits_consistency
    assert Expr._ufl_num_typecodes_ == len(Expr._ufl_all_handler_names_)
AssertionError

```

What I think might be happening is that somehow two different versions of UFL (or parts of UFL and UFL-legacy) are being imported at the same time, leading to mismatched type registries. I have verified there is no separate `ufl` package in the container (`import ufl` fails unless I add the alias). So I’m unsure whether this is a problem with my environment setup or whether **`ufl_legacy` 2022.x is in fact not fully compatible with `dolfin` 2019.1**.

**My questions:**

1. Can someone confirm whether `ufl_legacy==2022.3.0` is officially compatible with `FEniCS 2019.1`? I could not find an installation for ufl version 2019.
2. If yes, what are common reasons for this `check_type_traits_consistency` assertion to fail in containerized installs?
3. If sticking with `ufl_legacy`, is there a supported way to alias the entire tree safely, or should I avoid aliasing altogether and patch imports in my scripts to `ufl_legacy.*`? Please note that using Apptainer containers is a requirement of the HPC and other options like conda environments are not feasible.

Thanks in advance for any guidance on this issue.

---

<div class="post-metadata">

**Author:** ![dokken](https://yyz2.discourse-cdn.com/free1/user_avatar/fenicsproject.discourse.group/dokken/32/1560_2.png) [@dokken](https://fenicsproject.discourse.group/u/dokken)\
**Post date:** [August 29, 2025, 6:23am UTC](https://fenicsproject.discourse.group/t/installing-legacy-fenics-compatibility-of-ufl-legacy-2022-with-fenics-2019/18163/2 "2025-08-29T06:23:11Z")

</div>

> [@rojin\_anbar](#):
>
> Can someone confirm whether `ufl_legacy==2022.3.0` is officially compatible with `FEniCS 2019.1`? I could not find an installation for ufl version 2019.

If you are on 2019.1.0 and not the «master»-branch of legacy fenics, I would use [Bitbucket](https://bitbucket.org/fenics-project/ufl/) and the 2019.1 tag from there, rather than going the ufl legacy route.

If you want a recipe for running on UFL 2022.3.0 with the master branch of legacy DOLFIN, I would suggest having a look at:

> <https://github.com/scientificcomputing/packages/blob/main/fenics/Dockerfile>

for inspiration.

> [@rojin\_anbar](#):
>
> However, many of my scripts import from **`ufl.*`**. To accommodate them, I tried aliasing `ufl_legacy` to `ufl`. That succeeds for light, top-level symbols, but importing the **tensors** module fails:
> 
> ```auto
> apptainer exec --containall ~/fenics-legacy-updated.sif python3 -c "import sys; import ufl_legacy as ufl; sys.modules['ufl']=ufl; from ufl.tensors import ListTensor; print('UFL ok')"
> 
> ```
> 
> **Error:**
> 
> ```auto
> File "/usr/lib/python3/dist-packages/ufl_legacy/tensors.py", line 25, in <module>
> class ListTensor(Operator):
> File "/usr/lib/python3/dist-packages/ufl_legacy/core/ufl_type.py", line 370, in _ufl_type_decorator_
> check_type_traits_consistency(cls)
> File "/usr/lib/python3/dist-packages/ufl_legacy/core/ufl_type.py", line 132, in check_type_traits_consistency
> assert Expr._ufl_num_typecodes_ == len(Expr._ufl_all_handler_names_)
> AssertionError
> 
> ```

However, I tested your “renaming” workaround, and that does not work in that docker image, which  
to me indicates that the workaround is not quite correct.  
In general, what I would change in scripts depending on UFL is:

```python
try:
   import ufl
except ModuleNotFoundError:
   import ufl_legacy as ufl

```

> [@rojin\_anbar](#):
>
> If sticking with `ufl_legacy`, is there a supported way to alias the entire tree safely, or should I avoid aliasing altogether and patch imports in my scripts to `ufl_legacy.*`? Please note that using Apptainer containers is a requirement of the HPC and other options like conda environments are not feasible.

Maybe @minrk or @dparsons can comment on the feasibility to aliasing the whole tree safely, as I don’t know an easy way of doing it.

---

<div class="post-metadata">

**Author:** ![dparsons](https://avatars.discourse-cdn.com/v4/letter/d/5e9695/32.png) [@dparsons](https://fenicsproject.discourse.group/u/dparsons)\
**Post date:** [August 29, 2025, 2:16pm UTC](https://fenicsproject.discourse.group/t/installing-legacy-fenics-compatibility-of-ufl-legacy-2022-with-fenics-2019/18163/3 "2025-08-29T14:16:28Z")

</div>

It looks like the alias needs more hacking to rename the lower level API.  
There is a pattern for this used in the debian h5py package. Different users variously wanted h5py-serial, or h5py-mpi. So we built both and made them available as `h5py/_debian_h5py_serial` and `h5py/_debian_h5py_mpi`. An aliasing script was then constructed as `h5py/ __init__.py`, see [Files · master · Debian Science Team / h5py · GitLab](https://salsa.debian.org/science-team/h5py/-/blob/master/debian/wrapper_module/h5py/%5C__init_%5C_.py?ref_type=heads)

You can see that script scans through the lower level API, whether in serial or in mpi, and registers it under `_h5py`.

Evidentally ufl\_legacy needs the same kind of registration to access the lower level submodules.  
This seems to work, at least for your ListTensor test case:

```auto
import sys
import ufl_legacy as ufl
api = [k for k in ufl. __dict__.keys() if not k.startswith('__') and not k.endswith('__')]
for key in api:
    # "imports" symbols (makes them accessible)
    setattr(ufl,key,getattr(ufl,key))
    # rename symbols as properties of toplevel ufl module
    sys.modules['ufl.{}'.format(key)] = getattr(ufl,key)

```

then

```auto
from ufl.tensors import ListTensor
print(ListTensor)

```

shows

```auto
<class 'ufl_legacy.tensors.ListTensor'>

```

---

<div class="post-metadata">

**Author:** ![dparsons](https://avatars.discourse-cdn.com/v4/letter/d/5e9695/32.png) [@dparsons](https://fenicsproject.discourse.group/u/dparsons)\
**Post date:** [August 29, 2025, 2:41pm UTC](https://fenicsproject.discourse.group/t/installing-legacy-fenics-compatibility-of-ufl-legacy-2022-with-fenics-2019/18163/4 "2025-08-29T14:41:22Z")

</div>

> [@dparsons](#):
>
> ` setattr(ufl,key,getattr(ufl,key))`

I think this middle line was needed when distinguishing `_h5py_mpi` from `_h5py`. I think it is not needed for ufl\_legacy→ufl.

You might find it works simply with

```auto
import sys
import ufl_legacy as ufl
api = [k for k in ufl. __dict__.keys() if not k.startswith('__') and not k.endswith('__')]
for key in api:
    # rename symbols as properties of toplevel ufl module
    sys.modules['ufl.{}'.format(key)] = getattr(ufl,key)
del api

```

---

<div class="post-metadata">

**Author:** ![rojin\_anbar](https://yyz2.discourse-cdn.com/free1/user_avatar/fenicsproject.discourse.group/rojin_anbar/32/8812_2.png) [@rojin\_anbar](https://fenicsproject.discourse.group/u/rojin_anbar)\
**Post date:** [August 29, 2025, 7:32pm UTC](https://fenicsproject.discourse.group/t/installing-legacy-fenics-compatibility-of-ufl-legacy-2022-with-fenics-2019/18163/5 "2025-08-29T19:32:27Z")

</div>

Thank you very much @dokken and @dparsons  
This fix solved the issue.
