Repository: stellargraph/stellargraph (language: python)

Issue:
CI breaks on "conda" job
### Describe the bug

CI job `conda` in GHA breaks on the current `develop` branch: step `s-weigand/setup-conda@v1` installs Python 3.9, which in step `Conda build StellarGraph` contradicts with requirements in `setup.py`: https://github.com/stellargraph/stellargraph/blob/f9cb68a9b7849cc7754deb8c3460ab10589ff376/setup.py#L91

### To Reproduce

Run with broken `conda` job: https://github.com/stellargraph/stellargraph/runs/3864294442

### Observed behavior


<details>

<summary>See error trace</summary>

```
1m 4s
Run conda build . --no-anaconda-upload
  conda build . --no-anaconda-upload
  shell: /usr/bin/bash -e {0}
No numpy version specified in conda_build_config.yaml.  Falling back to default numpy value of 1.16
WARNING:conda_build.metadata:No numpy version specified in conda_build_config.yaml.  Falling back to default numpy value of 1.16
INFO:conda_build.variants:Adding in variants from internal_defaults
Adding in variants from internal_defaults
INFO:conda_build.metadata:Attempting to finalize metadata for stellargraph
Attempting to finalize metadata for stellargraph
Collecting package metadata (repodata.json): ...working... done
Solving environment: ...working... done
Collecting package metadata (repodata.json): ...working... done
Solving environment: ...working... done
BUILD START: ['stellargraph-1.2.1-py_0.tar.bz2']
Collecting package metadata (repodata.json): ...working... done
Solving environment: ...working... done

>## Package Plan ##

  environment location: /usr/share/miniconda/conda-bld/stellargraph_1633990644068/_h_env_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_


The following NEW packages will be INSTALLED:

    _libgcc_mutex:    0.1-main                
    _openmp_mutex:    4.5-1_gnu               
    ca-certificates:  2021.9.30-h06a4308_1    
    certifi:          2021.5.30-py39h06a4308_0
    ld_impl_linux-64: 2.35.1-h7274673_9       
    libffi:           3.3-he6710b0_2          
    libgcc-ng:        9.3.0-h5101ec6_17       
    libgomp:          9.3.0-h5101ec6_17       
    libstdcxx-ng:     9.3.0-hd4cf53a_17       
    ncurses:          6.2-he6710b0_1          
    openssl:          1.1.1l-h7f8727e_0       
    pip:              21.2.4-py39h06a4308_0   
    python:           3.9.7-h12debd9_1        
    readline:         8.1-h27cfd23_0          
    setuptools:       58.0.4-py39h06a4308_0   
    sqlite:           3.36.0-hc218d9a_0       
    tk:               8.6.11-h1ccaba5_0       
    tzdata:           2021a-h5d7bf9c_0        
    wheel:            0.37.0-pyhd3eb1b0_1     
    xz:               5.2.5-h7b6447c_0        
    zlib:             1.2.11-h7b6447c_3       

Preparing transaction: ...working... done
Verifying transaction: ...working... done
Executing transaction: ...working... done
Collecting package metadata (repodata.json): ...working... done
Solving environment: ...working... done
  DEPRECATION: A future pip version will change local packages to be built in-place without first copying to a temporary directory. We recommend you use --use-feature=in-tree-build to test your packages with this new behavior before it becomes the default.
   pip 21.3 will remove support for this functionality. You can find discussion regarding this at https://github.com/pypa/pip/issues/7555.
    Running command python setup.py egg_info
    /usr/share/miniconda/conda-bld/stellargraph_1633990644068/_h_env_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_/lib/python3.9/site-packages/setuptools/dist.py:487: UserWarning: Normalizing '1.3.0b' to '1.3.0b0'
      warnings.warn(tmpl.format(**locals()))
    running egg_info
    creating /tmp/pip-pip-egg-info-bvc9t0is/stellargraph.egg-info
    writing /tmp/pip-pip-egg-info-bvc9t0is/stellargraph.egg-info/PKG-INFO
    writing dependency_links to /tmp/pip-pip-egg-info-bvc9t0is/stellargraph.egg-info/dependency_links.txt
    writing requirements to /tmp/pip-pip-egg-info-bvc9t0is/stellargraph.egg-info/requires.txt
    writing top-level names to /tmp/pip-pip-egg-info-bvc9t0is/stellargraph.egg-info/top_level.txt
    writing manifest file '/tmp/pip-pip-egg-info-bvc9t0is/stellargraph.egg-info/SOURCES.txt'
    reading manifest file '/tmp/pip-pip-egg-info-bvc9t0is/stellargraph.egg-info/SOURCES.txt'
    reading manifest template 'MANIFEST.in'
    adding license file 'LICENSE'
    adding license file 'AUTHORS'
    writing manifest file '/tmp/pip-pip-egg-info-bvc9t0is/stellargraph.egg-info/SOURCES.txt'
ERROR: Package 'stellargraph' requires a different Python: 3.9.7 not in '<3.9.0,>=3.6.0'
Traceback (most recent call last):
Copying /home/runner/work/stellargraph/stellargraph to /usr/share/miniconda/conda-bld/stellargraph_1633990644068/work/
  File "/usr/share/miniconda/bin/conda-build", line 11, in <module>
source tree in: /usr/share/miniconda/conda-bld/stellargraph_1633990644068/work
    sys.exit(main())
export PREFIX=/usr/share/miniconda/conda-bld/stellargraph_1633990644068/_h_env_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_
  File "/usr/share/miniconda/lib/python3.9/site-packages/conda_build/cli/main_build.py", line 481, in main
export BUILD_PREFIX=/usr/share/miniconda/conda-bld/stellargraph_1633990644068/_build_env
    execute(sys.argv[1:])
export SRC_DIR=/usr/share/miniconda/conda-bld/stellargraph_1633990644068/work
  File "/usr/share/miniconda/lib/python3.9/site-packages/conda_build/cli/main_build.py", line 470, in execute
Using pip 21.2.4 from $PREFIX/lib/python3.9/site-packages/pip (python 3.9)
    outputs = api.build(args.recipe, post=args.post, test_run_post=args.test_run_post,
Non-user install because user site-packages disabled
  File "/usr/share/miniconda/lib/python3.9/site-packages/conda_build/api.py", line 186, in build
Ignoring indexes: https://pypi.org/simple
    return build_tree(
Created temporary directory: /tmp/pip-ephem-wheel-cache-9yxazmt0
  File "/usr/share/miniconda/lib/python3.9/site-packages/conda_build/build.py", line 3085, in build_tree
Created temporary directory: /tmp/pip-req-tracker-v6p5w16c
    packages_from_this = build(metadata, stats,
Initialized build tracking at /tmp/pip-req-tracker-v6p5w16c
  File "/usr/share/miniconda/lib/python3.9/site-packages/conda_build/build.py", line 2208, in build
Created build tracker: /tmp/pip-req-tracker-v6p5w16c
    utils.check_call_env(cmd, env=env, rewrite_stdout_env=rewrite_env,
Entered build tracker: /tmp/pip-req-tracker-v6p5w16c
  File "/usr/share/miniconda/lib/python3.9/site-packages/conda_build/utils.py", line 412, in check_call_env
Created temporary directory: /tmp/pip-install-6voyttlx
    return _func_defaulting_env_to_os_environ('call', *popenargs, **kwargs)
Processing $SRC_DIR
  File "/usr/share/miniconda/lib/python3.9/site-packages/conda_build/utils.py", line 392, in _func_defaulting_env_to_os_environ
  Created temporary directory: /tmp/pip-req-build-r9_m20ul
    raise subprocess.CalledProcessError(proc.returncode, _args)
  Added file://$SRC_DIR to build tracker '/tmp/pip-req-tracker-v6p5w16c'
subprocess.CalledProcessError: Command '['/bin/bash', '-o', 'errexit', '/usr/share/miniconda/conda-bld/stellargraph_1633990644068/work/conda_build.sh']' returned non-zero exit status 1.
    Running setup.py (path:/tmp/pip-req-build-r9_m20ul/setup.py) egg_info for package from file://$SRC_DIR
    Created temporary directory: /tmp/pip-pip-egg-info-bvc9t0is
  Source in /tmp/pip-req-build-r9_m20ul has version 1.3.0b0, which satisfies requirement stellargraph==1.3.0b0 from file://$SRC_DIR
  Removed stellargraph==1.3.0b0 from file://$SRC_DIR from build tracker '/tmp/pip-req-tracker-v6p5w16c'
Exception information:
Traceback (most recent call last):
  File "$PREFIX/lib/python3.9/site-packages/pip/_internal/resolution/resolvelib/resolver.py", line 94, in resolve
    result = self._result = resolver.resolve(
  File "$PREFIX/lib/python3.9/site-packages/pip/_vendor/resolvelib/resolvers.py", line 472, in resolve
    state = resolution.resolve(requirements, max_rounds=max_rounds)
  File "$PREFIX/lib/python3.9/site-packages/pip/_vendor/resolvelib/resolvers.py", line 376, in resolve
    raise ResolutionImpossible(causes)
pip._vendor.resolvelib.resolvers.ResolutionImpossible: [RequirementInformation(requirement=RequiresPythonRequirement('<3.9.0,>=3.6.0'), parent=LinkCandidate('file://$SRC_DIR'))]

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "$PREFIX/lib/python3.9/site-packages/pip/_internal/cli/base_command.py", line 173, in _main
    status = self.run(options, args)
  File "$PREFIX/lib/python3.9/site-packages/pip/_internal/cli/req_command.py", line 203, in wrapper
    return func(self, options, args)
  File "$PREFIX/lib/python3.9/site-packages/pip/_internal/commands/install.py", line 315, in run
    requirement_set = resolver.resolve(
  File "$PREFIX/lib/python3.9/site-packages/pip/_internal/resolution/resolvelib/resolver.py", line 103, in resolve
    raise error from e
pip._internal.exceptions.UnsupportedPythonVersion: Package 'stellargraph' requires a different Python: 3.9.7 not in '<3.9.0,>=3.6.0'
Removed build tracker: '/tmp/pip-req-tracker-v6p5w16c'
Error: Process completed with exit code 1.
0s
0s
0s

```

</details>

### Expected behavior

The job finishes successfully

### Environment

Operating system: Ubuntu 20.04.3

Python version: 3.9.7

### Proposed solution

One could pin Python version in the [`s-weigand/setup-conda@v1`  step](https://github.com/stellargraph/stellargraph/blob/f9cb68a9b7849cc7754deb8c3460ab10589ff376/.github/workflows/ci.yml#L337):

```
conda:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: s-weigand/setup-conda@v1
         with:
           python-version: 3.8
      ...
```


Discussion / hints:

Fix patch:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 8c606b1b0..46ef8af71 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -339,6 +339,8 @@ jobs:
     steps:
       - uses: actions/checkout@v2
       - uses: s-weigand/setup-conda@v1
+        with:
+          python-version: 3.8
 
       - name: Install conda build tools
         run: |
diff --git a/demos/embeddings/metapath2vec-embeddings.ipynb b/demos/embeddings/metapath2vec-embeddings.ipynb
index 2fd5b2d18..9f40b771e 100644
--- a/demos/embeddings/metapath2vec-embeddings.ipynb
+++ b/demos/embeddings/metapath2vec-embeddings.ipynb
@@ -268,7 +268,7 @@
    "source": [
     "from gensim.models import Word2Vec\n",
     "\n",
-    "model = Word2Vec(walks, size=128, window=5, min_count=0, sg=1, workers=2, iter=1)"
+    "model = Word2Vec(walks, vector_size=128, window=5, min_count=0, sg=1, workers=2, epochs=1)"
    ]
   },
   {
@@ -310,7 +310,7 @@
    "outputs": [],
    "source": [
     "# Retrieve node embeddings and corresponding subjects\n",
-    "node_ids = model.wv.index2word  # list of node IDs\n",
+    "node_ids = model.wv.index_to_key  # list of node IDs\n",
     "node_embeddings = (\n",
     "    model.wv.vectors\n",
     ")  # numpy.ndarray of size number of nodes times embeddings dimensionality\n",
diff --git a/demos/embeddings/node2vec-embeddings.ipynb b/demos/embeddings/node2vec-embeddings.ipynb
index 86a54aec1..efdca4943 100644
--- a/demos/embeddings/node2vec-embeddings.ipynb
+++ b/demos/embeddings/node2vec-embeddings.ipynb
@@ -253,7 +253,9 @@
     "from gensim.models import Word2Vec\n",
     "\n",
     "str_walks = [[str(n) for n in walk] for walk in walks]\n",
-    "model = Word2Vec(str_walks, size=128, window=5, min_count=0, sg=1, workers=2, iter=1)"
+    "model = Word2Vec(\n",
+    "    str_walks, vector_size=128, window=5, min_count=0, sg=1, workers=2, epochs=1\n",
+    ")"
    ]
   },
   {
@@ -296,7 +298,7 @@
    "outputs": [],
    "source": [
     "# Retrieve node embeddings and corresponding subjects\n",
-    "node_ids = model.wv.index2word  # list of node IDs\n",
+    "node_ids = model.wv.index_to_key  # list of node IDs\n",
     "node_embeddings = (\n",
     "    model.wv.vectors\n",
     ")  # numpy.ndarray of size number of nodes times embeddings dimensionality\n",
diff --git a/demos/link-prediction/ctdne-link-prediction.ipynb b/demos/link-prediction/ctdne-link-prediction.ipynb
index 015bc6993..d969216f5 100644
--- a/demos/link-prediction/ctdne-link-prediction.ipynb
+++ b/demos/link-prediction/ctdne-link-prediction.ipynb
@@ -441,21 +441,21 @@
     "embedding_size = 128\n",
     "temporal_model = Word2Vec(\n",
     "    temporal_walks,\n",
-    "    size=embedding_size,\n",
+    "    vector_size=embedding_size,\n",
     "    window=context_window_size,\n",
     "    min_count=0,\n",
     "    sg=1,\n",
     "    workers=2,\n",
-    "    iter=1,\n",
+    "    epochs=1,\n",
     ")\n",
     "static_model = Word2Vec(\n",
     "    static_walks,\n",
-    "    size=embedding_size,\n",
+    "    vector_size=embedding_size,\n",
     "    window=context_window_size,\n",
     "    min_count=0,\n",
     "    sg=1,\n",
     "    workers=2,\n",
-    "    iter=1,\n",
+    "    epochs=1,\n",
     ")"
    ]
   },
diff --git a/demos/link-prediction/metapath2vec-link-prediction.ipynb b/demos/link-prediction/metapath2vec-link-prediction.ipynb
index f3023bcb9..25bdc73aa 100644
--- a/demos/link-prediction/metapath2vec-link-prediction.ipynb
+++ b/demos/link-prediction/metapath2vec-link-prediction.ipynb
@@ -516,12 +516,12 @@
     "\n",
     "    model = Word2Vec(\n",
     "        walks,\n",
-    "        size=dimensions,\n",
+    "        vector_size=dimensions,\n",
     "        window=context_window_size,\n",
     "        min_count=0,\n",
     "        sg=1,\n",
     "        workers=workers,\n",
-    "        iter=num_iter,\n",
+    "        epochs=num_iter,\n",
     "    )\n",
     "\n",
     "    def get_embedding(u):\n",
diff --git a/demos/link-prediction/node2vec-link-prediction.ipynb b/demos/link-prediction/node2vec-link-prediction.ipynb
index 32162e381..68abfd0ef 100644
--- a/demos/link-prediction/node2vec-link-prediction.ipynb
+++ b/demos/link-prediction/node2vec-link-prediction.ipynb
@@ -485,12 +485,12 @@
     "\n",
     "    model = Word2Vec(\n",
     "        walks,\n",
