Repository: internetarchive/openlibrary

Issue:
Cannot read memcached from /admin/inspect/memcache
```
<class 'TypeError'> at /admin/inspect/memcache
a bytes-like object is required, not 'str'
```

### Relevant url?
- e.g. https://openlibrary.org/admin/inspect/memcache?keys=home.homepage.en-&action=read&debug=true

### Steps to Reproduce
1. Log in to openlibrary prod or local as admin
2. Go to the home page (so that it gets added to cache)
3. Go to /admin/inspect/memcache?keys=home.homepage.en-&action=read&debug=true

### Details

- **Logged in (Y/N)?** Y
- **Browser type/version?** FF82
- **Operating system?** Win10
- **Environment (prod/dev/local)?** prod
<!-- If not sure, put prod -->

### Proposal & Constraints
<!-- What is the proposed solution / implementation? Is there a precedent of this approach succeeding elsewhere? -->

### Related files
<!-- Files related to this issue; this is super useful for new contributors who might want to help! If you're not sure, leave this blank; a maintainer will add them. -->

### Stakeholders
@cclauss 



Discussion:
Note: Turns out this is a separate issue from: #4085
Clicking on that URL does not generate that TypeError.  How can we make this exception more discoverable?
Clicking on the URL generates a type error for me:

![image](https://user-images.githubusercontent.com/6251786/99275866-01c61c80-27fa-11eb-9919-2e915d97a981.png)

It should generate the same error on local dev environment.
Added reproduction steps
Dropping in priority since only affects admins

Resolving patch:
diff --git a/openlibrary/utils/compress.py b/openlibrary/utils/compress.py
--- a/openlibrary/utils/compress.py
+++ b/openlibrary/utils/compress.py
@@ -32,6 +32,7 @@
 some_record, and restored_record being identical to some_record.
 """
 
+
 class Compressor(object):
     def __init__(self, seed):
         c = zlib.compressobj(9)
@@ -46,26 +47,43 @@ def __init__(self, seed):
         self.d_context = d.copy()
 
     def compress(self, text):
+        if not isinstance(text, str):
+            text = text.decode()
         c = self.c_context.copy()
         t = c.compress(text.encode())
         t2 = c.flush(zlib.Z_FINISH)
         return t + t2
 
     def decompress(self, ctext):
+        if not isinstance(ctext, bytes):
+            ctext = ctext.encode()
         d = self.d_context.copy()
         t = d.decompress(ctext)
         while d.unconsumed_tail:
             t += d.decompress(d.unconsumed_tail)
         return t.decode()
 
-def test():
+
+def test_compressor():
+    """
+    >>> test_compressor()  # Self-doctest this code.
+    """
     c = Compressor(__doc__)
     test_string = "zlib is a pretty good compression algorithm"
     ct = c.compress(test_string)
-    # print 'initial length=%d, compressed=%d'% (len(test_string), len(ct))
+    # print('initial length=%d, compressed=%d' % (len(test_string), len(ct)))
     # the above string compresses from 43 bytes to 29 bytes using the
     # current doc text as compression seed, not bad for such short input.
     dt = c.decompress(ct)
     assert dt == test_string, (dt, test_string)
+    # Test that utf-8 encoded bytes return the utf-8 string
+    ct = c.compress(test_string.encode("utf-8"))
+    # print('initial length=%d, compressed=%d' % (len(test_string), len(ct)))
+    # the above string compresses from 43 bytes to 29 bytes using the
+    # current doc text as compression seed, not bad for such short input.
+    dt = c.decompress(ct)
+    assert dt == test_string, (dt, test_string)
+
 
-test()
+if __name__ == "__main__":
+    test_compressor()


Test patch: