Repository: google/pytype

Issue:
"AttributeError: module 'time' has no attribute 'clock'" when running pytype in Python 3.8
I'm trying to run pytype on Python 3.8, with Python 3.7 target code (`-V 3.7`), and encounter the following error:

```
$  pytype --config ./setup.cfg -V 3.7 ./*.py ./gramhopper ./tests
Computing dependencies
Analyzing 44 sources with 0 local dependencies
ninja: Entering directory `/code/python/gramhopper/.pytype'
[1/44] check gramhopper.gramhopper.responses.response_helper
FAILED: /code/python/gramhopper/.pytype/pyi/gramhopper/gramhopper/responses/response_helper.pyi 
pytype-single --disable wrong-keyword-args --imports_info /code/python/gramhopper/.pytype/imports/gramhopper.gramhopper.responses.response_helper.imports --module-name gramhopper.gramhopper.responses.response_helper -V 3.7 -o /code/python/gramhopper/.pytype/pyi/gramhopper/gramhopper/responses/response_helper.pyi --analyze-annotated --nofail --quick /code/python/gramhopper/gramhopper/responses/response_helper.py
Traceback (most recent call last):
  File "/opt/anaconda3/envs/gh_2019_12_03-2/bin/pytype-single", line 8, in <module>
    sys.exit(main())
  File "/opt/anaconda3/envs/gh_2019_12_03-2/lib/python3.8/site-packages/pytype/main.py", line 86, in main
    with metrics.StopWatch("total_time"):
  File "/opt/anaconda3/envs/gh_2019_12_03-2/lib/python3.8/site-packages/pytype/metrics.py", line 154, in __enter__
    self._start_time = time.clock()
AttributeError: module 'time' has no attribute 'clock'
ninja: build stopped: subcommand failed.
```

Python version: 3.8.0
Pytype version: 2019.11.27

I'm aware to the fact that pytype does not yet support analyzing Python 3.8 code (#440), but not that this is an error when running pytype on Python 3.8, not analyzing Python 3.8 code.

This is caused by removing `time.clock()` function in Python 3.8, as warned [here](https://docs.python.org/3.7/library/time.html#time.clock): `Deprecated since version 3.3, will be removed in version 3.8: The behaviour of this function depends on the platform: use perf_counter() or process_time() instead, depending on your requirements, to have a well defined behaviour.`
Fixed AttributeError in Python 3.8 (#466)
This PR fixed and seems to be close #466.


Discussion:
Hmm, I don't think we've tried running pytype under 3.8 yet. Good to know that this needs fixing - thanks!
When runing pytype in python3.8 I get error:

```
Python versions > 3.7 are not yet supported.
```
> When runing pytype in python3.8 I get error:
> 
> ```
> Python versions > 3.7 are not yet supported.
> ```

This error is raised when trying to run pytype with a 3.8 target code. This issue is about what occurs when running pytype with a 3.7 target code, but on Python 3.8.

Thanks for your pull request. It looks like this may be your first contribution to a Google open source project (if not, look below for help). Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

:memo: **Please visit <https://cla.developers.google.com/> to sign.**

Once you've signed (or fixed any issues), please reply here with `@googlebot I signed it!` and we'll verify it.

----

#### What to do if you already signed the CLA

##### Individual signers

*   It's possible we don't have your GitHub username or you're using a different email address on your commit. Check [your existing CLA data](https://cla.developers.google.com/clas) and verify that your [email is set on your git commits](https://help.github.com/articles/setting-your-email-in-git/).

##### Corporate signers

*   Your company has a Point of Contact who decides which employees are authorized to participate. Ask your POC to be added to the group of authorized contributors. If you don't know who your Point of Contact is, direct the Google project maintainer to [go/cla#troubleshoot](http://go/cla#troubleshoot) ([Public version](https://opensource.google/docs/cla/#troubleshoot)).
*   The email used to register you as an authorized contributor must be the email used for the Git commit. Check [your existing CLA data](https://cla.developers.google.com/clas) and verify that your [email is set on your git commits](https://help.github.com/articles/setting-your-email-in-git/).
*   The email used to register you as an authorized contributor must also be [attached to your GitHub account](https://github.com/settings/emails).
		

ℹ️ **Googlers: [Go here](https://goto.google.com/prinfo/https%3A%2F%2Fgithub.com%2Fgoogle%2Fpytype%2Fpull%2F471) for more info**.

<!-- need_sender_cla -->
@googlebot I signed it!
CLAs look good, thanks!

ℹ️ **Googlers: [Go here](https://goto.google.com/prinfo/https%3A%2F%2Fgithub.com%2Fgoogle%2Fpytype%2Fpull%2F471) for more info**.

<!-- ok -->
thanks for the fix! we'll merge this internally and reexport to github (your name will still be on the commit)

Resolving patch:
diff --git a/pytype/metrics.py b/pytype/metrics.py
--- a/pytype/metrics.py
+++ b/pytype/metrics.py
@@ -20,6 +20,7 @@ def bar(n):
 
 import math
 import re
+import sys
 import time
 
 import yaml
@@ -57,6 +58,17 @@ def _prepare_for_test(enabled=True):
   _enabled = enabled
 
 
+def get_cpu_clock():
+  """Returns CPU clock to keep compatibilty with various Python versions."""
+  # https://github.com/google/pytype/issues/473: pytype doesn't recognize
+  # version_info tuple comparisons.
+  if sys.version_info >= (3, 3):
+    return time.process_time()  # pytype: disable=module-attr
+
+  # time.clock() is deprecated since Python 3.3 and removed in Python 3.8.
+  return time.clock()
+
+
 def get_metric(name, constructor, *args, **kwargs):
   """Return an existing metric or create a new one for the given name.
 
@@ -151,10 +163,10 @@ class StopWatch(Metric):
   """A counter that measures the time spent in a "with" statement."""
 
   def __enter__(self):
-    self._start_time = time.clock()
+    self._start_time = get_cpu_clock()
 
   def __exit__(self, exc_type, exc_value, traceback):
-    self._total = time.clock() - self._start_time
+    self._total = get_cpu_clock() - self._start_time
     del self._start_time
 
   def _summary(self):
@@ -175,13 +187,13 @@ def __init__(self, name):
 
   def __enter__(self):
     if not self._calls:
-      self._start_time = time.clock()
+      self._start_time = get_cpu_clock()
     self._calls += 1
 
   def __exit__(self, exc_type, exc_value, traceback):
     self._calls -= 1
     if not self._calls:
-      self._time += time.clock() - self._start_time
+      self._time += get_cpu_clock() - self._start_time
       del self._start_time
 
   def _merge(self, other):
diff --git a/pytype/pytd/parse/node.py b/pytype/pytd/parse/node.py
--- a/pytype/pytd/parse/node.py
+++ b/pytype/pytd/parse/node.py
@@ -61,7 +61,6 @@ def VisitData(self, node):
 """
 
 import collections
-import time
 
 from pytype import metrics
 from pytype.pytd.parse import preconditions
@@ -237,13 +236,13 @@ def _Visit(node, visitor, *args, **kwargs):
   recursive = name in _visiting
   _visiting.add(name)
 
-  start = time.clock()
+  start = metrics.get_cpu_clock()
   try:
     return _VisitNode(node, visitor, *args, **kwargs)
   finally:
     if not recursive:
       _visiting.remove(name)
-      elapsed = time.clock() - start
+      elapsed = metrics.get_cpu_clock() - start
       metrics.get_metric("visit_" + name, metrics.Distribution).add(elapsed)
       if _visiting:
         metrics.get_metric(


Test patch: