Repository: einsteinpy/einsteinpy

Issue:
Add Tensor name to __str__ and __repr__ in Tensor Class
<!--

WELCOME ABOARD!

Hi and welcome to the einsteinpy project. We appreciate bug reports, questions
about documentation, and suggestions for new features.

IMPORTANT: If you are reporting a problem with einsteinpy, please follow the
template below. If it's a suggestion, a possible new addition to the library,
or just want to say "Thank you!", you can remove all this text and start
from scratch.

-->
<!--- Provide a general summary of the issue in the Title above -->

🐞 **What bugs you?**

Currently, both `str` and `repr`,  in `einsteinpy.symbolic.tensor.py > Tensor`, don't show the Tensor name. As such, there is only one way to check the name, that is by explicitly accessing `tensor.name`.

🎯 **Goal**
<!--- Why is this change important to you? How would you use it? -->
<!--- How can it benefit other users? -->
Technically, `str` is supposed to be readable and `repr` is supposed to be unambiguous. Outputting the tensor `name` should improve both.

💡 **Possible solutions**
<!--- Not obligatory, but suggest an idea for implementing addition or change -->
Add `name` to `str` and  `repr`. For example, the output of `str(tensor)` could be something like:
```
Tensor TensorName 
[[...]]
```

📋  **Steps to solve the problem**

 * Comment below about what you've started working on.
 * Add, commit, push your changes
 * Submit a pull request and add this in comments - `Addresses #<put issue number here>`
 * Ask for a review in comments section of pull request
 * Celebrate your contribution to this project 🎉


Discussion:
pep8speaks: Hello @Starninja666! Thanks for opening this PR. We checked the lines you've touched for [PEP 8](https://www.python.org/dev/peps/pep-0008) issues, and found:

