codecov[bot]: # [Codecov](https://codecov.io/gh/joblib/joblib/pull/752?src=pr&el=h1) Report
> Merging [#752](https://codecov.io/gh/joblib/joblib/pull/752?src=pr&el=desc) into [master](https://codecov.io/gh/joblib/joblib/commit/b0bc5dd24b123b445965a5f4d487beaf6fadd083?src=pr&el=desc) will **increase** coverage by `0.04%`.
> The diff coverage is `100%`.

[![Impacted file tree graph](https://codecov.io/gh/joblib/joblib/pull/752/graphs/tree.svg?src=pr&token=gA6LF5DGTW&height=150&width=650)](https://codecov.io/gh/joblib/joblib/pull/752?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #752      +/-   ##
==========================================
+ Coverage   95.24%   95.28%   +0.04%     
==========================================
  Files          43       43              
  Lines        6137     6150      +13     
==========================================
+ Hits         5845     5860      +15     
+ Misses        292      290       -2
```


| [Impacted Files](https://codecov.io/gh/joblib/joblib/pull/752?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [joblib/test/test\_memory.py](https://codecov.io/gh/joblib/joblib/pull/752/diff?src=pr&el=tree#diff-am9ibGliL3Rlc3QvdGVzdF9tZW1vcnkucHk=) | `97.95% <100%> (+0.04%)` | :arrow_up: |
| [joblib/memory.py](https://codecov.io/gh/joblib/joblib/pull/752/diff?src=pr&el=tree#diff-am9ibGliL21lbW9yeS5weQ==) | `95.75% <100%> (+0.3%)` | :arrow_up: |
| [joblib/\_parallel\_backends.py](https://codecov.io/gh/joblib/joblib/pull/752/diff?src=pr&el=tree#diff-am9ibGliL19wYXJhbGxlbF9iYWNrZW5kcy5weQ==) | `96.8% <0%> (-1.61%)` | :arrow_down: |
| [joblib/test/test\_parallel.py](https://codecov.io/gh/joblib/joblib/pull/752/diff?src=pr&el=tree#diff-am9ibGliL3Rlc3QvdGVzdF9wYXJhbGxlbC5weQ==) | `96.73% <0%> (+0.14%)` | :arrow_up: |
| [joblib/\_store\_backends.py](https://codecov.io/gh/joblib/joblib/pull/752/diff?src=pr&el=tree#diff-am9ibGliL19zdG9yZV9iYWNrZW5kcy5weQ==) | `90.47% <0%> (+0.52%)` | :arrow_up: |
| [joblib/pool.py](https://codecov.io/gh/joblib/joblib/pull/752/diff?src=pr&el=tree#diff-am9ibGliL3Bvb2wucHk=) | `91.37% <0%> (+1.72%)` | :arrow_up: |
| [joblib/backports.py](https://codecov.io/gh/joblib/joblib/pull/752/diff?src=pr&el=tree#diff-am9ibGliL2JhY2twb3J0cy5weQ==) | `95.83% <0%> (+2.08%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/joblib/joblib/pull/752?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/joblib/joblib/pull/752?src=pr&el=footer). Last update [b0bc5dd...188d155](https://codecov.io/gh/joblib/joblib/pull/752?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

aabadie: > can you please add an entry to the changelog?

Done
diff --git a/CHANGES.rst b/CHANGES.rst
index 6d01fa4..35f50e2 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -1,6 +1,14 @@
 Latest changes
 ===============
 
+Release 0.12.3
+--------------
+
+Alexandre Abadie
+
+    Fix MemorizedResult not picklable (#747).
+
+
 Release 0.12.2
 --------------
 
diff --git a/joblib/memory.py b/joblib/memory.py
index bbb52aa..1cebe63 100644
--- a/joblib/memory.py
+++ b/joblib/memory.py
@@ -210,8 +210,11 @@ class MemorizedResult(Logger):
     def __init__(self, location, func, args_id, backend='local',
                  mmap_mode=None, verbose=0, timestamp=None, metadata=None):
         Logger.__init__(self)
-        self.func = func
         self.func_id = _build_func_identifier(func)
+        if isinstance(func, _basestring):
+            self.func = func
+        else:
+            self.func = self.func_id
         self.args_id = args_id
         self.store_backend = _store_backend_factory(backend, location,
                                                     verbose=verbose)

pickling breaks between joblib version 0.11 and 0.12.2
For my script below, will someone please tell me why the result of call_and_shelve() can be pickled in version 0.11,  but not in version 0.12.2? Or tell me what I am doing wrong, or if this is a bug...

Thanks.

## I have this little script
```python
from joblib import Memory
import numpy as np
import pickle
cachedir = 'PATH_TO_CACHE'
memory = Memory(cachedir, verbose=0)

@memory.cache
def g(x):
	print('A long-running calculation, with parameter %s' % x)
	return np.hamming(x)

result = g.call_and_shelve(4)
print('\nMemorized result: {}'.format(result))

canned_pickle = pickle.dumps(result)
open_can = pickle.loads(canned_pickle)

print('Depickled: {}\n'.format(open_can))
```
### With joblib:0.11 everything works and I get this output:
```python
Memorized result: MemorizedResult(cachedir="/Users/mpsommer/Documents/python/job_lib_cache/joblib", func="__main__--Users-mpsommer-Documents-python-job_lib/g-alias", argument_hash="f7c5defad10d1a7505df243840ad5209")
Depickled: MemorizedResult(cachedir="/Users/mpsommer/Documents/python/job_lib_cache/joblib", func="__main__--Users-mpsommer-Documents-python-job_lib/g-alias", argument_hash="f7c5defad10d1a7505df243840ad5209")
```

### With joblib:0.12.2 the pickling breaks and I get this output:
```python
Memorized result: MemorizedResult(location="/Users/mpsommer/Documents/python/job_lib_cache/joblib", func="<function g at 0x104448aa0>", args_id="f7c5defad10d1a7505df243840ad5209")
Traceback (most recent call last):
  File "job_lib.py", line 15, in <module>
    canned_pickle = pickle.dumps(result)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 1374, in dumps
    Pickler(file, protocol).dump(obj)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 224, in dump
    self.save(obj)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 331, in save
    self.save_reduce(obj=obj, *rv)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 401, in save_reduce
    save(args)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 286, in save
    f(self, obj) # Call unbound method with explicit self
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 562, in save_tuple
    save(element)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 286, in save
    f(self, obj) # Call unbound method with explicit self
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 753, in save_global
    (obj, module, name))
pickle.PicklingError: Can't pickle <function g at 0x104448aa0>: it's not the same object as __main__.g
```

diff --git a/joblib/test/test_memory.py b/joblib/test/test_memory.py
index 59cbec3..4690b5b 100644
--- a/joblib/test/test_memory.py
+++ b/joblib/test/test_memory.py
@@ -964,3 +964,25 @@ def test_dummy_store_backend():
 
     backend_obj = _store_backend_factory(backend_name, "dummy_location")
     assert isinstance(backend_obj, DummyStoreBackend)
+
+
+def test_memorized_result_pickle(tmpdir):
+    # Verify a MemoryResult object can be pickled/depickled. Non regression
+    # test introduced following issue
+    # https://github.com/joblib/joblib/issues/747
+
+    memory = Memory(location=tmpdir.strpath)
+
+    @memory.cache
+    def g(x):
+        return x**2
+
+    memorized_result = g.call_and_shelve(4)
+    memorized_result_pickle = pickle.dumps(memorized_result)
+    memorized_result_loads = pickle.loads(memorized_result_pickle)
+
+    assert memorized_result.store_backend.location == \
+        memorized_result_loads.store_backend.location
+    assert memorized_result.func == memorized_result_loads.func
+    assert memorized_result.args_id == memorized_result_loads.args_id
+    assert str(memorized_result) == str(memorized_result_loads)

pip install -e .
parse_log_pytest
pytest
pytest
3.6
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
attrs @ file:///opt/conda/conda-bld/attrs_1642510447205/work
certifi==2021.5.30
importlib-metadata @ file:///tmp/build/80754af9/importlib-metadata_1631916693255/work
iniconfig @ file:///home/linux1/recipes/ci/iniconfig_1610983019677/work
-e git+https://github.com/joblib/joblib.git@74c357ade50588037cecb6bdceb33fa3f48a3caf#egg=joblib
more-itertools @ file:///tmp/build/80754af9/more-itertools_1637733554872/work
packaging @ file:///tmp/build/80754af9/packaging_1637314298585/work
pluggy @ file:///tmp/build/80754af9/pluggy_1615976315926/work
py @ file:///opt/conda/conda-bld/py_1644396412707/work
pyparsing @ file:///tmp/build/80754af9/pyparsing_1635766073266/work
pytest==6.2.4
toml @ file:///tmp/build/80754af9/toml_1616166611790/work
typing_extensions @ file:///opt/conda/conda-bld/typing_extensions_1647553014482/work
zipp @ file:///tmp/build/80754af9/zipp_1633618647012/work

name: joblib
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - attrs=21.4.0=pyhd3eb1b0_0
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2021.5.30=py36h06a4308_0
  - importlib-metadata=4.8.1=py36h06a4308_0
  - importlib_metadata=4.8.1=hd3eb1b0_0
  - iniconfig=1.1.1=pyhd3eb1b0_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.3=he6710b0_2
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - more-itertools=8.12.0=pyhd3eb1b0_0
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - packaging=21.3=pyhd3eb1b0_0
  - pip=21.2.2=py36h06a4308_0
  - pluggy=0.13.1=py36h06a4308_0
  - py=1.11.0=pyhd3eb1b0_0
  - pyparsing=3.0.4=pyhd3eb1b0_0
  - pytest=6.2.4=py36h06a4308_2
  - python=3.6.13=h12debd9_1
  - readline=8.2=h5eee18b_0
  - setuptools=58.0.4=py36h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - toml=0.10.2=pyhd3eb1b0_0
  - typing_extensions=4.1.1=pyh06a4308_0
  - wheel=0.37.1=pyhd3eb1b0_0
  - xz=5.6.4=h5eee18b_1
  - zipp=3.6.0=pyhd3eb1b0_0
  - zlib=1.2.13=h5eee18b_1
prefix: /opt/conda/envs/joblib

joblib/test/test_memory.py::test_memorized_result_pickle
joblib/test/test_memory.py::test_memory_integration joblib/test/test_memory.py::test_no_memory joblib/test/test_memory.py::test_memory_kwarg joblib/test/test_memory.py::test_memory_lambda joblib/test/test_memory.py::test_memory_name_collision joblib/test/test_memory.py::test_memory_warning_lambda_collisions joblib/test/test_memory.py::test_memory_warning_collision_detection joblib/test/test_memory.py::test_memory_partial joblib/test/test_memory.py::test_memory_eval joblib/test/test_memory.py::test_argument_change joblib/test/test_memory.py::test_memory_exception joblib/test/test_memory.py::test_memory_ignore joblib/test/test_memory.py::test_partial_decoration[ignore0-100-r] joblib/test/test_memory.py::test_partial_decoration[ignore1-10-None] joblib/test/test_memory.py::test_func_dir joblib/test/test_memory.py::test_persistence joblib/test/test_memory.py::test_call_and_shelve joblib/test/test_memory.py::test_call_and_shelve_argument_hash joblib/test/test_memory.py::test_memorized_pickling joblib/test/test_memory.py::test_memorized_repr joblib/test/test_memory.py::test_memory_file_modification joblib/test/test_memory.py::test_memory_in_memory_function_code_change joblib/test/test_memory.py::test_clear_memory_with_none_location joblib/test/test_memory.py::test_memory_func_with_kwonly_args joblib/test/test_memory.py::test_memory_func_with_signature joblib/test/test_memory.py::test__get_items joblib/test/test_memory.py::test__get_items_to_delete joblib/test/test_memory.py::test_memory_reduce_size joblib/test/test_memory.py::test_memory_clear joblib/test/test_memory.py::test_cached_function_race_condition_when_persisting_output joblib/test/test_memory.py::test_cached_function_race_condition_when_persisting_output_2 joblib/test/test_memory.py::test_memory_recomputes_after_an_error_why_loading_results joblib/test/test_memory.py::test_deprecated_cachedir_behaviour joblib/test/test_memory.py::test_register_invalid_store_backends_key[None] joblib/test/test_memory.py::test_register_invalid_store_backends_key[invalid_prefix1] joblib/test/test_memory.py::test_register_invalid_store_backends_key[invalid_prefix2] joblib/test/test_memory.py::test_register_invalid_store_backends_object joblib/test/test_memory.py::test_memory_default_store_backend joblib/test/test_memory.py::test_instanciate_incomplete_store_backend joblib/test/test_memory.py::test_dummy_store_backend
joblib/memory.py CHANGES.rst
joblib/memory.py CHANGES.rst