Repository: saulpw/visidata

Issue:
python-dateutil should not be needed to run VisiData
VisiData uses `python-dateutil` for its **date** type. It is considered a non-optional dependency, and part of the default installations for every package of VisiData.

However, if absent, VisiData should still be executable, if the **date** type is not being used.

`bin/visidata`, an entrypoint set-up by pip, seems to add it as a run requirement. Possibly, because it is part of the `setup.py` `install_requires`.

The goal for this issue is to investigate that more, and see if it is possible to remove `python-dateutil` from `bin/visidata`'s run requirement.


Discussion:
bin/visidata
```
 #!/usr/bin/python3                                                                                                                                
 # EASY-INSTALL-ENTRY-SCRIPT: 'visidata','console_scripts','visidata'                                                                              
 __requires__ = 'visidata'                                                                                                                         
 import re                                                                                                                                         
 import sys                                                                                                                                        
 from pkg_resources import load_entry_point                                                                                                        
                                                                                                                                                   
 if __name__ == '__main__':                                                                                                                        
     sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])                                                                             
     sys.exit(                                                                                                                                     
         load_entry_point('visidata', 'console_scripts', 'visidata')()                                                                             
     )  
```

setup.py
```
    entry_points={'console_scripts': [                                                                                                          
           'visidata=visidata.main:vd_cli'                                                                                                         
         ],                                                                                                                                        
       },                                                                                                                                          
```
    
Maybe the fix is having a try/except around this part?

visidata/_types.py
```
         elif isinstance(s, str):                                                                                                                  
             r = dateutil.parser.parse(s)  
```

returning an `ExpectedException` if the module is not available. Otherwise, I am not sure where `dateutil` is being pulled from.

Resolving patch:
diff --git a/visidata/_types.py b/visidata/_types.py
--- a/visidata/_types.py
+++ b/visidata/_types.py
@@ -14,9 +14,11 @@
 vd.option('disp_date_fmt','%Y-%m-%d', 'default fmtstr to strftime for date values', replay=True)
 
 try:
-    import dateutil.parser
+    from dateutil.parser import parse as date_parse
 except ImportError:
-    pass
+    def date_parse(r=''):
+        vd.warning('install python-dateutil for date type')
+        return r
 
 # VisiDataType .typetype are e.g. int, float, str, and used internally in these ways:
 #
@@ -163,7 +165,7 @@ def __new__(cls, *args, **kwargs):
         if isinstance(s, int) or isinstance(s, float):
             r = datetime.datetime.fromtimestamp(s)
         elif isinstance(s, str):
-            r = dateutil.parser.parse(s)
+            r = date_parse(s)
         elif isinstance(s, (datetime.datetime, datetime.date)):
             r = s
         else:


Test patch: