Repository: wandb/wandb

Issue:
[CLI]: Integration with OpenAI gym is broken due to missing ImageEncoder in the most recent gym version
### Describe the bug


The following snippet to initialize wandb with gym monitoring:

```
wandb.init(project="atari",  monitor_gym=True)
```

throws the following exception:

```
Traceback (most recent call last):
  File "/usr/local/lib/python3.9/site-packages/wandb/sdk/wandb_init.py", line 1073, in init
    wi.setup(kwargs)
  File "/usr/local/lib/python3.9/site-packages/wandb/sdk/wandb_init.py", line 247, in setup
    wandb.gym.monitor()
  File "/usr/local/lib/python3.9/site-packages/wandb/integration/gym/__init__.py", line 11, in monitor
    vcr.ImageEncoder.orig_close = vcr.ImageEncoder.close
AttributeError: module 'gym.wrappers.monitoring.video_recorder' has no attribute 'ImageEncoder'
```

which checks out because the `ImageEncoder` class was removed in the gym repo [here](https://github.com/openai/gym/commit/de9eed541b9a2fda2bb33e72c235e2169a2f72a7).

### Additional Files

_No response_

### Environment

WandB version:
wandb==0.13.3

OS: Ubuntu 20.04.4 LTS

Python version: 3.9.7

Versions of relevant libraries:
gym==0.26.1


### Additional Context

_No response_


Discussion:
Hi @pauldb89 , thank-you for letting us know. I put in a request for review by eng. Once I hear back with updates, I will let you know. In the meantime please continue using the last compatible gym version, 0.25.2.

Resolving patch:
diff --git a/wandb/integration/gym/__init__.py b/wandb/integration/gym/__init__.py
--- a/wandb/integration/gym/__init__.py
+++ b/wandb/integration/gym/__init__.py
@@ -1,25 +1,53 @@
 import re
+from typing import Optional
 
 import wandb
 
+_gym_version_lt_0_26: Optional[bool] = None
+
 
 def monitor():
     vcr = wandb.util.get_module(
         "gym.wrappers.monitoring.video_recorder",
-        required="Couldn't import the gym python package, install with pip install gym",
+        required="Couldn't import the gym python package, install with `pip install gym`",
     )
-    vcr.ImageEncoder.orig_close = vcr.ImageEncoder.close
+
+    global _gym_version_lt_0_26
+
+    if _gym_version_lt_0_26 is None:
+        import gym  # type: ignore
+        from pkg_resources import parse_version
+
+        if parse_version(gym.__version__) < parse_version("0.26.0"):
+            _gym_version_lt_0_26 = True
+        else:
+            _gym_version_lt_0_26 = False
+
+    # breaking change in gym 0.26.0
+    vcr_recorder_attribute = "ImageEncoder" if _gym_version_lt_0_26 else "VideoRecorder"
+    recorder = getattr(vcr, vcr_recorder_attribute)
+    path = "output_path" if _gym_version_lt_0_26 else "path"
+
+    recorder.orig_close = recorder.close
 
     def close(self):
-        vcr.ImageEncoder.orig_close(self)
-        m = re.match(r".+(video\.\d+).+", self.output_path)
+        recorder.orig_close(self)
+        m = re.match(r".+(video\.\d+).+", getattr(self, path))
         if m:
             key = m.group(1)
         else:
             key = "videos"
-        wandb.log({key: wandb.Video(self.output_path)})
+        wandb.log({key: wandb.Video(getattr(self, path))})
+
+    def del_(self):
+        self.orig_close()
 
-    vcr.ImageEncoder.close = close
+    if not _gym_version_lt_0_26:
+        recorder.__del__ = del_
+    recorder.close = close
     wandb.patched["gym"].append(
-        ["gym.wrappers.monitoring.video_recorder.ImageEncoder", "close"]
+        [
+            f"gym.wrappers.monitoring.video_recorder.{vcr_recorder_attribute}",
+            "close",
+        ]
     )


Test patch: