{"action":"created","comment":{"url":"https://api.github.com/repos/edx/edx-platform/pulls/comments/37312607","id":37312607,"diff_hunk":"@@ -1,144 +1,203 @@\n \"\"\"\n-Get call stacks of Model Class\n-in three cases-\n-1. QuerySet API\n-2. save()\n-3. delete()\n-\n-classes:\n-CallStackManager -  stores all stacks in global dictionary and logs\n-CallStackMixin - used for Model save(), and delete() method\n-\n-Functions:\n-capture_call_stack - global function used to store call stack\n-\n-Decorators:\n-donottrack - mainly for the places where we know the calls. This decorator will let us not to track in specified cases\n-\n-How to use-\n-1. Import following in the file where class to be tracked resides\n-    from openedx.core.djangoapps.call_stack_manager import CallStackManager, CallStackMixin\n-2. Override objects of default manager by writing following in any model class which you want to track-\n-    objects = CallStackManager()\n-3. For tracking Save and Delete events-\n-    Use mixin called \"CallStackMixin\"\n-    For ex.\n-        class StudentModule(CallStackMixin, models.Model):\n-4. Decorator is a parameterized decorator with class name/s as argument\n-    How to use -\n-    1. Import following\n-        import from openedx.core.djangoapps.call_stack_manager import donottrack\n \"\"\"\n \n import logging\n import traceback\n import re\n import collections\n+import wrapt\n+import types\n+import inspect\n from django.db.models import Manager\n \n log = logging.getLogger(__name__)\n \n-# list of regular expressions acting as filters\n+# List of regular expressions acting as filters\n REGULAR_EXPS = [re.compile(x) for x in ['^.*python2.7.*$', '^.*<exec_function>.*$', '^.*exec_code_object.*$',\n                                         '^.*edxapp/src.*$', '^.*call_stack_manager.*$']]\n-# Variable which decides whether to track calls in the function or not. Do it by default.\n+\n+# Flag which decides whether to track calls in the function or not. Default True.\n TRACK_FLAG = True\n \n-# List keeping track of Model classes not be tracked for special cases\n-# usually cases where we know that the function is calling Model classes.\n+# List keeping track of entities not to be tracked\n HALT_TRACKING = []\n \n-# Module Level variables\n-# dictionary which stores call stacks.\n-# { \"ModelClasses\" : [ListOfFrames]}\n+#  Dictionary which stores call logs\n+# {'EntityName' : [ListOfFrames]}\n # Frames - ('FilePath','LineNumber','Context')\n-# ex. {\"<class 'courseware.models.StudentModule'>\" : [[(file,line number,context),(---,---,---)],\n-#                                                    [(file,line number,context),(---,---,---)]]}\n+# ex. {\"<class 'courseware.models.StudentModule'>\" : [[(file, line number, function name, context),(---,---,---)],\n+#                                                    [(file, line number, function name, context),(---,---,---)]]}\n STACK_BOOK = collections.defaultdict(list)\n \n \n-def capture_call_stack(current_model):\n-    \"\"\" logs customised call stacks in global dictionary `STACK_BOOK`, and logs it.\n+def capture_call_stack(entity_name):\n+    \"\"\" Logs customised call stacks in global dictionary STACK_BOOK and logs it.\n+\n+    Arguments:\n+        entity_name - entity\n \n-    Args:\n-        current_model - Name of the model class\n     \"\"\"\n-    # holds temporary callstack\n-    # frame[0][6:-1] -> File name along with path\n-    # frame[1][6:] -> Line Number\n-    # frame[2][3:] -> Context\n-    temp_call_stack = [(frame[0][6:-1],\n-                        frame[1][6:],\n-                        frame[2][3:])\n-                       for frame in [stack.replace(\"\\n\", \"\").strip().split(',') for stack in traceback.format_stack()]\n+    # Holds temporary callstack\n+    # List with each element 4-tuple(filename, line number, function name, text)\n+    # and filtered with respect to regular expressions\n+    temp_call_stack = [(frame[0],\n+                        frame[1],\n+                        frame[2],\n+                        frame[3])\n+                       for frame in [frames for frames in traceback.extract_stack()]\n                        if not any(reg.match(frame[0]) for reg in REGULAR_EXPS)]\n \n-    # avoid duplication.\n-    if temp_call_stack not in STACK_BOOK[current_model] and TRACK_FLAG \\\n-            and not issubclass(current_model, tuple(HALT_TRACKING)):\n-        STACK_BOOK[current_model].append(temp_call_stack)\n-        log.info(\"logging new call stack for %s:\\n %s\", current_model, temp_call_stack)\n+    def _print(frame):\n+        return str('\\n File ' + str(frame[0]) + ', line number ' + str(frame[1]) + ', in ' +\n+                   str(frame[2]) + '\\n\\t' + str(frame[3]))\n+\n+    # Customize output of call stack\n+    final_call_stack = \"\"\n+    for frame in temp_call_stack:\n+        final_call_stack += _print(frame)\n+\n+    def _should_get_logged(entity_name):\n+        if not HALT_TRACKING:\n+            if TRACK_FLAG and temp_call_stack not in STACK_BOOK[entity_name]:  # TRACK_FLAG False iff @donottrack\n+                return True\n+            else:\n+                return False\n+        else:\n+            if inspect.isclass(entity_name):\n+                if temp_call_stack not in STACK_BOOK[entity_name] and not issubclass(entity_name, tuple(HALT_TRACKING[-1])):\n+                    return True\n+                else:\n+                    return False\n+            else:  # Assumption : Everything other than \"class\" will be passed as string\n+                if temp_call_stack not in STACK_BOOK[entity_name] and entity_name not in tuple(HALT_TRACKING[-1]):\n+                    return True\n+                else:\n+                    return False\n+\n+    if _should_get_logged(entity_name):\n+        STACK_BOOK[entity_name].append(temp_call_stack)","path":"openedx/core/djangoapps/call_stack_manager/core.py","position":178,"original_position":133,"commit_id":"2a4bb60df48a167ef29f0e0eae00ca2fae6bc22c","original_commit_id":"573095e1366de7baca1516ece2a2c5ba075ecef1","user":{"login":"cpennington","id":30236,"avatar_url":"https://avatars.githubusercontent.com/u/30236?v=3","gravatar_id":"","url":"https://api.github.com/users/cpennington","html_url":"https://github.com/cpennington","followers_url":"https://api.github.com/users/cpennington/followers","following_url":"https://api.github.com/users/cpennington/following{/other_user}","gists_url":"https://api.github.com/users/cpennington/gists{/gist_id}","starred_url":"https://api.github.com/users/cpennington/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cpennington/subscriptions","organizations_url":"https://api.github.com/users/cpennington/orgs","repos_url":"https://api.github.com/users/cpennington/repos","events_url":"https://api.github.com/users/cpennington/events{/privacy}","received_events_url":"https://api.github.com/users/cpennington/received_events","type":"User","site_admin":false},"body":"Did you push this change?","created_at":"2015-08-18T15:29:33Z","updated_at":"2015-08-18T15:29:33Z","html_url":"https://github.com/edx/edx-platform/pull/8835#discussion_r37312607","pull_request_url":"https://api.github.com/repos/edx/edx-platform/pulls/8835","_links":{"self":{"href":"https://api.github.com/repos/edx/edx-platform/pulls/comments/37312607"},"html":{"href":"https://github.com/edx/edx-platform/pull/8835#discussion_r37312607"},"pull_request":{"href":"https://api.github.com/repos/edx/edx-platform/pulls/8835"}}},"pull_request":{"url":"https://api.github.com/repos/edx/edx-platform/pulls/8835","id":39509982,"html_url":"https://github.com/edx/edx-platform/pull/8835","diff_url":"https://github.com/edx/edx-platform/pull/8835.diff","patch_url":"https://github.com/edx/edx-platform/pull/8835.patch","issue_url":"https://api.github.com/repos/edx/edx-platform/issues/8835","number":8835,"state":"open","locked":false,"title":"WIP:Making Call Stack Manager work in StudentModule and StudentModuleHistory","user":{"login":"utkjad","id":5477150,"avatar_url":"https://avatars.githubusercontent.com/u/5477150?v=3","gravatar_id":"","url":"https://api.github.com/users/utkjad","html_url":"https://github.com/utkjad","followers_url":"https://api.github.com/users/utkjad/followers","following_url":"https://api.github.com/users/utkjad/following{/other_user}","gists_url":"https://api.github.com/users/utkjad/gists{/gist_id}","starred_url":"https://api.github.com/users/utkjad/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/utkjad/subscriptions","organizations_url":"https://api.github.com/users/utkjad/orgs","repos_url":"https://api.github.com/users/utkjad/repos","events_url":"https://api.github.com/users/utkjad/events{/privacy}","received_events_url":"https://api.github.com/users/utkjad/received_events","type":"User","site_admin":false},"body":"This PR mainly enhances functionality of call stack manager in following ways \r\n- [x] Make call stack manager work in CSM(Courseware Student Module)\r\n- [x] Add unit test for decorating parameterized function with `@donottrack`\r\n- [x] Add new requirement of `wrapt` (as a result of conflict between `@contract` and any parameterized decorator such as `@donotrack()`)\r\n- [x]  Add new `trackit` + unit test for the same\r\n- [x]  Fix bug for HALT_TRACKING \r\n- [x]  Stack implementation of HALT_TRACKING\r\n- [x] Customize output of stacks\r\n- [ ] Method which gives unique call-stacks for any particular entity\r\n- [x] Add number to each call stack ex. ~ Logging call stack number 48 ~\r\n\r\nUPDATE: \r\n- [x] BUG - Make sure that `ChunkingCallStackManager` does not get logged. Logging calls of this `class` is undesirable\r\n\r\nUPDATE\r\n- [x]  Add unit test for generator using `yield`\r\n- [ ]  Django 1.7 Future Notes?\r\n- [x] `issubclass` works with `class` only. Extend function for functions/methods.\r\n- [x] tests working individually but not as a whole suite -----> Solved the bug\r\n\r\n@doctoryes @alawibaba @cpennington @macdiesel\r\n\r\nRelated previous closed PR - https://github.com/edx/edx-platform/pull/8722","created_at":"2015-07-08T18:49:11Z","updated_at":"2015-08-18T15:29:33Z","closed_at":null,"merged_at":null,"merge_commit_sha":"1ebb8c5267694d33952e6c4f3f70300282346a78","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/edx/edx-platform/pulls/8835/commits","review_comments_url":"https://api.github.com/repos/edx/edx-platform/pulls/8835/comments","review_comment_url":"https://api.github.com/repos/edx/edx-platform/pulls/comments{/number}","comments_url":"https://api.github.com/repos/edx/edx-platform/issues/8835/comments","statuses_url":"https://api.github.com/repos/edx/edx-platform/statuses/2a4bb60df48a167ef29f0e0eae00ca2fae6bc22c","head":{"label":"edx:utkjad/injecting_callstackmanager","ref":"utkjad/injecting_callstackmanager","sha":"2a4bb60df48a167ef29f0e0eae00ca2fae6bc22c","user":{"login":"edx","id":3179841,"avatar_url":"https://avatars.githubusercontent.com/u/3179841?v=3","gravatar_id":"","url":"https://api.github.com/users/edx","html_url":"https://github.com/edx","followers_url":"https://api.github.com/users/edx/followers","following_url":"https://api.github.com/users/edx/following{/other_user}","gists_url":"https://api.github.com/users/edx/gists{/gist_id}","starred_url":"https://api.github.com/users/edx/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/edx/subscriptions","organizations_url":"https://api.github.com/users/edx/orgs","repos_url":"https://api.github.com/users/edx/repos","events_url":"https://api.github.com/users/edx/events{/privacy}","received_events_url":"https://api.github.com/users/edx/received_events","type":"Organization","site_admin":false},"repo":{"id":10391073,"name":"edx-platform","full_name":"edx/edx-platform","owner":{"login":"edx","id":3179841,"avatar_url":"https://avatars.githubusercontent.com/u/3179841?v=3","gravatar_id":"","url":"https://api.github.com/users/edx","html_url":"https://github.com/edx","followers_url":"https://api.github.com/users/edx/followers","following_url":"https://api.github.com/users/edx/following{/other_user}","gists_url":"https://api.github.com/users/edx/gists{/gist_id}","starred_url":"https://api.github.com/users/edx/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/edx/subscriptions","organizations_url":"https://api.github.com/users/edx/orgs","repos_url":"https://api.github.com/users/edx/repos","events_url":"https://api.github.com/users/edx/events{/privacy}","received_events_url":"https://api.github.com/users/edx/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/edx/edx-platform","description":"The Open edX platform, the software that powers edX!","fork":false,"url":"https://api.github.com/repos/edx/edx-platform","forks_url":"https://api.github.com/repos/edx/edx-platform/forks","keys_url":"https://api.github.com/repos/edx/edx-platform/keys{/key_id}","collaborators_url":"https://api.github.com/repos/edx/edx-platform/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/edx/edx-platform/teams","hooks_url":"https://api.github.com/repos/edx/edx-platform/hooks","issue_events_url":"https://api.github.com/repos/edx/edx-platform/issues/events{/number}","events_url":"https://api.github.com/repos/edx/edx-platform/events","assignees_url":"https://api.github.com/repos/edx/edx-platform/assignees{/user}","branches_url":"https://api.github.com/repos/edx/edx-platform/branches{/branch}","tags_url":"https://api.github.com/repos/edx/edx-platform/tags","blobs_url":"https://api.github.com/repos/edx/edx-platform/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/edx/edx-platform/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/edx/edx-platform/git/refs{/sha}","trees_url":"https://api.github.com/repos/edx/edx-platform/git/trees{/sha}","statuses_url":"https://api.github.com/repos/edx/edx-platform/statuses/{sha}","languages_url":"https://api.github.com/repos/edx/edx-platform/languages","stargazers_url":"https://api.github.com/repos/edx/edx-platform/stargazers","contributors_url":"https://api.github.com/repos/edx/edx-platform/contributors","subscribers_url":"https://api.github.com/repos/edx/edx-platform/subscribers","subscription_url":"https://api.github.com/repos/edx/edx-platform/subscription","commits_url":"https://api.github.com/repos/edx/edx-platform/commits{/sha}","git_commits_url":"https://api.github.com/repos/edx/edx-platform/git/commits{/sha}","comments_url":"https://api.github.com/repos/edx/edx-platform/comments{/number}","issue_comment_url":"https://api.github.com/repos/edx/edx-platform/issues/comments{/number}","contents_url":"https://api.github.com/repos/edx/edx-platform/contents/{+path}","compare_url":"https://api.github.com/repos/edx/edx-platform/compare/{base}...{head}","merges_url":"https://api.github.com/repos/edx/edx-platform/merges","archive_url":"https://api.github.com/repos/edx/edx-platform/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/edx/edx-platform/downloads","issues_url":"https://api.github.com/repos/edx/edx-platform/issues{/number}","pulls_url":"https://api.github.com/repos/edx/edx-platform/pulls{/number}","milestones_url":"https://api.github.com/repos/edx/edx-platform/milestones{/number}","notifications_url":"https://api.github.com/repos/edx/edx-platform/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/edx/edx-platform/labels{/name}","releases_url":"https://api.github.com/repos/edx/edx-platform/releases{/id}","created_at":"2013-05-30T20:20:38Z","updated_at":"2015-08-18T09:13:10Z","pushed_at":"2015-08-18T15:22:40Z","git_url":"git://github.com/edx/edx-platform.git","ssh_url":"git@github.com:edx/edx-platform.git","clone_url":"https://github.com/edx/edx-platform.git","svn_url":"https://github.com/edx/edx-platform","homepage":"http://open.edx.org/","size":2089653,"stargazers_count":2076,"watchers_count":2076,"language":"Python","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":1224,"mirror_url":null,"open_issues_count":134,"forks":1224,"open_issues":134,"watchers":2076,"default_branch":"master"}},"base":{"label":"edx:master","ref":"master","sha":"13ef9a62d1d0097e26c58dd02de07f3553c1767c","user":{"login":"edx","id":3179841,"avatar_url":"https://avatars.githubusercontent.com/u/3179841?v=3","gravatar_id":"","url":"https://api.github.com/users/edx","html_url":"https://github.com/edx","followers_url":"https://api.github.com/users/edx/followers","following_url":"https://api.github.com/users/edx/following{/other_user}","gists_url":"https://api.github.com/users/edx/gists{/gist_id}","starred_url":"https://api.github.com/users/edx/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/edx/subscriptions","organizations_url":"https://api.github.com/users/edx/orgs","repos_url":"https://api.github.com/users/edx/repos","events_url":"https://api.github.com/users/edx/events{/privacy}","received_events_url":"https://api.github.com/users/edx/received_events","type":"Organization","site_admin":false},"repo":{"id":10391073,"name":"edx-platform","full_name":"edx/edx-platform","owner":{"login":"edx","id":3179841,"avatar_url":"https://avatars.githubusercontent.com/u/3179841?v=3","gravatar_id":"","url":"https://api.github.com/users/edx","html_url":"https://github.com/edx","followers_url":"https://api.github.com/users/edx/followers","following_url":"https://api.github.com/users/edx/following{/other_user}","gists_url":"https://api.github.com/users/edx/gists{/gist_id}","starred_url":"https://api.github.com/users/edx/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/edx/subscriptions","organizations_url":"https://api.github.com/users/edx/orgs","repos_url":"https://api.github.com/users/edx/repos","events_url":"https://api.github.com/users/edx/events{/privacy}","received_events_url":"https://api.github.com/users/edx/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/edx/edx-platform","description":"The Open edX platform, the software that powers edX!","fork":false,"url":"https://api.github.com/repos/edx/edx-platform","forks_url":"https://api.github.com/repos/edx/edx-platform/forks","keys_url":"https://api.github.com/repos/edx/edx-platform/keys{/key_id}","collaborators_url":"https://api.github.com/repos/edx/edx-platform/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/edx/edx-platform/teams","hooks_url":"https://api.github.com/repos/edx/edx-platform/hooks","issue_events_url":"https://api.github.com/repos/edx/edx-platform/issues/events{/number}","events_url":"https://api.github.com/repos/edx/edx-platform/events","assignees_url":"https://api.github.com/repos/edx/edx-platform/assignees{/user}","branches_url":"https://api.github.com/repos/edx/edx-platform/branches{/branch}","tags_url":"https://api.github.com/repos/edx/edx-platform/tags","blobs_url":"https://api.github.com/repos/edx/edx-platform/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/edx/edx-platform/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/edx/edx-platform/git/refs{/sha}","trees_url":"https://api.github.com/repos/edx/edx-platform/git/trees{/sha}","statuses_url":"https://api.github.com/repos/edx/edx-platform/statuses/{sha}","languages_url":"https://api.github.com/repos/edx/edx-platform/languages","stargazers_url":"https://api.github.com/repos/edx/edx-platform/stargazers","contributors_url":"https://api.github.com/repos/edx/edx-platform/contributors","subscribers_url":"https://api.github.com/repos/edx/edx-platform/subscribers","subscription_url":"https://api.github.com/repos/edx/edx-platform/subscription","commits_url":"https://api.github.com/repos/edx/edx-platform/commits{/sha}","git_commits_url":"https://api.github.com/repos/edx/edx-platform/git/commits{/sha}","comments_url":"https://api.github.com/repos/edx/edx-platform/comments{/number}","issue_comment_url":"https://api.github.com/repos/edx/edx-platform/issues/comments{/number}","contents_url":"https://api.github.com/repos/edx/edx-platform/contents/{+path}","compare_url":"https://api.github.com/repos/edx/edx-platform/compare/{base}...{head}","merges_url":"https://api.github.com/repos/edx/edx-platform/merges","archive_url":"https://api.github.com/repos/edx/edx-platform/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/edx/edx-platform/downloads","issues_url":"https://api.github.com/repos/edx/edx-platform/issues{/number}","pulls_url":"https://api.github.com/repos/edx/edx-platform/pulls{/number}","milestones_url":"https://api.github.com/repos/edx/edx-platform/milestones{/number}","notifications_url":"https://api.github.com/repos/edx/edx-platform/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/edx/edx-platform/labels{/name}","releases_url":"https://api.github.com/repos/edx/edx-platform/releases{/id}","created_at":"2013-05-30T20:20:38Z","updated_at":"2015-08-18T09:13:10Z","pushed_at":"2015-08-18T15:22:40Z","git_url":"git://github.com/edx/edx-platform.git","ssh_url":"git@github.com:edx/edx-platform.git","clone_url":"https://github.com/edx/edx-platform.git","svn_url":"https://github.com/edx/edx-platform","homepage":"http://open.edx.org/","size":2089653,"stargazers_count":2076,"watchers_count":2076,"language":"Python","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":1224,"mirror_url":null,"open_issues_count":134,"forks":1224,"open_issues":134,"watchers":2076,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/edx/edx-platform/pulls/8835"},"html":{"href":"https://github.com/edx/edx-platform/pull/8835"},"issue":{"href":"https://api.github.com/repos/edx/edx-platform/issues/8835"},"comments":{"href":"https://api.github.com/repos/edx/edx-platform/issues/8835/comments"},"review_comments":{"href":"https://api.github.com/repos/edx/edx-platform/pulls/8835/comments"},"review_comment":{"href":"https://api.github.com/repos/edx/edx-platform/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/edx/edx-platform/pulls/8835/commits"},"statuses":{"href":"https://api.github.com/repos/edx/edx-platform/statuses/2a4bb60df48a167ef29f0e0eae00ca2fae6bc22c"}}}}