question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

functools.cached_property doesn't behave as expected in the spyder console

See original GitHub issue

Issue Report Checklist

  • Searched the issues page for similar reports
  • Read the relevant sections of the Spyder Troubleshooting Guide and followed its advice
  • Reproduced the issue after updating with conda update spyder (or pip, if not using Anaconda)
  • Could not reproduce inside jupyter qtconsole (if console-related)
  • Tried basic troubleshooting (if a bug/error)
    • Restarted Spyder
    • Reset preferences with spyder --reset
    • Reinstalled the latest version of Anaconda
    • Tried the other applicable steps from the Troubleshooting Guide
  • Completed the Problem Description, Steps to Reproduce and Version sections below

Problem Description

functools.cached_property caches properties that doesn’t change much. Useful for bypassing slow calculations that doesn’t change between each call. But in Spyder it eagerly calculates as soon a class is initialized, not nice when you want to avoid slow calculations at all cost.

Turns out when testing that in a standard iPython console that that is not the correct behaviour. It is easier to show with some examples:

What steps reproduce the problem?

In a plain iPython console I get the expected behaviour:

In [1]: from functools import cached_property
   ...: 
   ...: class DataSet:
   ...:     def __init__(self, sequence_of_numbers):
   ...:         self._data = tuple(sequence_of_numbers)
   ...:         self.set_chunks(self._data[0])
   ...: 
   ...:     @cached_property
   ...:     def shape(self):
   ...:         print("Long calculation time...")
   ...: 
   ...:         out = (len(self._data),)
   ...:         return out
   ...: 
   ...:     def set_chunks(self, chunks):
   ...:         self._chunks = chunks
   ...:         if "shape" in self.__dict__:
   ...:             del self.__dict__["shape"]
   ...:

In [2]: a = DataSet([1, 2, 3])

In [3]: a.shape
Long calculation time...
Out[3]: (3,)

# Very fast now:
In [4]: a.shape
Out[4]: (3,)

In spyder:

from functools import cached_property

class DataSet:
    def __init__(self, sequence_of_numbers):
        self._data = tuple(sequence_of_numbers)
        self.set_chunks(self._data[0])

    @cached_property
    def shape(self):
        print("Long calculation time...")

        out = (len(self._data),)
        return out

    def set_chunks(self, chunks):
        self._chunks = chunks
        if "shape" in self.__dict__:
            del self.__dict__["shape"]


a = DataSet([1, 2, 3])
Long calculation time...

# Fast
a.shape
Out[12]: (3,)

# Chunk changes triggers also shape:
a.set_chunks(5)
Long calculation time...

# When it should have been a triggered at this point:
a.shape
Out[12]: (3,)

# Same when deleting from __dict__
del a.__dict__["shape"]
Long calculation time...

Versions

  • Spyder version: Spyder 4.2.0
  • Python version: Python 3.8.5 64-bit
  • Qt version: Qt 5.9.7
  • PyQt version: PyQt5 5.9.2
  • Operating System name/version: Windows 10

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:7 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
Illviljancommented, Jan 8, 2021

Seems possible to catch prints using:

import io
from contextlib import redirect_stdout

def difficult_function():
    print("this is a debug message")
    return 5

f = io.StringIO()
with redirect_stdout(f):
    out = difficult_function()
printed_text = f.getvalue()

Inspired by https://stackoverflow.com/questions/16571150/how-to-capture-stdout-output-from-a-python-function-call

So I’m imagining making this a more generic decorator that handles functions and properties and then add that to the functions that does instant calls to the object.

I have no clue where this is in Spyder though and I don’t feel like putting a week or two into figuring it out.

0reactions
impact27commented, Jan 8, 2021

When the prompt returns, the namespace is sent to spyder. Your suggestion of adding a warning when the variable explorer triggers outputting text to the console is good, but I’m not sure how easy it would be to implement. Would you be willing to give it a go?

Read more comments on GitHub >

github_iconTop Results From Across the Web

Spyder Python 4.2.2 Download for Windows / Change Log ...
functools.cached_property doesn't behave as expected in the spyder console - Opening Dataframe in Variable Explorer not working with ...
Read more >
python logger does not log info Code Example - Code Grepper
usr/bin/env python import logging logging.basicConfig(filename='test.log', format='%(filename)s: %(message)s', level=logging.DEBUG) logging.debug('This is a ...
Read more >
Python Commands
Use conda update command to check to see if a new update is available. If conda tells you an update is available, you...
Read more >
Issue #9419: Side tag for Python 3.9 - releng - Pagure.io
I've noticed there is a side tag issue template. For which release? 33. Name of the side tag? f33-python. Number of builds that...
Read more >
Python Scientific lecture notes
Unlike Matlab, Scilab or R, Python does not come with a pre-bundled set of modules ... Given there is a sum, what other...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found