Repository: biopython/biopython (language: python)

Issue:
Standardize on import numpy as np
I think we should follow the numpy documentation and avoid the plain ``import numpy`` form in favour of ``import numpy as np``.

With the current code base:

```
$ cat *.py */*.py */*/*.py | grep "import numpy" | sort | uniq -c
   1         >>> import numpy
   9     import numpy
   3     import numpy as np
   1     import numpy as np  # type: ignore
  17 import numpy
   1 import numpy  # type: ignore
   8 import numpy as np
   1 import numpy as np  # type: ignore
   1 import numpy.linalg
```

This is a fairly simple change with search-and-replace (e.g. using ``sed`` at the command line), suitable for a first-time contributor so marking as such.


Discussion / hints:
Does the numpy documentation recommend using `np` instead of `numpy`? The latter is more explicit.
Yes, e.g. https://numpy.org/doc/stable/user/absolute_beginners.html#how-to-import-numpy
I'd like to work on this issue
About to make a pull request with this. 
Two volunteers at once? Oh well. There is plenty here, aside the main code base (tests, tutorial, website documentation, etc).
Ah, looks like I was beat by a couple minutes on these commits. If y'all have anymore good first issues, I'd love to help.
> Ah, looks like I was beat by a couple minutes on these commits. If y'all have anymore good first issues, I'd love to help.

Shouldn't have picked when someone is already working on it 🤷
Unlucky timing @pvalle6, how about checking the website examples on https://github.com/biopython/biopython.github.io then?
For sure. Thanks for recommendation @peterjc 
> Yes, e.g. https://numpy.org/doc/stable/user/absolute_beginners.html#how-to-import-numpy

Before spending more time on this, you may want to reconsider if this is really a good idea. Yes, the numpy documentation says

"This is a widely adopted convention that you should follow"

but the rationale

"for better readability of code using NumPy"

does not really apply to Biopython.

Here, readability can mean using `np` as an abbreviation for `numpy` to make lines shorter and therefore more readable. But that is relevant only for code that does complex things with numpy. In Biopython, our use of numpy is simple, and any gain in code length by making this substitution is negligible.

Alternatively, readability can mean using `np` consistently for recognizability. But anyone who recognizes `np` as numpy will surely recognize `numpy` as numpy. And for people new to Python, using `np` instead of `numpy` will be one more potential source of confusion. It is also inconsistent with Python's rule that explicit is better than implicit.

Note also that "This is a widely adopted convention that you should follow" may just mean "if you use an alias, use `np`" rather than "you must always use an alias".

Practically speaking, replacing `numpy` by `np` will be more complicated than it may appear at first. For example, in the `test_Align*` scripts there are lots (hundreds?) of lines where `numpy` is used in lines where flake8/black code checking was turned off (because they insisted on unreadable code). Someone (i.e., not me) would have to go in and fix those by hand.
That's a valid point @mdehoon 
On that specific concern, we could leave the tests alone.

I do think user facing code should be updated (specifically documentation including the tutorial and the doctests). The easiest way to do that would be apply it to the ``Doc`` and source code under ``Bio``, ``Scripts`` (and if relevant ``BioSQL/``).
> I do think user facing code should be updated (specifically documentation including the tutorial and the doctests).

Why do you think so?
Just chiming in to say that while `import numpy as np` might not be a _de jure_ standard, it is the _de facto_ standard and as such, should not be confusing at all.
Why? Because anywhere our documentation (including examples) imports numpy, it should use the ``import numpy as np`` style to match the convention set out by the numpy team. This will be easiest for our users, especially Python novices.
@peterjc Is this issue still open? How can I contribute to it?
It looks like https://github.com/biopython/biopython/pull/4242 is stalled, although @pvalle6 also offered to help on it. I'd say if @PaarthAgarwal doesn't reply this week, that @pvalle6 might as well take over that effort and/or start again if easier. If there is an obvious part of the work @Aum8 could handle, that would be nice.

Noting the discussion above, I would leave the ``Tests/`` alone for now.

In fact, it might be best to start small, for example only the tutorial under ``Doc/``?
> It looks like https://github.com/biopython/biopython/pull/4242 is stalled, although @pvalle6 also offered to help on it. I'd say if @PaarthAgarwal doesn't reply this week, that @pvalle6 might as well take over that effort and/or start again if easier. If there is an obvious part of the work @Aum8 could handle, that would be nice.
> 
> Noting the discussion above, I would leave the ``Tests/`` alone for now.
> 
> In fact, it might be best to start small, for example only the tutorial under ``Doc/``?

I asked if he would accept a commit to his forked repo and never got a reply. I'd be happy to restart this. Although, I would rather start smaller.
> It looks like #4242 is stalled, although @pvalle6 also offered to help on it. I'd say if @PaarthAgarwal doesn't reply this week, that @pvalle6 might as well take over that effort and/or start again if easier. If there is an obvious part of the work @Aum8 could handle, that would be nice.
> 
> Noting the discussion above, I would leave the `Tests/` alone for now.
> 
> In fact, it might be best to start small, for example only the tutorial under `Doc/`?

Thank you for guiding me on that! I would like to help with @pvalle6 on the tutorial under `Doc/` , if he is ok with that.




> > It looks like #4242 is stalled, although @pvalle6 also offered to help on it. I'd say if @PaarthAgarwal doesn't reply this week, that @pvalle6 might as well take over that effort and/or start again if easier. If there is an obvious part of the work @Aum8 could handle, that would be nice.
> > Noting the discussion above, I would leave the `Tests/` alone for now.
> > In fact, it might be best to start small, for example only the tutorial under `Doc/`?
> 
> Thank you for guiding me on that! I would like to help with @pvalle6 on the tutorial under `Doc/` , if he is ok with that.

I'm about to add some commits to my numpy-standardization branch, feel free to add anything you want to it. We can create a pull request whenever. I'm unsure if we can just keep an unmerged pull request and continually add to it.
After the tutorial changes, my grep results above suggest just a single doctest needs updating (search for ``>>> import numpy``), perhaps there are more though?
Recently, I create a PR on this issue. would you merge it?
@BabaYaga1221 you mean your pull request #4259?