* In the file [`src/einsteinpy/symbolic/tensor.py`](https://github.com/einsteinpy/einsteinpy/blob/95738f07c030cb5fcdd6681dcae4adc52c6fcd61/src/einsteinpy/symbolic/tensor.py):

> [Line 130:34](https://github.com/einsteinpy/einsteinpy/blob/95738f07c030cb5fcdd6681dcae4adc52c6fcd61/src/einsteinpy/symbolic/tensor.py#L130): [W291](https://duckduckgo.com/?q=pep8%20W291) trailing whitespace
> [Line 133:31](https://github.com/einsteinpy/einsteinpy/blob/95738f07c030cb5fcdd6681dcae4adc52c6fcd61/src/einsteinpy/symbolic/tensor.py#L133): [W291](https://duckduckgo.com/?q=pep8%20W291) trailing whitespace


shreyasbapat: Thanks for the Pull Request! I will review in a while.
codecov[bot]: # [Codecov](https://codecov.io/gh/einsteinpy/einsteinpy/pull/458?src=pr&el=h1) Report
> Merging [#458](https://codecov.io/gh/einsteinpy/einsteinpy/pull/458?src=pr&el=desc) into [master](https://codecov.io/gh/einsteinpy/einsteinpy/commit/8da5d43f3336bea32df30e44be9f3bd4fe7d1afd&el=desc) will **decrease** coverage by `0.03%`.
> The diff coverage is `83.33%`.

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

```diff
@@            Coverage Diff             @@
##           master     #458      +/-   ##
==========================================
- Coverage   94.55%   94.51%   -0.04%     
==========================================
  Files          63       63              
  Lines        2075     2079       +4     
==========================================
+ Hits         1962     1965       +3     
- Misses        113      114       +1     
```


| [Impacted Files](https://codecov.io/gh/einsteinpy/einsteinpy/pull/458?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [src/einsteinpy/symbolic/tensor.py](https://codecov.io/gh/einsteinpy/einsteinpy/pull/458/diff?src=pr&el=tree#diff-c3JjL2VpbnN0ZWlucHkvc3ltYm9saWMvdGVuc29yLnB5) | `96.61% <83.33%> (-0.76%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/einsteinpy/einsteinpy/pull/458?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/einsteinpy/einsteinpy/pull/458?src=pr&el=footer). Last update [8da5d43...22fdff6](https://codecov.io/gh/einsteinpy/einsteinpy/pull/458?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

ritzvik: https://github.com/einsteinpy/einsteinpy/blob/b8351acb11eae83d55c8b861590fe8e16b82f768/src/einsteinpy/symbolic/tensor.py#L263-L267

Here, offload the responsibility of `name` parameter to `Tensor` class by `super(BaseRelativityTensor, self).__init__(arr=arr, config=config, name=name)` and remove the line `self.name=name`. 

Also, change the default `None` into `name="GenericTensor"` in `BaseRelativityTensor`. Update the docstrings accordingly
ritzvik: For quality checks
https://docs.einsteinpy.org/en/latest/dev_guide.html#code-linting
ritzvik: > https://github.com/einsteinpy/einsteinpy/blob/b8351acb11eae83d55c8b861590fe8e16b82f768/src/einsteinpy/symbolic/tensor.py#L263-L267
> 
> Here, offload the responsibility of `name` parameter to `Tensor` class by `super(BaseRelativityTensor, self).__init__(arr=arr, config=config, name=name)` and remove the line `self.name=name`.
> 
> Also, change the default `None` into `name="GenericTensor"` in `BaseRelativityTensor`. Update the docstrings accordingly

No need to change default name. It's already done in another PR. Just rebase
Starninja666: All requested changes have been made, please review! :) 
ritzvik: Code coverage is low because the tests are not hitting the `if` condition.

https://github.com/einsteinpy/einsteinpy/blob/0151c00e292abec7a172705196ec89e276e52804/src/einsteinpy/tests/test_symbolic/test_tensor.py#L113-L117

```
obj1 = Tensor(test_list, name="blah blah")
assert .... # whatever assert is already there
assert ("blah blah" in str(obj1))
```

This would fix it(probably)
ritzvik: After the changes, rebase :)

Patch:
diff --git a/src/einsteinpy/symbolic/tensor.py b/src/einsteinpy/symbolic/tensor.py
index eee06a4..2416859 100644
--- a/src/einsteinpy/symbolic/tensor.py
+++ b/src/einsteinpy/symbolic/tensor.py
@@ -71,7 +71,7 @@ class Tensor:
     Base Class for Tensor manipulation
     """
 
-    def __init__(self, arr, config="ll"):
+    def __init__(self, arr, config="ll", name=None):
         """
         Constructor and Initializer
         
@@ -81,6 +81,8 @@ class Tensor:
             Sympy Array, multi-dimensional list containing Sympy Expressions, or Sympy Expressions or int or float scalar
         config : str
             Configuration of contravariant and covariant indices in tensor. 'u' for upper and 'l' for lower indices. Defaults to 'll'.
+        name : str or None
+            Name of the tensor.
 
         Raises
         ------
@@ -104,6 +106,7 @@ class Tensor:
             raise TypeError(
                 "config is either not of type 'str' or does contain characters other than 'l' or 'u'"
             )
+        self.name = name
 
     @property
     def order(self):
@@ -129,7 +132,10 @@ class Tensor:
         Returns a String with a readable representation of the object of class Tensor
 
         """
-        representation = "Tensor" + "\n"
+        representation = "Tensor"
+        if self.name is not None:
+            representation = " ".join((representation, self.name))
+        representation += "\n"
         representation += self.arr.__str__()
         return representation
 
@@ -263,11 +269,10 @@ class BaseRelativityTensor(Tensor):
             Raised when argument parent_metric does not belong to MetricTensor class and isn't None.
 
         """
-        super(BaseRelativityTensor, self).__init__(arr=arr, config=config)
+        super(BaseRelativityTensor, self).__init__(arr=arr, config=config, name=name)
         # Cannot implement the check that parent metric belongs to the class MetricTensor
         # Due to the issue of cyclic imports, would find a workaround
         self._parent_metric = parent_metric
-        self.name = name
         if isinstance(syms, (list, tuple)):
             self.syms = syms
             self.dims = len(self.syms)


Test patch:
diff --git a/src/einsteinpy/tests/test_symbolic/test_tensor.py b/src/einsteinpy/tests/test_symbolic/test_tensor.py
index 3cb7d6c..17e5c0e 100644
--- a/src/einsteinpy/tests/test_symbolic/test_tensor.py
+++ b/src/einsteinpy/tests/test_symbolic/test_tensor.py
@@ -113,8 +113,9 @@ def test_Tensor_getitem():
 def test_Tensor_str():
     x, y, z = symbols("x y z")
     test_list = [[[x, y], [y, x]], [[z, x], [y, z]]]
-    obj1 = Tensor(test_list)
+    obj1 = Tensor(test_list, name="Test")
     assert "object at 0x" not in str(obj1)
+    assert "Test" in str(obj1)
 
 
 def test_Tensor_repr():