-    "        size=dimensions,\n",
+    "        vector_size=dimensions,\n",
     "        window=window_size,\n",
     "        min_count=0,\n",
     "        sg=1,\n",
     "        workers=workers,\n",
-    "        iter=num_iter,\n",
+    "        epochs=num_iter,\n",
     "    )\n",
     "\n",
     "    def get_embedding(u):\n",
diff --git a/demos/node-classification/node2vec-node-classification.ipynb b/demos/node-classification/node2vec-node-classification.ipynb
index 24cd1f94b..7d423f307 100644
--- a/demos/node-classification/node2vec-node-classification.ipynb
+++ b/demos/node-classification/node2vec-node-classification.ipynb
@@ -263,7 +263,9 @@
     "from gensim.models import Word2Vec\n",
     "\n",
     "str_walks = [[str(n) for n in walk] for walk in walks]\n",
-    "model = Word2Vec(str_walks, size=128, window=5, min_count=0, sg=1, workers=2, iter=1)"
+    "model = Word2Vec(\n",
+    "    str_walks, vector_size=128, window=5, min_count=0, sg=1, workers=2, epochs=1\n",
+    ")"
    ]
   },
   {
@@ -306,7 +308,7 @@
    "outputs": [],
    "source": [
     "# Retrieve node embeddings and corresponding subjects\n",
-    "node_ids = model.wv.index2word  # list of node IDs\n",
+    "node_ids = model.wv.index_to_key  # list of node IDs\n",
     "node_embeddings = (\n",
     "    model.wv.vectors\n",
     ")  # numpy.ndarray of size number of nodes times embeddings dimensionality\n",
diff --git a/demos/node-classification/node2vec-weighted-node-classification.ipynb b/demos/node-classification/node2vec-weighted-node-classification.ipynb
index 26f11834f..ed5d41f37 100644
--- a/demos/node-classification/node2vec-weighted-node-classification.ipynb
+++ b/demos/node-classification/node2vec-weighted-node-classification.ipynb
@@ -389,7 +389,7 @@
    "outputs": [],
    "source": [
     "weighted_model = Word2Vec(\n",
-    "    weighted_walks, size=128, window=5, min_count=0, sg=1, workers=1, iter=1\n",
+    "    weighted_walks, vector_size=128, window=5, min_count=0, sg=1, workers=1, epochs=1\n",
     ")"
    ]
   },
@@ -435,7 +435,7 @@
    "outputs": [],
    "source": [
     "# Retrieve node embeddings and corresponding subjects\n",
-    "node_ids = weighted_model.wv.index2word  # list of node IDs\n",
+    "node_ids = weighted_model.wv.index_to_key  # list of node IDs\n",
     "weighted_node_embeddings = (\n",
     "    weighted_model.wv.vectors\n",
     ")  # numpy.ndarray of size number of nodes times embeddings dimensionality\n",
@@ -711,7 +711,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "model = Word2Vec(walks, size=128, window=5, min_count=0, sg=1, workers=1, iter=1)"
+    "model = Word2Vec(walks, vector_size=128, window=5, min_count=0, sg=1, workers=1, epochs=1)"
    ]
   },
   {
@@ -743,7 +743,7 @@
    ],
    "source": [
     "# Retrieve node embeddings and corresponding subjects\n",
-    "node_ids = model.wv.index2word  # list of node IDs\n",
+    "node_ids = model.wv.index_to_key  # list of node IDs\n",
     "node_embeddings = (\n",
     "    model.wv.vectors\n",
     ")  # numpy.ndarray of size number of nodes times embeddings dimensionality\n",
@@ -1053,7 +1053,7 @@
    "outputs": [],
    "source": [
     "weighted_model = Word2Vec(\n",
-    "    weighted_walks, size=128, window=5, min_count=0, sg=1, workers=1, iter=1\n",
+    "    weighted_walks, vector_size=128, window=5, min_count=0, sg=1, workers=1, epochs=1\n",
     ")"
    ]
   },
