pymc-devs / pymc-devs/pytensor
pt.tensor("x") without shape= gives misleading error — default implies optional when it isn't
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 644
- Forks
- 208
- Avg merge
- 2d 14h
- Merged PRs (30d)
- 16
Description
The problem
A user who calls `pt.tensor("x")` without a `shape` argument gets:
TypeError: 'NoneType' object is not iterable
This is opaque. The user hasn't passed `None`, they've omitted an argument that appears optional. The function signature says `shape: ... | None = None`, which tells them "this is optional." It isn't — `shape` is effectively required, because `TensorType` has no way to infer dimensionality without it.
The same applies directly:
>>> TensorType("float64")
TypeError: 'NoneType' object is not iterable
Where
`TensorType.init` iterates over `shape` unconditionally:
if isinstance(shape, int):
shape = (shape,)
self.shape = tuple(parse_bcast_and_shape(s) for s in shape) # shape=None → crash
There's a guard for `int`, but no guard for `None`. The default flows straight into the loop.
Contrast
`pt.xtensor("x", dims=("a",))` works without `shape` because `XTensorType` knows `ndim` from `dims` and fills a default. `TensorType` has no equivalent — which is fine — but the error should reflect that.
What's confusing
- The signature is misleading: `shape: ... | None = None` declares `None` as the default and a valid type. It's neither.
- The error says nothing useful: "'NoneType' object is not iterable" tells users nothing about what they did wrong or how to fix it.
- No pointer to helpers: the error doesn't mention `shape=` or the shorthand constructors.
Proposed fix
Remove the default from `shape` in both `tensor()` and `TensorType.init`, and drop `| None` from the type hints. Python then gives its native message:
# tensor()
def tensor(name=None, *, dtype=None, shape, **kwargs):
...
# TensorType.__init__
def __init__(self, dtype, shape, name=None, broadcastable=None):
...
Result:
>>> pt.tensor("x")
TypeError: tensor() missing 1 required keyword-only argument: 'shape'
>>> TensorType("float64")
TypeError: TensorType.__init__() missing 1 required positional argument: 'shape'
Zero new code, zero breakage (every call site in the repo already passes `shape=`), and the deprecated `broadcastable` pathway still works since `broadcastable` has its own default and gets assigned to `shape` before use.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with TensorType.init at pytensor/tensor/type.py:121-123, then locate the tensor() entry point and inspect how both signatures handle shape. Verify the existing call sites described in the issue and confirm that omitted shape produces Python's missing-argument errors while the deprecated broadcastable pathway remains supported.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- machine-learning
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100