I have removed the "help wanted" label to stop any more volunteers for something already being worked on.
OK. Got it. Can you assign me some other issue? @peterjc 

Looking much better,

```
$ cat *.py */*.py */*/*.py | grep "import numpy" | sort | uniq -c
   1             import numpy
   1         >>> import numpy
  40     import numpy
   1     import numpy  # noqa F401
   1     import numpy  # noqa: F401
  13     import numpy as np
   1     import numpy as np  # noqa F401
   1     import numpy as np  # type: ignore
   1     import numpy.testing
   7 import numpy
  24 import numpy as np
   2 import numpy as np  # type: ignore
   1 import numpy.linalg
```

Adjusting the regex:

```
$ cat *.py */*.py */*/*.py | grep -E "import numpy($|  #)" | sort | uniq -c
   1             import numpy
   1         >>> import numpy
  40     import numpy
   1     import numpy  # noqa F401
   1     import numpy  # noqa: F401
   7 import numpy
```

Now with filenames:

```
Tests/run_tests.py:    import numpy
Tests/test_Align_Alignment.py:    import numpy
Tests/test_Align_a2m.py:import numpy
Tests/test_Align_bed.py:import numpy
Tests/test_Align_bigbed.py:    import numpy
Tests/test_Align_bigmaf.py:import numpy
Tests/test_Align_bigpsl.py:    import numpy
Tests/test_Align_clustal.py:import numpy
Tests/test_Align_emboss.py:    import numpy
Tests/test_Align_exonerate.py:    import numpy
Tests/test_Align_fasta.py:import numpy
Tests/test_Align_hhr.py:import numpy
Tests/test_Align_maf.py:    import numpy
Tests/test_Align_mauve.py:    import numpy
Tests/test_Align_msf.py:    import numpy
Tests/test_Align_nexus.py:    import numpy
Tests/test_Align_phylip.py:    import numpy
Tests/test_Align_psl.py:    import numpy
Tests/test_Align_sam.py:    import numpy
Tests/test_Align_stockholm.py:    import numpy
Tests/test_Align_tabular.py:    import numpy
Tests/test_Cluster.py:    import numpy
Tests/test_LogisticRegression.py:    import numpy
Tests/test_PDB_DSSP.py:    import numpy  # noqa: F401
Tests/test_PDB_Exposure.py:    import numpy
Tests/test_PDB_FragmentMapper.py:    import numpy
Tests/test_PDB_MMCIF2Dict.py:    import numpy
Tests/test_PDB_MMCIFParser.py:    import numpy
Tests/test_PDB_NACCESS.py:    import numpy
Tests/test_PDB_PDBParser.py:    import numpy
Tests/test_PDB_SMCRA.py:    import numpy
Tests/test_PDB_Superimposer.py:    import numpy
Tests/test_PDB_parse_pdb_header.py:    import numpy  # noqa F401
Tests/test_PDB_vectors.py:    import numpy
Tests/test_RCSBFormats.py:    import numpy
Tests/test_SeqIO_PdbIO.py:    import numpy
Tests/test_SeqRecord.py:    import numpy
Tests/test_Seq_objs.py:    import numpy
Tests/test_align_substitution_matrices.py:    import numpy
Tests/test_align_substitution_matrices.py:import numpy
Tests/test_codonalign.py:    import numpy
Tests/test_kNN.py:    import numpy
Tests/test_motifs.py:    import numpy
Tests/test_pairwise_aligner.py:    import numpy
Tests/test_pairwise_aligner.py:            import numpy
Tests/test_pairwise_alignment_map.py:    import numpy
Tests/test_phenotype.py:    import numpy
Tests/test_phenotype_fit.py:    import numpy
Tests/test_seq.py:    import numpy
Bio/Align/__init__.py:    import numpy
Bio/Align/__init__.py:        >>> import numpy
```

Leaving aside the ``Tests/test_Align*.py`` files discussed above (would need manual reformatting and/or adjusting the black excemptions), the main code-base is almost done.
Just test files now, the biggest group being ``Tests/test_PDB_*.py`` which should be a nice batch to do as a single pull request.
Current cases to fix:

```
$ grep -E "import numpy($|  #)" *.py */*.py */*/*.py
Tests/test_Align_codonalign.py:    import numpy
Tests/test_LogisticRegression.py:    import numpy
Tests/test_PDB_DSSP.py:    import numpy  # noqa: F401
Tests/test_PDB_Exposure.py:    import numpy
Tests/test_PDB_FragmentMapper.py:    import numpy
Tests/test_PDB_MMCIF2Dict.py:    import numpy
Tests/test_PDB_MMCIFParser.py:    import numpy
Tests/test_PDB_NACCESS.py:    import numpy
Tests/test_PDB_PDBParser.py:    import numpy
Tests/test_PDB_SMCRA.py:    import numpy
Tests/test_PDB_Superimposer.py:    import numpy
Tests/test_PDB_parse_pdb_header.py:    import numpy  # noqa F401
Tests/test_PDB_vectors.py:    import numpy
Tests/test_RCSBFormats.py:    import numpy
Tests/test_SeqIO_PdbIO.py:    import numpy
Tests/test_SeqRecord.py:    import numpy
Tests/test_Seq_objs.py:    import numpy
Tests/test_codonalign.py:    import numpy
Tests/test_kNN.py:    import numpy
Tests/test_phenotype.py:    import numpy
Tests/test_phenotype_fit.py:    import numpy
Tests/test_seq.py:    import numpy
Bio/phenotype/__init__.py:    import numpy
```

Fix patch:
diff --git a/Bio/Align/_aligncore.c b/Bio/Align/_aligncore.c
index c0af9ab55c6..58fbef54203 100644
--- a/Bio/Align/_aligncore.c
+++ b/Bio/Align/_aligncore.c
@@ -451,8 +451,8 @@ PyDoc_STRVAR(
     "b'ACAGTT'\n"
     ">>> parser.shape\n"
     "(3, 7)\n"
-    ">>> import numpy\n"
-    ">>> coordinates = numpy.zeros((3, 7), int)\n"
+    ">>> import numpy as np\n"
+    ">>> coordinates = np.zeros((3, 7), int)\n"
     ">>> parser.fill(coordinates)\n"
     ">>> coordinates\n"
     "array([[ 0,  2,  3,  4,  6,  8, 10],\n"
diff --git a/Bio/phenotype/__init__.py b/Bio/phenotype/__init__.py
index 61f62b33134..1c652f736c3 100644
--- a/Bio/phenotype/__init__.py
+++ b/Bio/phenotype/__init__.py
@@ -85,7 +85,7 @@
 
 try:
     # Both phen_micro.py and pm_fitting require NumPy, so require NumPy here
-    import numpy
+    import numpy as np
 except ImportError:
     from Bio import MissingPythonDependencyError
 
diff --git a/CONTRIB.rst b/CONTRIB.rst
index a65b5169d7b..e1314eb1d01 100644
--- a/CONTRIB.rst
+++ b/CONTRIB.rst
@@ -184,6 +184,7 @@ please open an issue on GitHub or mention it on the mailing list.
 - John Bradley <https://github.com/johnbradley>
 - John Kern <https://github.com/kern3020>
 - John Ma <https://github.com/JohnMCMa>
+- John Stilley <https://github.com/john-science>
 - Jonathan Taylor <jonathan dot taylor at utoronto dot ca>
 - Jordan Willis <https://github.com/jwillis0720>
 - Jose Blanca <https://github.com/JoseBlanca>
diff --git a/Doc/Tutorial/chapter_align.rst b/Doc/Tutorial/chapter_align.rst
index e4a3eec24b9..7ca6a1aa183 100644
--- a/Doc/Tutorial/chapter_align.rst
+++ b/Doc/Tutorial/chapter_align.rst
@@ -4704,11 +4704,11 @@ matches to any unknown nucleotides separately.
 
 .. code:: pycon
 
-   >>> import numpy
+   >>> import numpy as np
    >>> from Bio import Align
    >>> query = "GGTGGGGG"
    >>> target = "AAAAAAAggggGGNGAAAAA"
-   >>> coordinates = numpy.array([[0, 7, 15, 20], [0, 0, 8, 8]])
+   >>> coordinates = np.array([[0, 7, 15, 20], [0, 0, 8, 8]])
    >>> alignment = Align.Alignment([target, query], coordinates)
    >>> print(alignment)
    target            0 AAAAAAAggggGGNGAAAAA 20


Test patch:
diff --git a/Tests/test_LogisticRegression.py b/Tests/test_LogisticRegression.py
index d2657aa3541..6c1ad3e9127 100644
--- a/Tests/test_LogisticRegression.py
+++ b/Tests/test_LogisticRegression.py
@@ -13,7 +13,7 @@
 import warnings
 
 try:
-    import numpy
+    import numpy as np
     from numpy import linalg  # missing in PyPy's micronumpy
 except ImportError:
     from Bio import MissingExternalDependencyError
diff --git a/Tests/test_PDB_Exposure.py b/Tests/test_PDB_Exposure.py
index e37aa8d318d..0cab0e0aaf5 100644
--- a/Tests/test_PDB_Exposure.py
+++ b/Tests/test_PDB_Exposure.py
@@ -18,7 +18,7 @@
 import warnings
 
 try:
-    import numpy
+    import numpy as np
 except ImportError:
     from Bio import MissingPythonDependencyError
 
diff --git a/Tests/test_PDB_FragmentMapper.py b/Tests/test_PDB_FragmentMapper.py
index cdca87a73c5..03feb97e557 100644
--- a/Tests/test_PDB_FragmentMapper.py
+++ b/Tests/test_PDB_FragmentMapper.py
@@ -11,7 +11,7 @@
 import unittest
 
 try:
-    import numpy
+    import numpy as np
 except ImportError:
     from Bio import MissingPythonDependencyError
 
diff --git a/Tests/test_PDB_MMCIF2Dict.py b/Tests/test_PDB_MMCIF2Dict.py
index 24f4980f58f..6b117ae3fa2 100644
--- a/Tests/test_PDB_MMCIF2Dict.py
+++ b/Tests/test_PDB_MMCIF2Dict.py
@@ -13,7 +13,7 @@
 import unittest
 
 try:
-    import numpy
+    import numpy as np
 except ImportError:
     from Bio import MissingPythonDependencyError
 
diff --git a/Tests/test_PDB_MMCIFParser.py b/Tests/test_PDB_MMCIFParser.py
index 6031c209e2f..736d2ae9054 100644
--- a/Tests/test_PDB_MMCIFParser.py
+++ b/Tests/test_PDB_MMCIFParser.py
@@ -15,7 +15,7 @@
 import warnings
 
 try:
-    import numpy
+    import numpy as np
     from numpy import dot  # Missing on old PyPy's micronumpy
 
     del dot
@@ -150,9 +150,9 @@ def test_parsers(self):
             self.assertEqual(
                 [a.get_occupancy() for a in atoms[:5]], [1.0, 1.0, 1.0, 1.0, 1.0]
             )
-            self.assertIsInstance(atoms[0].get_coord(), numpy.ndarray)
-            coord = numpy.array([19.594, 32.367, 28.012], dtype=numpy.float32)
-            numpy.testing.assert_array_equal(atoms[0].get_coord(), coord)
+            self.assertIsInstance(atoms[0].get_coord(), np.ndarray)
+            coord = np.array([19.594, 32.367, 28.012], dtype=np.float32)
+            np.testing.assert_array_equal(atoms[0].get_coord(), coord)
 
             self.assertEqual(atoms[0].get_bfactor(), 18.03)
             for atom in atoms:
@@ -181,20 +181,20 @@ def test_with_anisotrop(self):
             self.assertEqual(
                 [a.get_occupancy() for a in atoms[:5]], [1.0, 1.0, 1.0, 1.0, 1.0]
             )
-            self.assertIsInstance(atoms[0].get_coord(), numpy.ndarray)
-            coord = numpy.array([50.346, 19.287, 17.288], dtype=numpy.float32)
-            numpy.testing.assert_array_equal(atoms[0].get_coord(), coord)
+            self.assertIsInstance(atoms[0].get_coord(), np.ndarray)
+            coord = np.array([50.346, 19.287, 17.288], dtype=np.float32)
+            np.testing.assert_array_equal(atoms[0].get_coord(), coord)
             self.assertEqual(atoms[0].get_bfactor(), 32.02)
 
-            ansiou = numpy.array(
-                [0.4738, -0.0309, -0.0231, 0.4524, 0.0036, 0.2904], dtype=numpy.float32
+            ansiou = np.array(
+                [0.4738, -0.0309, -0.0231, 0.4524, 0.0036, 0.2904], dtype=np.float32
             )
-            numpy.testing.assert_array_equal(atoms[0].get_anisou(), ansiou)
-            ansiou = numpy.array(
-                [1.1242, 0.2942, -0.0995, 1.1240, -0.1088, 0.8221], dtype=numpy.float32
+            np.testing.assert_array_equal(atoms[0].get_anisou(), ansiou)
+            ansiou = np.array(
+                [1.1242, 0.2942, -0.0995, 1.1240, -0.1088, 0.8221], dtype=np.float32
             )
             atom_937 = list(f_structure[0]["A"])[114]["CB"]
-            numpy.testing.assert_array_equal(atom_937.get_anisou(), ansiou)
+            np.testing.assert_array_equal(atom_937.get_anisou(), ansiou)
 
     def testModels(self):
         """Test file with multiple models."""
diff --git a/Tests/test_PDB_NACCESS.py b/Tests/test_PDB_NACCESS.py
index 7f875a1892c..86e70adaf5d 100644
--- a/Tests/test_PDB_NACCESS.py
+++ b/Tests/test_PDB_NACCESS.py
@@ -20,7 +20,7 @@
 import unittest
 
 try:
-    import numpy
+    import numpy as np
 except ImportError:
     from Bio import MissingPythonDependencyError
 
diff --git a/Tests/test_PDB_PDBParser.py b/Tests/test_PDB_PDBParser.py
index c88c8d81d3c..46a3846d530 100644
--- a/Tests/test_PDB_PDBParser.py
+++ b/Tests/test_PDB_PDBParser.py
@@ -18,7 +18,7 @@
 from io import StringIO
 
 try:
-    import numpy
+    import numpy as np
 except ImportError:
     from Bio import MissingPythonDependencyError
 
diff --git a/Tests/test_PDB_SMCRA.py b/Tests/test_PDB_SMCRA.py
index 2d176fdf344..e764daca667 100644
--- a/Tests/test_PDB_SMCRA.py
+++ b/Tests/test_PDB_SMCRA.py
@@ -18,7 +18,7 @@
 from copy import deepcopy
 
 try:
-    import numpy
+    import numpy as np
     from numpy import dot  # Missing on old PyPy's micronumpy
 
     del dot
@@ -467,7 +467,7 @@ def get_total_pos(self, o):
         """Sum of positions of atoms in an entity along with the number of atoms."""
         if hasattr(o, "get_coord"):
             return o.get_coord(), 1
-        total_pos = numpy.array((0.0, 0.0, 0.0))
+        total_pos = np.array((0.0, 0.0, 0.0))
         total_count = 0
         for p in o.get_list():
             pos, count = self.get_total_pos(p)
@@ -484,11 +484,11 @@ def test_transform(self):
         """Transform entities (rotation and translation)."""
         for o in (self.s, self.m, self.c, self.r, self.a):
             rotation = rotmat(Vector(1, 3, 5), Vector(1, 0, 0))
-            translation = numpy.array((2.4, 0, 1), "f")
+            translation = np.array((2.4, 0, 1), "f")
             oldpos = self.get_pos(o)
             o.transform(rotation, translation)
             newpos = self.get_pos(o)
-            newpos_check = numpy.dot(oldpos, rotation) + translation
+            newpos_check = np.dot(oldpos, rotation) + translation
             for i in range(3):
                 self.assertAlmostEqual(newpos[i], newpos_check[i])
 
@@ -534,13 +534,13 @@ def test_structure_com(self):
         """Calculate Structure center of mass."""
         com = self.structure.center_of_mass()
 
-        self.assertTrue(numpy.allclose(com, [19.870, 25.455, 28.753], atol=1e-3))
+        self.assertTrue(np.allclose(com, [19.870, 25.455, 28.753], atol=1e-3))
 
     def test_structure_cog(self):
         """Calculate Structure center of geometry."""
         cog = self.structure.center_of_mass(geometric=True)
 
-        self.assertTrue(numpy.allclose(cog, [19.882, 25.842, 28.333], atol=1e-3))
+        self.assertTrue(np.allclose(cog, [19.882, 25.842, 28.333], atol=1e-3))
 
     def test_chain_cog(self):
         """Calculate center of geometry of individual chains."""
@@ -552,7 +552,7 @@ def test_chain_cog(self):
 
         for chain in self.structure[0].get_chains():  # one model only
             cog = chain.center_of_mass(geometric=True)
-            self.assertTrue(numpy.allclose(cog, expected[chain.id], atol=1e-3))
+            self.assertTrue(np.allclose(cog, expected[chain.id], atol=1e-3))
 
     def test_com_empty_structure(self):
         """Center of mass of empty structure raises ValueError."""
diff --git a/Tests/test_PDB_Superimposer.py b/Tests/test_PDB_Superimposer.py
index 76af77a5eb2..87e78279a8f 100644
--- a/Tests/test_PDB_Superimposer.py
+++ b/Tests/test_PDB_Superimposer.py
@@ -12,7 +12,7 @@
 import unittest
 
 try:
-    import numpy
+    import numpy as np
 except ImportError:
     from Bio import MissingPythonDependencyError
 
@@ -36,14 +36,14 @@ def test_Superimposer(self):
         fixed = Selection.unfold_entities(s1, "A")
         s2 = p.get_structure("MOVING", pdb1)
         moving = Selection.unfold_entities(s2, "A")
-        rot = numpy.identity(3).astype("f")
-        tran = numpy.array((1.0, 2.0, 3.0), "f")
+        rot = np.identity(3).astype("f")
+        tran = np.array((1.0, 2.0, 3.0), "f")
         for atom in moving:
             atom.transform(rot, tran)
         sup = Superimposer()
         sup.set_atoms(fixed, moving)
-        self.assertTrue(numpy.allclose(sup.rotran[0], numpy.identity(3)))
-        self.assertTrue(numpy.allclose(sup.rotran[1], numpy.array([-1.0, -2.0, -3.0])))
+        self.assertTrue(np.allclose(sup.rotran[0], np.identity(3)))
+        self.assertTrue(np.allclose(sup.rotran[1], np.array([-1.0, -2.0, -3.0])))
         self.assertAlmostEqual(sup.rms, 0.0, places=3)
         # Turn black code style off
         # fmt: off
diff --git a/Tests/test_PDB_vectors.py b/Tests/test_PDB_vectors.py
index 1d16b5c0cbf..b34c1d3d01b 100644
--- a/Tests/test_PDB_vectors.py
+++ b/Tests/test_PDB_vectors.py
@@ -9,7 +9,7 @@
 import unittest
 
 try:
-    import numpy
+    import numpy as np
     from numpy.random import random
 except ImportError:
     from Bio import MissingPythonDependencyError
@@ -49,40 +49,30 @@ def test_Vector(self):
         self.assertEqual(calc_angle(v1, v2, v3), 1.5707963267948966)
         self.assertEqual(calc_dihedral(v1, v2, v3, v4), 1.5707963267948966)
         self.assertTrue(
-            numpy.array_equal((v1 - v2).get_array(), numpy.array([0.0, 0.0, 1.0]))
+            np.array_equal((v1 - v2).get_array(), np.array([0.0, 0.0, 1.0]))
         )
         self.assertTrue(
-            numpy.array_equal((v1 - 1).get_array(), numpy.array([-1.0, -1.0, 0.0]))
+            np.array_equal((v1 - 1).get_array(), np.array([-1.0, -1.0, 0.0]))
         )
         self.assertTrue(
-            numpy.array_equal(
-                (v1 - (1, 2, 3)).get_array(), numpy.array([-1.0, -2.0, -2.0])
-            )
-        )
-        self.assertTrue(
-            numpy.array_equal((v1 + v2).get_array(), numpy.array([0.0, 0.0, 1.0]))
+            np.array_equal((v1 - (1, 2, 3)).get_array(), np.array([-1.0, -2.0, -2.0]))
         )
         self.assertTrue(
-            numpy.array_equal((v1 + 3).get_array(), numpy.array([3.0, 3.0, 4.0]))
+            np.array_equal((v1 + v2).get_array(), np.array([0.0, 0.0, 1.0]))
         )
+        self.assertTrue(np.array_equal((v1 + 3).get_array(), np.array([3.0, 3.0, 4.0])))
         self.assertTrue(
-            numpy.array_equal(
-                (v1 + (1, 2, 3)).get_array(), numpy.array([1.0, 2.0, 4.0])
-            )
+            np.array_equal((v1 + (1, 2, 3)).get_array(), np.array([1.0, 2.0, 4.0]))
         )
-        self.assertTrue(numpy.array_equal(v1.get_array() / 2, numpy.array([0, 0, 0.5])))
-        self.assertTrue(numpy.array_equal(v1.get_array() / 2, numpy.array([0, 0, 0.5])))
+        self.assertTrue(np.array_equal(v1.get_array() / 2, np.array([0, 0, 0.5])))
+        self.assertTrue(np.array_equal(v1.get_array() / 2, np.array([0, 0, 0.5])))
         self.assertEqual(v1 * v2, 0.0)
         self.assertTrue(
-            numpy.array_equal((v1**v2).get_array(), numpy.array([0.0, -0.0, 0.0]))
+            np.array_equal((v1**v2).get_array(), np.array([0.0, -0.0, 0.0]))
         )
+        self.assertTrue(np.array_equal((v1**2).get_array(), np.array([0.0, 0.0, 2.0])))
         self.assertTrue(
-            numpy.array_equal((v1**2).get_array(), numpy.array([0.0, 0.0, 2.0]))
-        )
-        self.assertTrue(
-            numpy.array_equal(
-                (v1 ** (1, 2, 3)).get_array(), numpy.array([0.0, 0.0, 3.0])
-            )
+            np.array_equal((v1 ** (1, 2, 3)).get_array(), np.array([0.0, 0.0, 3.0]))
         )
         self.assertEqual(v1.norm(), 1.0)
         self.assertEqual(v1.normsq(), 1.0)
@@ -93,40 +83,36 @@ def test_normalization(self):
         """Test Vector normalization."""
         v1 = Vector([2, 0, 0])
         self.assertTrue(
-            numpy.array_equal(v1.normalized().get_array(), numpy.array([1, 0, 0]))
+            np.array_equal(v1.normalized().get_array(), np.array([1, 0, 0]))
         )
         # State of v1 should not be affected by `normalized`
-        self.assertTrue(numpy.array_equal(v1.get_array(), numpy.array([2, 0, 0])))
+        self.assertTrue(np.array_equal(v1.get_array(), np.array([2, 0, 0])))
         v1.normalize()
         # State of v1 should be affected by `normalize`
-        self.assertTrue(numpy.array_equal(v1.get_array(), numpy.array([1, 0, 0])))
+        self.assertTrue(np.array_equal(v1.get_array(), np.array([1, 0, 0])))
 
     def test_refmat(self):
         """Test refmat can mirror one matrix to another."""
         v1 = Vector(0, 0, 1)
         v2 = Vector(0, 1, 0)
         ref = refmat(v1, v2)
-        self.assertTrue(numpy.allclose(ref[0], [1.0, 0.0, 0.0]))
-        self.assertTrue(numpy.allclose(ref[1], [0.0, 0.0, 1.0]))
-        self.assertTrue(numpy.allclose(ref[2], [0.0, 1.0, 0.0]))
-        self.assertTrue(
-            numpy.allclose(v1.left_multiply(ref).get_array(), [0.0, 1.0, 0.0])
-        )
+        self.assertTrue(np.allclose(ref[0], [1.0, 0.0, 0.0]))
+        self.assertTrue(np.allclose(ref[1], [0.0, 0.0, 1.0]))
+        self.assertTrue(np.allclose(ref[2], [0.0, 1.0, 0.0]))
+        self.assertTrue(np.allclose(v1.left_multiply(ref).get_array(), [0.0, 1.0, 0.0]))
 
     def test_rotmat_90(self):
         """Test regular 90 deg rotation."""
         v1 = Vector(0, 0, 1)
         v2 = Vector(0, 1, 0)
         rot = rotmat(v1, v2)
-        self.assertTrue(numpy.allclose(rot[0], numpy.array([1.0, 0.0, 0.0])))
-        self.assertTrue(numpy.allclose(rot[1], numpy.array([0.0, 0.0, 1.0])))
-        self.assertTrue(numpy.allclose(rot[2], numpy.array([0.0, -1.0, 0.0])))
-        self.assertTrue(
-            numpy.allclose(v1.left_multiply(rot).get_array(), [0.0, 1.0, 0.0])
-        )
+        self.assertTrue(np.allclose(rot[0], np.array([1.0, 0.0, 0.0])))
+        self.assertTrue(np.allclose(rot[1], np.array([0.0, 0.0, 1.0])))
+        self.assertTrue(np.allclose(rot[2], np.array([0.0, -1.0, 0.0])))
+        self.assertTrue(np.allclose(v1.left_multiply(rot).get_array(), [0.0, 1.0, 0.0]))
         self.assertTrue(
-            numpy.allclose(
-                v1.right_multiply(numpy.transpose(rot)).get_array(),
+            np.allclose(
+                v1.right_multiply(np.transpose(rot)).get_array(),
                 [0.0, 1.0, 0.0],
             )
         )
@@ -137,7 +123,7 @@ def test_rotmat_180(self):
         v2 = Vector([-1.0, -0.8, 0])
         rot = rotmat(v1, v2)
         v3 = v1.left_multiply(rot)
-        self.assertTrue(numpy.allclose(v2.get_array(), v3.get_array()))
+        self.assertTrue(np.allclose(v2.get_array(), v3.get_array()))
 
     def test_rotmat_0(self):
         """Test rotmat when the rotation is 0 deg (singularity)."""
@@ -145,7 +131,7 @@ def test_rotmat_0(self):
         v2 = Vector([1.0, 0.8, 0])
         rot = rotmat(v1, v2)
         v3 = v1.left_multiply(rot)
-        self.assertTrue(numpy.allclose(v1.get_array(), v3.get_array()))
+        self.assertTrue(np.allclose(v1.get_array(), v3.get_array()))
 
     def test_m2rotaxis_90(self):
         """Test 90 deg rotation."""
@@ -153,8 +139,8 @@ def test_m2rotaxis_90(self):
         v2 = Vector(0, 1, 0)
         rot = rotmat(v1, v2)
         angle, axis = m2rotaxis(rot)
-        self.assertTrue(numpy.allclose(axis.get_array(), [-1.0, 0.0, 0.0]))
-        self.assertLess(abs(angle - numpy.pi / 2), 1e-5)
+        self.assertTrue(np.allclose(axis.get_array(), [-1.0, 0.0, 0.0]))
+        self.assertLess(abs(angle - np.pi / 2), 1e-5)
 
     def test_m2rotaxis_180(self):
         """Test 180 deg rotation."""
@@ -163,7 +149,7 @@ def test_m2rotaxis_180(self):
         rot = rotmat(v1, v2)
         angle, axis = m2rotaxis(rot)
         self.assertLess(abs(axis * v1), 1e-5)  # axis orthogonal to v1
-        self.assertLess(abs(angle - numpy.pi), 1e-5)
+        self.assertLess(abs(angle - np.pi), 1e-5)
 
     def test_m2rotaxis_0(self):
         """Test 0 deg rotation. Axis must be [1, 0, 0] as per Vector docs."""
@@ -171,29 +157,29 @@ def test_m2rotaxis_0(self):
         v2 = Vector([1.0, 0.8, 0])
         rot = rotmat(v1, v2)
         angle, axis = m2rotaxis(rot)
-        self.assertTrue(numpy.allclose(axis.get_array(), [1, 0, 0]))
+        self.assertTrue(np.allclose(axis.get_array(), [1, 0, 0]))
         self.assertLess(abs(angle), 1e-5)
 
     def test_Vector_angles(self):
         """Test Vector angles."""
-        angle = random() * numpy.pi
+        angle = random() * np.pi
         axis = Vector(random(3) - random(3))
         axis.normalize()
         m = rotaxis(angle, axis)
         cangle, caxis = m2rotaxis(m)
         self.assertAlmostEqual(angle, cangle, places=3)
         self.assertTrue(
-            numpy.allclose(list(map(int, (axis - caxis).get_array())), [0, 0, 0]),
+            np.allclose(list(map(int, (axis - caxis).get_array())), [0, 0, 0]),
             f"Want {axis.get_array()!r} and {caxis.get_array()!r}"
             " to be almost equal",
         )
 
     def test_get_spherical_coordinates(self):
         """Test spherical coordinates."""
-        srt22 = numpy.sqrt(2.0) / 2
-        r45 = numpy.radians(45)
-        # r90 = numpy.radians(90)
-        r135 = numpy.radians(135)
+        srt22 = np.sqrt(2.0) / 2
+        r45 = np.radians(45)
+        # r90 = np.radians(90)
+        r135 = np.radians(135)
         for i in range(2):
             for j in range(2):
                 for k in range(2):
@@ -204,7 +190,7 @@ def test_get_spherical_coordinates(self):
                             (1 if k else -1) * srt22,
                         ]
                     )
-                    # print(sc[0], numpy.degrees(sc[1]), numpy.degrees(sc[2]))
+                    # print(sc[0], np.degrees(sc[1]), np.degrees(sc[2]))
                     self.assertEqual(1.0, sc[0])  # r
                     self.assertEqual(
                         (1 if j else -1) * (r45 if i else r135), sc[1]
@@ -215,15 +201,15 @@ def test_coord_space(self):
         """Confirm can generate coordinate space transform for 3 points."""
         # start with 3 points already aligned to axes
         point_set = (
-            numpy.array([[2.0], [0.0], [2.0], [1.0]]),
-            numpy.array([[0.0], [0.0], [0.0], [1.0]]),
-            numpy.array([[0.0], [0.0], [2.0], [1.0]]),
+            np.array([[2.0], [0.0], [2.0], [1.0]]),
+            np.array([[0.0], [0.0], [0.0], [1.0]]),
+            np.array([[0.0], [0.0], [2.0], [1.0]]),
         )
         # confirm get id matrix to transform to/from coord space
-        homog_id = numpy.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]])
+        homog_id = np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]])
         mtxs = coord_space(point_set[0], point_set[1], point_set[2], True)
         for i in range(2):
-            self.assertTrue(numpy.array_equal(mtxs[i], homog_id))
+            self.assertTrue(np.array_equal(mtxs[i], homog_id))
         # test in every quadrant
         for i in range(2):
             for j in range(2):
@@ -241,17 +227,17 @@ def test_coord_space(self):
                     rslt = [1, 2, 3]
                     for i in range(3):
                         rslt[i] = mtxs[0].dot(ps2[i])
-                    self.assertTrue(numpy.array_equal(rslt, point_set))
+                    self.assertTrue(np.array_equal(rslt, point_set))
 
                     # confirm reverse transform returns translated points
                     for i in range(3):
                         rslt[i] = mtxs[1].dot(rslt[i])
-                    self.assertTrue(numpy.array_equal(rslt, ps2))
+                    self.assertTrue(np.array_equal(rslt, ps2))
 
     def test_multi_coord_space(self):
         """Confirm multi_coord_space computes forward, reverse transforms."""
         # start with 3 points already aligned to axes
-        point_set = numpy.array(
+        point_set = np.array(
             [
                 [
                     [2.0, 0.0, 2.0, 1.0],
@@ -261,12 +247,12 @@ def test_multi_coord_space(self):
             ]
         )
         # confirm get id matrix to transform to/from coord space
-        homog_id = numpy.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]])
+        homog_id = np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]])
         mtxs = multi_coord_space(point_set, 1, True)
         for i in range(2):
-            self.assertTrue(numpy.array_equal(mtxs[i][0], homog_id))
+            self.assertTrue(np.array_equal(mtxs[i][0], homog_id))
         # test in every quadrant
-        test_set = numpy.empty([8, 3, 4], dtype=numpy.float64)
+        test_set = np.empty([8, 3, 4], dtype=np.float64)
         m = 0
         for i in range(2):
             for j in range(2):
@@ -285,12 +271,12 @@ def test_multi_coord_space(self):
             rslt = [1, 2, 3]
             for i in range(3):
                 rslt[i] = mtxs[0][m].dot(test_set[m][i])
-            self.assertTrue(numpy.array_equal(rslt, point_set[0]))
+            self.assertTrue(np.array_equal(rslt, point_set[0]))
 
             # confirm reverse transform returns translated points
             for i in range(3):
                 rslt[i] = mtxs[1][m].dot(rslt[i])
-            self.assertTrue(numpy.array_equal(rslt, test_set[m]))
+            self.assertTrue(np.array_equal(rslt, test_set[m]))
 
 
 if __name__ == "__main__":
diff --git a/Tests/test_RCSBFormats.py b/Tests/test_RCSBFormats.py
index 4493263f303..d8109e2cd7d 100644
--- a/Tests/test_RCSBFormats.py
+++ b/Tests/test_RCSBFormats.py
@@ -12,7 +12,7 @@
 import warnings
 
 try:
-    import numpy
+    import numpy as np
     from numpy import dot  # Missing on old PyPy's micronumpy
 
     del dot
diff --git a/Tests/test_SeqIO_PdbIO.py b/Tests/test_SeqIO_PdbIO.py
index 2658d936c64..8981cc8af98 100644
--- a/Tests/test_SeqIO_PdbIO.py
+++ b/Tests/test_SeqIO_PdbIO.py
@@ -8,7 +8,7 @@
 import warnings
 
 try:
-    import numpy
+    import numpy as np
     from numpy import dot  # Missing on PyPy's micronumpy
 
     del dot
diff --git a/Tests/test_SeqRecord.py b/Tests/test_SeqRecord.py
index ff93b407216..a1cc90f9b7d 100644
--- a/Tests/test_SeqRecord.py
+++ b/Tests/test_SeqRecord.py
@@ -11,9 +11,9 @@
 import unittest
 
 try:
-    import numpy
+    import numpy as np
 except ImportError:
-    numpy = None  # type: ignore
+    np = None  # type: ignore
 
 from Bio import BiopythonDeprecationWarning
 from Bio import SeqIO
@@ -245,8 +245,8 @@ def test_slicing(self):
         self.assertEqual("BC", self.record[1:3].seq)
         with self.assertRaises(ValueError):
             c = self.record["a"].seq
-        if numpy is not None:
-            start, stop = numpy.array([1, 3])  # numpy integers
+        if np is not None:
+            start, stop = np.array([1, 3])  # numpy integers
             self.assertEqual("B", self.record[start])
             self.assertEqual("BC", self.record[start:stop].seq)
 
diff --git a/Tests/test_Seq_objs.py b/Tests/test_Seq_objs.py
index 4d1f41fe698..55300c63262 100644
--- a/Tests/test_Seq_objs.py
+++ b/Tests/test_Seq_objs.py
@@ -22,9 +22,9 @@
 from Bio.SeqRecord import SeqRecord
 
 try:
-    import numpy
+    import numpy as np
 except ImportError:
-    numpy = None
+    np = None
 
 # This is just the standard table with less stop codons
 # (replaced with coding for O as an artificial example)
@@ -89,9 +89,9 @@ class StringMethodTests(unittest.TestCase):
     for seq in _examples[:]:
         _examples.append(MutableSeq(seq))
     _start_end_values = [0, 1, 2, 1000, -1, -2, -999, None]
-    if numpy is not None:
-        # test with numpy integers (numpy.int32, numpy.int64 etc.)
-        _start_end_values.extend(numpy.array([3, 5]))
+    if np is not None:
+        # test with numpy integers (np.int32, np.int64 etc.)
+        _start_end_values.extend(np.array([3, 5]))
 
     def _test_method(self, method_name, start_end=False):
         """Check this method matches the plain string's method."""
diff --git a/Tests/test_codonalign.py b/Tests/test_codonalign.py
index 82364096906..156f3cb8493 100644
--- a/Tests/test_codonalign.py
+++ b/Tests/test_codonalign.py
@@ -453,11 +453,11 @@ def test_dn_ds_matrix(self):
 
 
 try:
-    import numpy
+    import numpy as np
 except ImportError:
-    numpy = None
+    np = None
 
-if numpy:
+if np:
 
     class Test_MK(unittest.TestCase):
         def test_mk(self):
diff --git a/Tests/test_kNN.py b/Tests/test_kNN.py
index fa895e12083..3f33b20a04b 100644
--- a/Tests/test_kNN.py
+++ b/Tests/test_kNN.py
@@ -12,9 +12,9 @@
 import warnings
 
 try:
-    import numpy
+    import numpy as np
 
-    del numpy
+    del np
     from numpy import asarray
 
     del asarray
diff --git a/Tests/test_phenotype.py b/Tests/test_phenotype.py
index 1cedf29302c..e322e0ef0de 100644
--- a/Tests/test_phenotype.py
+++ b/Tests/test_phenotype.py
@@ -8,9 +8,9 @@
 """Tests for the Bio.phenotype module."""
 
 try:
-    import numpy
+    import numpy as np
 
-    del numpy
+    del np
 except ImportError:
     from Bio import MissingExternalDependencyError
 
diff --git a/Tests/test_phenotype_fit.py b/Tests/test_phenotype_fit.py
index 0455fcd844b..c3926d1a50c 100644
--- a/Tests/test_phenotype_fit.py
+++ b/Tests/test_phenotype_fit.py
@@ -8,9 +8,9 @@
 """Tests for the Bio.phenotype module's fitting functionality."""
 
 try:
-    import numpy
+    import numpy as np
 
-    del numpy
+    del np
 except ImportError:
     from Bio import MissingExternalDependencyError
 
diff --git a/Tests/test_seq.py b/Tests/test_seq.py
index f59744b563d..060fc3b2e9c 100644
--- a/Tests/test_seq.py
+++ b/Tests/test_seq.py
@@ -9,9 +9,9 @@
 import warnings
 
 try:
-    import numpy
+    import numpy as np
 except ImportError:
-    numpy = None
+    np = None
 
 from Bio import BiopythonWarning
 from Bio import Seq
@@ -469,8 +469,8 @@ def test_mul_method(self):
         """Test mul method; relies on addition method."""
         for seq in test_seqs + protein_seqs:
             self.assertEqual(seq * 3, seq + seq + seq)
-        if numpy is not None:
-            factor = numpy.intc(3)  # numpy integer
+        if np is not None:
+            factor = np.intc(3)  # numpy integer
             for seq in test_seqs + protein_seqs:
                 self.assertEqual(seq * factor, seq + seq + seq)
 
@@ -486,8 +486,8 @@ def test_rmul_method(self):
         """Test rmul method; relies on addition method."""
         for seq in test_seqs + protein_seqs:
             self.assertEqual(3 * seq, seq + seq + seq)
-        if numpy is not None:
-            factor = numpy.intc(3)  # numpy integer
+        if np is not None:
+            factor = np.intc(3)  # numpy integer
             for seq in test_seqs + protein_seqs:
                 self.assertEqual(factor * seq, seq + seq + seq)
 
@@ -505,8 +505,8 @@ def test_imul_method(self):
             original_seq = seq * 1  # make a copy
             seq *= 3
             self.assertEqual(seq, original_seq + original_seq + original_seq)
-        if numpy is not None:
-            factor = numpy.intc(3)  # numpy integer
+        if np is not None:
+            factor = np.intc(3)  # numpy integer
             for seq in test_seqs + protein_seqs:
                 original_seq = seq * 1  # make a copy
                 seq *= factor
@@ -673,8 +673,8 @@ def test_setting_slices(self):
             self.mutable_s,
             "Set slice with MutableSeq",
         )
-        if numpy is not None:
-            one, three, five, seven = numpy.array([1, 3, 5, 7])  # numpy integers
+        if np is not None:
+            one, three, five, seven = np.array([1, 3, 5, 7])  # numpy integers
             self.assertEqual(
                 Seq.MutableSeq("AATA"), self.mutable_s[one:five], "Slice mutable seq"
             )
@@ -696,8 +696,8 @@ def test_setting_slices(self):
     def test_setting_item(self):
         self.mutable_s[3] = "G"
         self.assertEqual(Seq.MutableSeq("TCAGAAGGATGCATCATG"), self.mutable_s)
-        if numpy is not None:
-            i = numpy.intc(3)
+        if np is not None:
+            i = np.intc(3)
             self.mutable_s[i] = "X"
             self.assertEqual(Seq.MutableSeq("TCAXAAGGATGCATCATG"), self.mutable_s)
 
@@ -828,8 +828,8 @@ def test_set_wobble_codon_to_n(self):
         """Test setting wobble codon to N (set slice with stride 3)."""
         self.mutable_s[2::3] = "N" * len(self.mutable_s[2::3])
         self.assertEqual(Seq.MutableSeq("TCNAANGGNTGNATNATN"), self.mutable_s)
-        if numpy is not None:
-            start, step = numpy.array([2, 3])  # numpy integers
+        if np is not None:
+            start, step = np.array([2, 3])  # numpy integers
             self.mutable_s[start::step] = "X" * len(self.mutable_s[2::3])
             self.assertEqual(Seq.MutableSeq("TCXAAXGGXTGXATXATX"), self.mutable_s)