@@ -1086,7 +1086,7 @@
    ],
    "source": [
     "# Retrieve node embeddings and corresponding subjects\n",
-    "node_ids = weighted_model.wv.index2word  # list of node IDs\n",
+    "node_ids = weighted_model.wv.index_to_key  # list of node IDs\n",
     "weighted_node_embeddings = (\n",
     "    weighted_model.wv.vectors\n",
     ")  # numpy.ndarray of size number of nodes times embeddings dimensionality\n",
diff --git a/docs/spelling_wordlist.txt b/docs/spelling_wordlist.txt
index 1e23ec92e..cc542e525 100644
--- a/docs/spelling_wordlist.txt
+++ b/docs/spelling_wordlist.txt
@@ -187,6 +187,7 @@ et
 exponentiates
 expressivity
 generalization
+gensim
 hasn
 homophily
 hyperparameter
diff --git a/setup.py b/setup.py
index a4bc497a5..a75031c99 100644
--- a/setup.py
+++ b/setup.py
@@ -30,7 +30,6 @@
     "networkx>=2.2",
     "scikit_learn>=0.20",
     "matplotlib>=2.2",
-    "gensim>=3.4.0",
     "pandas>=0.24",
 ]
 
@@ -45,7 +44,14 @@
 #
 # Other demos do not have specific requirements
 EXTRAS_REQUIRES = {
-    "demos": ["numba", "jupyter", "seaborn", "rdflib", "mplleaflet==0.0.5"],
+    "demos": [
+        "numba",
+        "jupyter",
+        "seaborn",
+        "rdflib",
+        "mplleaflet==0.0.5",
+        "gensim>=4.0.0",
+    ],
     "igraph": ["python-igraph"],
     "neo4j": ["py2neo"],
     "test": [
diff --git a/stellargraph/data/epgm.py b/stellargraph/data/epgm.py
index cbad3a617..ec37391c8 100644
--- a/stellargraph/data/epgm.py
+++ b/stellargraph/data/epgm.py
@@ -21,7 +21,6 @@
 import json
 import uuid
 import numpy as np
-import chardet
 import scipy.sparse as sp
 
 import multiprocessing


Test patch:
diff --git a/tests/core/test_utils.py b/tests/core/test_utils.py
index 49fa2edd6..697900c1b 100644
--- a/tests/core/test_utils.py
+++ b/tests/core/test_utils.py
@@ -212,7 +212,7 @@ def test_normalized_laplacian(example_graph):
     assert laplacian.shape == Aadj.get_shape()
 
     # Sum of laplacian is equal to the number of degree 0 nodes
-    laplacian = normalized_laplacian(Aadj, symmetric=False) 
+    laplacian = normalized_laplacian(Aadj, symmetric=False)
     num_degree_zero_nodes = (Aadj.sum(axis=1) == 0).sum()
     assert num_degree_zero_nodes == pytest.approx(laplacian.sum(), abs=1e-7)
     assert laplacian.get_shape() == Aadj.get_shape()