{"push_id":879713226,"size":129,"distinct_size":129,"ref":"refs/heads/feature-sharlikran-valda-fallout","head":"d38f884080632d95a86055000b38dc433bb32c86","before":"bd21ffa20b64f8c49e02a28ff3d493a97462ad4e","commits":[{"sha":"01e0b0b6cc1d8db0b543496aaa53cda3f82b9fe6","author":{"email":"4940bdc6f784780ad32bf9f03596977cf7f253eb@gmail.com","name":"MrD"},"message":"SHFileOperation WIP:\n\nSee discussion in:\nhttps://github.com/wrye-bash/wrye-bash/commit/c41779a3889b351834517568c346f9d13af152d0\nfor a useful script too (from:\nhttp://timgolden.me.uk/python/win32_how_do_i/copy-a-file.html)\n\nAs discussed aborted is most probably just a boolean, so no use\npassing it as SkipError.count.\n\nCorrected:\n\n-    120: AccessDeniedError,\n+    5   : AccessDeniedError,\n+    120 : CallNotImplementedError,\n\nbut left CallNotImplementedError in just in case\n\nStarted hashing up docs and made _DirectoryFileCollisionError private\nTODO(241): collisions handling on non shell path, tests (ideal module\nto start plugging some in - discuss in #104)\nDropped unused parameters from __copyOrMove (alpha)\n\nUnder #241.","distinct":true,"url":"https://api.github.com/repos/valda/wrye-bash/commits/01e0b0b6cc1d8db0b543496aaa53cda3f82b9fe6"},{"sha":"dacfb390bb804d0f589c9b0bd52b5210e7e93899","author":{"email":"4940bdc6f784780ad32bf9f03596977cf7f253eb@gmail.com","name":"MrD"},"message":"Deleted getUACIcon():\n\nUnder #173.\nWas unused and I want to have complete control over how non portable\nwindows only code is plugged into Bash.\nUnder #243 too.","distinct":true,"url":"https://api.github.com/repos/valda/wrye-bash/commits/dacfb390bb804d0f589c9b0bd52b5210e7e93899"},{"sha":"aa471e20263a79d4da7940d105f1244fca4b7825","author":{"email":"4940bdc6f784780ad32bf9f03596977cf7f253eb@gmail.com","name":"MrD"},"message":"Fix for _winreg not being available on linux:\n\nEven with the import fix Bash would erroneously crash with\n\"No supported games found\" - so edting was needed in bush. I ended up\nimporting _winreg once - WIP:\n\nIn bass - bass is amongst others a showcase of problematic module\nbindings ;)\nRefactoring WIP\nIn bass cause it's used by bosh _and_ basher\n\nMopy/bash/bosh.py:\nThe registry is used in windows to get user paths - hacked up some code to\nthe same effect for linux and should add to the linux readmes (when) that\npeople better use cli arguments for those.\n\nMopy/bash/basher/links.py:\nwindows only code - yak - links.py is on its way to be split, but this\nbuttons stuff is in the way\n\nMopy/bash/windows.py: is not guarded with `if winreg` as it will be blocked\nin next commits in linux (btw this one causes the problems in WINE canVista\npath).","distinct":true,"url":"https://api.github.com/repos/valda/wrye-bash/commits/aa471e20263a79d4da7940d105f1244fca4b7825"},{"sha":"ab640cd822b0827796a22c5df4abdf2e8d60a952","author":{"email":"4940bdc6f784780ad32bf9f03596977cf7f253eb@gmail.com","name":"MrD"},"message":"Another path fix - there are more I'm sure:\n\nbash.bolt.BoltError: Error creating required Wrye Bash directories.  \\\nPlease check the settings for the following paths in your bash.ini, \\\nthe drive does not exist:\n\nA path error was the result of relative paths.  The following paths are \\\ncausing the errors, however usually a relative path should be fine.  \\\nCheck your setup to see if you are using symbolic links or NTFS Junctions:\n\n/mnt/win/GAMES/TESIV/Oblivion/..\\Oblivion Mods/Bash Mod Data\n/mnt/win/GAMES/TESIV/Oblivion/..\\Oblivion Mods","distinct":true,"url":"https://api.github.com/repos/valda/wrye-bash/commits/ab640cd822b0827796a22c5df4abdf2e8d60a952"},{"sha":"56f0731d3846c937821955672948a564bde2ae8b","author":{"email":"4940bdc6f784780ad32bf9f03596977cf7f253eb@gmail.com","name":"MrD"},"message":"win32gui:\n\nTODO: eliminate from links.py (env.py module)\nif win32gui: win32gui.... is not needed as if not there it will raise, just\nfor singling out the uses","distinct":true,"url":"https://api.github.com/repos/valda/wrye-bash/commits/56f0731d3846c937821955672948a564bde2ae8b"},{"sha":"a9751915e101bf0ba6261e66dce1ff5d640f3e5d","author":{"email":"4940bdc6f784780ad32bf9f03596977cf7f253eb@gmail.com","name":"MrD"},"message":"Getting MAX_PATH on linux:\n\nSee: http://stackoverflow.com/q/32807560/281545\nIt is not needed as anyway import win32gui will raise - but here for\nsymmetry ;)\n\n(And for the env.py module to be)","distinct":true,"url":"https://api.github.com/repos/valda/wrye-bash/commits/a9751915e101bf0ba6261e66dce1ff5d640f3e5d"},{"sha":"aa6fa73a712a8402daf1f704485f6fa17359de3d","author":{"email":"4940bdc6f784780ad32bf9f03596977cf7f253eb@gmail.com","name":"MrD"},"message":"Mopy/bash/windows.py weak warnings and newlines","distinct":true,"url":"https://api.github.com/repos/valda/wrye-bash/commits/aa6fa73a712a8402daf1f704485f6fa17359de3d"},{"sha":"3e356302f1f1b82d034e81466b33725026263318","author":{"email":"4940bdc6f784780ad32bf9f03596977cf7f253eb@gmail.com","name":"MrD"},"message":"Pythonizing:\n\nJust trying to figure out what's used when in hopes of pinning the wine\ndialogues bug\n- main icon should be passed in the constructor, as should footer\n- set_main_icon dropped as seems not useful after show()\n\nTODO: vistaDialog returns VARIABLE LENGTH - a nono !","distinct":true,"url":"https://api.github.com/repos/valda/wrye-bash/commits/3e356302f1f1b82d034e81466b33725026263318"},{"sha":"c2cd65b5dccfd526be007da85e9da2021ee8c09b","author":{"email":"4940bdc6f784780ad32bf9f03596977cf7f253eb@gmail.com","name":"MrD"},"message":"Merge branch 'utumno-243-fixups' into dev:\n\nAs discussed in #243 vistaDialog is here to stay - so this branch is an\neffort to at least centralize windows only imports and start cleaning up\nwindows py\n\n- windows.py is written in NP style (note for instance the builder\npattern in TaskDialog) that really does not help debugging. The need\nfor debugging arose due to #240 - apparently some component (?) of the\ndialog fails on wine. Pythonize and make it into a package -\nconstants.py, structures.py (comtypes imports) and task_dialog.py.\n- I am tempted to bin all the TaskDialog API that's not used by Bash -\nmay do if the wine bug keeps eluding me.\n- _winreg (note the _) we were importing is used to query registry for\nsupported games, user paths and app buttons (...). Moved to bass and\nfrom there must be moved to a cross platform module for getting\nenvironment parameters (say 'env.py').\n\nA nice old _negative lines count_ refactoring merge.","distinct":true,"url":"https://api.github.com/repos/valda/wrye-bash/commits/c2cd65b5dccfd526be007da85e9da2021ee8c09b"},{"sha":"b40b1a10ff414dd41dd412c8484ca253e42ca92c","author":{"email":"4940bdc6f784780ad32bf9f03596977cf7f253eb@gmail.com","name":"MrD"},"message":"Fix for sticky installers tab on first run:\n\nUnder #197.\n\nAdding some debug prints and unbinding the event I got the error but the\nTabDragMixin.__OnDragEndForced handle run - so why it said I did not\nprocess the event ?\n\n------------------------------ Mopy/bash/balt.py ------------------------------\nindex 6da29c7..e03f4e9 100644\n@@ -1378,4 +1378,9 @@ def __OnDragStart(self, event):\n     def __OnDragEndForced(self, event):\n-        self.__dragging = wx.NOT_FOUND\n+        if self.__dragging != wx.NOT_FOUND:\n             self.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))\n+            self.__dragging = wx.NOT_FOUND\n+            try:\n+                self.ReleaseMouse()\n+            except:\n+                deprint('MCL:' + repr(self), traceback=True)\n         event.Skip()\n@@ -1389,3 +1394,3 @@ def __OnDragEnd(self, event):\n             except:\n-                pass\n+                deprint('Left Up:', traceback=True)\n         event.Skip()\n\n------------------------- Mopy/bash/basher/__init__.py -------------------------\nindex 55eca86..54a195d 100644\n@@ -3601,3 +3601,2 @@ def __init__(self, parent):\n         wx.Notebook.__init__(self, parent)\n-        balt.TabDragMixin.__init__(self)\n         #--Pages\n@@ -3641,3 +3640,4 @@ def __init__(self, parent):\n         self.Bind(wx.EVT_CONTEXT_MENU, self.DoTabMenu)\n-        self.Bind(wx.EVT_MOUSE_CAPTURE_LOST, self._onMouseCaptureLost)\n+        # self.Bind(wx.EVT_MOUSE_CAPTURE_LOST, self._onMouseCaptureLost)\n+        balt.TabDragMixin.__init__(self)\n\n@@ -3696,4 +3696,22 @@ def _onMouseCaptureLost(self, event):\n         Currently does nothing, but is necessary because without it the first run dialog in OnShow will throw an exception.\n+\n+        The error reads (line 656 does not seem able to throw - windows.py):\n+\n+bash\\windows.py:656: RuntimeWarning: tp_compare didn't return -1 or -2 for exception\n+  if notification == CREATED:\n+Traceback (most recent call last):\n+  File \"_ctypes/callbacks.c\", line 314, in 'calling callback function'\n+  File \"bash\\windows.py\", line 656, in __callback\n+    if notification == CREATED:\n+wx._core.PyAssertionError: C++ assertion \"wxAssertFailure\" failed at ..\\..\\src\\common\\wincmn.cpp(2571) in DoNotifyWindowAboutCaptureLost(): window that captured the mouse didn't process wxEVT_MOUSE_CAPTURE_LOST\n+\n+TabDragMixin _does_ process the event but has _not_ captured the mouse:\n+Traceback (most recent call last):\n+  File \"bash\\balt.py\", line 1383, in __OnDragEndForced\n+    self.ReleaseMouse()\n+  File \"C:\\_\\Python27\\lib\\site-packages\\wx-2.8-msw-unicode\\wx\\_core.py\", line 9744, in ReleaseMouse\n+    return _core_.Window_ReleaseMouse(*args, **kwargs)\n+PyAssertionError: C++ assertion \"GetCapture() == this\" failed at ..\\..\\src\\common\\wincmn.cpp(2536) in wxWindowBase::ReleaseMouse(): attempt to release mouse, but this window hasn't captured it\n         \"\"\"\n-        pass\n+        print repr(self)\n\nTurns out \"process\" meant stop propagating (that is just drop\n`event.Skip()`).\nNotice before I had to move the TabDragMixin init after the bind to have the\nmouse unstick from the installers tab\n\nFinal fix as seen in the commit - yey\n\nBonus - one `except: pass` less -> can't seem to catch PyAssertionError -\nbtw, _assertion error_ just cause I haven't handled the mouse capture\nlost ?!\n\nSigned-off-by: MrD <the.ubik@gmail.com>","distinct":true,"url":"https://api.github.com/repos/valda/wrye-bash/commits/b40b1a10ff414dd41dd412c8484ca253e42ca92c"},{"sha":"491dc027e08de6ae9d311f816ee605fb087289a9","author":{"email":"4940bdc6f784780ad32bf9f03596977cf7f253eb@gmail.com","name":"MrD"},"message":"Bump Bash version to 307","distinct":true,"url":"https://api.github.com/repos/valda/wrye-bash/commits/491dc027e08de6ae9d311f816ee605fb087289a9"},{"sha":"7018ed19cdf74fa3634181f9612874023563b829","author":{"email":"4940bdc6f784780ad32bf9f03596977cf7f253eb@gmail.com","name":"MrD"},"message":"General and advanced readme updates from forums:\n\nRemoved references to the outdated Wrye Python package from the install\nsection (linked to in our frontpage).\n\nAdded the explanation on merging plugins from @lojack5:\nhttp://forums.bethsoft.com/topic/1536340-wrye-bash-thread-105/?p=24340858\n\nRewrote \"Add Masters\" description based on explanation by @Arthmoor\nhere:\nhttp://forums.bethsoft.com/topic/1536340-wrye-bash-thread-105/page-3#entry24345148\nand the warning text Bash displays\nThis was triggered by the strange mergeability behavior reported by\n@Supierce:\nhttp://forums.bethsoft.com/topic/1536340-wrye-bash-thread-105/page-3#entry24344854\n\nAuto ghost updates suggested by @alt3rn1ty in:\nhttp://forums.bethsoft.com/topic/1536340-wrye-bash-thread-105/?p=24354404\nand\nhttp://forums.bethsoft.com/topic/1536340-wrye-bash-thread-105/?p=24359158","distinct":true,"url":"https://api.github.com/repos/valda/wrye-bash/commits/7018ed19cdf74fa3634181f9612874023563b829"},{"sha":"cac8abc27b628e3b5f41d3c555caf7efd88b5368","author":{"email":"4940bdc6f784780ad32bf9f03596977cf7f253eb@gmail.com","name":"MrD"},"message":"Readmes - some typos","distinct":true,"url":"https://api.github.com/repos/valda/wrye-bash/commits/cac8abc27b628e3b5f41d3c555caf7efd88b5368"},{"sha":"88224eb34140344b39ea3c53e55d815438e01c50","author":{"email":"4940bdc6f784780ad32bf9f03596977cf7f253eb@gmail.com","name":"MrD"},"message":"Advanced readme: Change screenshots directory by @Supierce:\n\nTemp closes #246","distinct":true,"url":"https://api.github.com/repos/valda/wrye-bash/commits/88224eb34140344b39ea3c53e55d815438e01c50"},{"sha":"9d1430926cd03c0e0917fe1b821d6607d71f8976","author":{"email":"4940bdc6f784780ad32bf9f03596977cf7f253eb@gmail.com","name":"MrD"},"message":"Readme.md update","distinct":true,"url":"https://api.github.com/repos/valda/wrye-bash/commits/9d1430926cd03c0e0917fe1b821d6607d71f8976"},{"sha":"f92076aa0260d9521fb82a18b9775875f927b959","author":{"email":"4940bdc6f784780ad32bf9f03596977cf7f253eb@gmail.com","name":"MrD"},"message":"Version History.html","distinct":true,"url":"https://api.github.com/repos/valda/wrye-bash/commits/f92076aa0260d9521fb82a18b9775875f927b959"},{"sha":"9f02e3ef2bd0b718cf2cb8224028d364f3cfa526","author":{"email":"4940bdc6f784780ad32bf9f03596977cf7f253eb@gmail.com","name":"MrD"},"message":"Merge branch 'rel-306' into dev:\n\nThis release features an almost complete refactoring of the codebase,\nfixing many bugs and opening the way to extend Bash functionality.\nBash, being a community work, has over the years become an\nassortment of hacks, patches and cruft and the program was just about to\nbecome non-operable. Example issues - in no particular order (although\nprobably the worst was the horrible performance):\n\n- deleting an item in the lists displayed by Bash ran different code\ndepending on whether the user hit delete or right clicked and chose\ndelete - most of those pieces of code were buggy\n- start up took more than 15 seconds on large Oblivion Load Orders and\nalt tabbing out and back into Bash would take 6-7 seconds - last one\nshould take no time in the usual case\n- as seen from the (user visible) debug prints the game detection\nalgorithm run 3-5 times\n- many, many broken things - including performance in general (most\nsimple operations would hang Bash for some seconds), display glitches\nand general UI inconsistencies and internal data structures corruption\n(see #176)\n\nThose bugs reflected the state of the code - again in no particular\norder:\n\n- bosh.py (the data model) in 305 was 24635 lines (reduced from\n30550 lines in 304.4 - see bosh section below)\n- basher.py (the UI lists/menus etc) was 18936 lines\n- the seven tabs that Bash featured were backed up by Tank (2) and List\n(5) instances - so implementing a feature (say delete) needed edits to\nat least two classes (usually 7)\n- the wx library was intermingled with the basher code - the menu items\n(Links) defined 215 AppendToMenu methods with nearly identical wx code\n- readability suffered - most attributes/variables were named `data` or\n`items`, globals hacks crippled the IDE static analysis, copy paste (aka\nravioli) code was everywhere.\n\nWhen I started in it I had no idea if refactoring the code was even\npossible, core Bash is 80k lines of code. It was clear that bosh needed\nsplitting, that candidate number one was the patchers code (well defined\nand functional) and that basher should follow - but was not at all\nclear if those were possible, let alone how exactly should the code be\nstructured and how much time would this take. Turns out that it was\npossible: Bash was indeed coded with modularity in mind (by Wrye ?)\nbut later additions bloated the initial modules beyond recognition\nand broke the (non enforced) encapsulation - however it wasn't too late.\nAlso turns out that refactoring needed 2 full work years of a single\nengineer (learning python).\n\nThe huge performance boost that this release features is the measurable\neffect of the increase in the code quality. In the items below I try to\ndescribe in a quantitative manner what \"code quality\" means and how it\nwas increased. That's meant to be read from an app that links to the\ncommits - both github and gitk do but additionally github links to the\nissues and files.\n\nThis release features splitting the patchers' code out of bosh\nto a dedicated package (whose final structure is still at stake). This\nreduced bosh to 10516 lines while naturally exposing class\ndependencies issues, hidden by the \"one file program\" nature of Bash.\nThe attempt to split bosh had already started in 305, involving:\n\n- an effort to eliminate code duplication in C and P patchers using\nmultiple inheritance (chopped off around 1500 lines of pure copy paste\ncode) - see commits in 3c40989669ab8ed318440d2faa82ab1d47edbce5\n- splitting out what was to become `record_groups.py` - see\nc3e354348909fbb9540a9e039560bcc8f717323e, but don't\nimitate it - lots has changed since then, including import conventions\nand commit style - for instance commits on dev that do not launch are\nstrictly forbidden.\n- splitting out what was to become `parsers.py` - see commits in\n08ab6e2baf632dab6308e50051ba1c33bd7edc52\n\nFinal (`record_groups.py`, `parsers.py`):\n6ae30fc058984bffa9c8de49fe52d9424dd4bd7f\n\nWith those out of the way it was finally possible to rip the patchers\nout of bosh - starting here:\n983f2596af8a70742b23dfa265f8b3f0968564f5\nThat was not a mere copy paste rip - warnings were squashed, long lines\nwere wrapped, and most importantly a lot of tricky refactoring was\napplied to eliminate code duplication - see for ex. commits in:\n72fc8a0d276cb6720268e5b617653680e6b8b482 for ripping\nand commits in (note the negative line count):\n5d2137787ccd87f29d03a7682a2d7d747221597b,\nfdab16396b3e1032d3c67e9626768b644efcd187,\n78a85e0f2dcbdf6a12d8e7b5b375adedc7b9e040 for refactoring\n\nSee #3 for commit links (finally closed in\nb6b743b83c37012cde7130d33423bf5e8c4f4a33) and #124 for the (still open)\npackage layout issue. Be aware that a lot of things changed since,\nincluding import style and the overall package layout - see:\ne6b2e0e90cfd16e105dbfd3ec1a2e9c49455c1ad\n\nThe remaining bosh.py code had some preliminary refactoring applied to\nit (archives handling, BAIN error handling and refresh etc - see\n6ddd4a8ac9e6954e6535e743ac8bf8ed01d9ce6a) but core bosh\nrefactoring will take place in 307. Major goals are splitting bosh into\na number of modules, getting rid of old style classes (DataDict\nhierarchy, that is the data store singletons) and refactoring settings\nto efficiently support profiles.\n\nThere are 544 occurrences of `.data` in 306 (1081 of `data`) as opposed\nto 1071 in 305 (2221 `data`) - baring string literals and comments\n(Pycharm only recently made these scopes available in IDE search, they\nwere much needed). Practically one had to run the debugger to see the\ntype of the object one had at hand, since the variable/attribute name\nwas always 'data':\n\n- data is the wrapped dictionary of `DataDict`. Most accesses to this\ndict were not via the wrappers the DataDict provides. This took\nmany commits to fix - ex\n56198be85d3e55cd07b0969354656a837b529174. Before even\n_thinking_ \"performance\" read the performance section below (no, none of\nthose modInfos.data.keys() calls was in the middle of a tight loop).\n- data also was an attribute of the Link hierarchy which had _different\nmeaning based on an isinstance check_:\n92e50cd0f4e74006b40d24facbeb7e608e25e00b. It could either mean a\nDataDict subclass (so in Links code there were `self.data.data`\naccesses) _or_ the list of selected items in the UI, leading to a\ncomplete chaos - see the commit above up till the final removal in\nffae59e77b17245a3409e0c0bb8a79e6f4f89966.\n- UIList subclasses have a `data` attribute that points to the\nDataDict singletons in bosh. That was dealt with throughout\ncoding 306 as it is closely related to a deeper issue namely the\nintermingling of UI and model/business logic code. This\nstems from the 'one file program' nature of Bash so solving this\nproperly means refactoring is at 100%.\n- to somehow improve readability I introduced idata and pdata\nattributes for the Installers and People data links -\neba53f93bea72445a9fdac56c82172baeb2ab837 - Those are transitory and\nmeant to also help in eliminating Tank.\nThe links of List subclasses were using self.window.data, whose uses\nI strived to encapsulate - random example:\n0934f1f8e2ecdba62614d94ef139a1287585c08e\n- all kind of different classes attributes were named `data`. Those\nrequired dedicated commits (hey, I couldn't just do a search and replace\nfor \"data\") - ex. 9839c47c6c9788ada85f2cfb033c0ccc8e7e2f85. An IDE\nreally helps here.\n- finally data local variables were renamed - ex.\n8e7728377ec9dc9b58448ab7320b9f8c06743fb5\n\nThe war with data was going on in parallel with smaller scale wars with\n`items` (e87dca7bad63e1b7fbe66ce36d32b65e6b1f9eb7 and its parents),\n`refresh` (4d872ab4fd53da6a8034852780dd1dc1ffe313b9), etc.\n\nThis is the part of refactoring that I consider almost done - and it was\na big pleasure coding it. Since I first tried coding for Bash the\ndichotomy between balt.Tank and basher.List clearly stood out as a major\nissue, as did the omnipresence of the wx library and of course the sheer\nsize of basher.py (the UI module).\nBasher became a package and then the UI API went through a complete\nrewrite. Basher globals served as a guide in the splitting process,\nand a metric of class dependencies. Eliminating those globals was an\nongoing effort throughout 306 coding - see for instance:\n892a19c25a38c5630e5fbaf50b0ed935c8f3b5be (screenlist, statusBar),\n5852328cc6a682107dc4f3e8bf34a9f9dfeeacc7 (gInstallers),\nfaea77112434ca2bc2591542339d9c7ad0aab2d5 (modList)\ntill final elimination in bab7c00953f0fea946983ceb211d850131e8a108\nGuest star: bosh.links (353be4379eb7c75a749e657079c1f86d6c1f1729)\nGlobals served as a link also between Bash's modules (so they evince\nclass and module coupling issues) - eventually encapsulated as static\nfields of the balt.Link.Frame singleton - see\n0690cf305e8a594b1d5690ca6ccce54596b62ad9\nLink.Frame is an interesting binding of the UI (basher) and the rest of\nbash that will serve as guide to a later refactoring phase. Especially\nLink.Frame.modList use in bosh must be eliminated but this is related\nto the RefreshUI/delete API finalization.\nThe items below detail the UI refactoring.\n\nwx usages went down by an impressive 1148:\n\n305: 2260 usages (balt: 381, basher: 1586)\n306: 1112 usages (balt: 418, basher/: 494)\n\nNote balt barely going up. This is because, as was stressed in the\nrelevant issue (#190), decoupling the wx library from the code\ndoes not simply mean \"create wrappers for wx classes/constants and\ndrop them into balt - it means that balt must export an API\", so:\n\n - balt should not return wx items on which wx methods will be called -\n see: 9856c69dc0ae2eb1e3ffea5d4e17fd0945f9706e for example fix.\n - the code outside of balt should be agnostic of wx ids. Bash code was\nfar form agnostic of wx ids - on the contrary it used them extensively:\n\n  - balt was exporting it as a function parameter - this mostly resulted\n  in client code calling it with `wx.ID_ANY` (adding wx usages) - see\n  for ex. a55516021550a7771d57de765411e75eca38ee5e,\n  18cf2b1f598454d105d8e0018c0150723bc6ca6b up till finally dropping\n  the last one of them in 370bef3b5ec75e2a30f43e3f822c95306ddb3f0e.\n  - event handlers were using `event.GetId()` - for example fix see\n  081bfa6ba7ec94f43fe22349292360ba26316313.\n  - Link.Execute() has an event parameter which was mostly used with the\n  IdList hack to define lists of menus - this was taken care by the\n  ChoiceLink subclass, introduced in\n  6fbec32fbecbc72f72c5dd908e8d12a503fde502 till finally the last uses of\n  IdList were binned: 000f320423d5b1e533eabf30c92e3f96bbdad5df and\n  IdList was removed (967b921e0dfe6a6d52cc83939c83374e0e3d6bbd) - note\n  that this permitted dropping the `_id` parameter from `Link.__init__`.\n  ItemLink.Execute() `event` parameter is in fact _never used_ in the\n  306 Link API iteration and will be removed. That's \"decoupling wx from\n  Bash code\".\n\nFor commits that combine both fixes see:\n  46599bb848c16e8b6627f5995521ac3113f4a14e,\n  9a77bfc42c83c20ca9c7c06f23ba90588dfe9b1f\n\nThe bulk of what remains is to hash up a clever interface for sizers -\nneeds thought as it must accommodate all usages while being powerful\nenough to cater for new ones. That being said, another\nthought is incorporating some basher wx dependent stuff back to balt\nwhich anyway should be split to a package - at least its bosh depended\nclasses should be clearly separated from its \"abstract\" wx wrapping API.\n\nIn a gigantic merge (054970e7b4d82e351c9a696b8e3c9750516d96b8 - avoid)\nthe Link subclasses were ripped from basher to per-tab modules - this\nis not final but it was a necessary step to start splitting basher. As\nwith the rip of patchers this was not a copy paste rip - a new Link\nclass API was introduced.\nUnlike the patchers rip however (where package structure and the class\nhierarchy is still at stake) the Link API has few rough edges left in.\nThe guide for designing the Link hierarchy was `AppendToMenu()` calls\nthat featured boilerplate wx code - for wip boilerplate elimination\ncommits see: 6cf40c1c9d819dc8722c1528140383b17193b030\nwhere `EnabledLink` is introduced and\n658fcac71fd15922a9fa81737fe4ba853ac28c5f where my favourite\n`TransLink` is introduced (AppendToMenu could become quite _complex_ -\nsee also `ChoiceLink`: 6fbec32fbecbc72f72c5dd908e8d12a503fde502).\nThe merge chopped off 785 wx uses and AppendToMenu was confined in balt,\nand reduced to 8 different implementations vs 215 (!) in 305.\n\nThe Link API significantly evolved since - compare the 306 (semi final)\nform with the 305 implementation:\n\n305: https://github.com/wrye-bash/wrye-bash/blob/d8f05202e6485a3bef0d92bb55a731b8040eb94e/Mopy/bash/balt.py#L2098-L2114\n306: https://github.com/wrye-bash/wrye-bash/blob/b40b1a10ff414dd41dd412c8484ca253e42ca92c/Mopy/bash/balt.py#L2392-L2446\n\nPrevious (old style) Link class explicitly defined _different_\nattributes based on an isinstance check, checking if the underlying\nwindow was a List or Tank instance. This made the code plain unreadable\n(given also the names used, see .data section above) while enforcing the\nTank/List dichotomy. The isinstance check was finally removed here:\n6d260f06281085cec8d5e6b0ededc3c61601c91c.\n\nHere is `INI_ListErrors` Link before and after the refactoring:\n\n305: https://github.com/wrye-bash/wrye-bash/blob/d8f05202e6485a3bef0d92bb55a731b8040eb94e/Mopy/bash/basher.py#L11168-L11191\n306: https://github.com/wrye-bash/wrye-bash/blob/b40b1a10ff414dd41dd412c8484ca253e42ca92c/Mopy/bash/basher/ini_links.py#L71-L90\n\nNote AppendToMenu code is encapsulated in EnabledLink, wx wrapper\nintroduced for the clipboard, text and help are now class variables,\n\"data\" is now \"selected\" and the lines are wrapped for more readable,\ndeclarative and concise code. For a more complicated example see:\n\n305: https://github.com/wrye-bash/wrye-bash/blob/d8f05202e6485a3bef0d92bb55a731b8040eb94e/Mopy/bash/basher.py#L11029-L11122\n306 :https://github.com/wrye-bash/wrye-bash/blob/b40b1a10ff414dd41dd412c8484ca253e42ca92c/Mopy/bash/basher/mods_links.py#L84-L161\n\nPrevious implementation directly manipulated wx IDs (by global ID_***\ncomplex hacks) while the new one declares classes and lets ChoiceLink\nsuperclass take care of creating and appending the menu items.\nThis permitted focusing on the Execute code which as seen got improved\nwhile refactored to remove duplication. This class still has rough\nedges (\\_self...) which will be corrected in 307 along with rough edges\nin the API - for one dropping ItemLink.Execute() `event` parameter.\nOf note that the Link subclasses featured a lot of duplicate code apart\nfrom the wx related stuff - see for instance:\n1a9a29e0abd0f59098168e7f03f9e82ebf6c698c for duplicate code in\nMod_Export Links.\n\nAfter the Links were ripped from basher it became obvious that\nrefactoring could not progress while balt.Tank and basher.List were\nboth still around. That lead, one fine morning, to a new class - UIList:\n14622274d131ccda4bd552a25c8063ccaef206e5. Both Tank and List had an\nattribute (glist and list (!) respectively) pointing to a ListControl\ninstance (the items displayed in the UI). The first UIList merge:\nabd5f245c8a8f8d2ac6abfd25004487ed805101d (see commits there for how\nUIList was engineered from common Tank/List code) has List.list removed\nin favour of gList: fc7bde8936db3a77728d912f9133c38a9df6cf2f, to be\nfinally encapsulated as _gList in\nc48ce7d7e4293feee0fa951a767c95dae282e92b (note there is a completely\nunrelated `gList` patcher attribute).\n\nThe first real snug though was unifying the sorting API of Tank and\nList. ListControl does not support sorting, one has to introduce a hacky\ndictionary mapping indexes to displayed items' ids (not wx ids) - that's\nwhat Tank was doing (undocumented !) while List was using no less than\nPopulateItems - resulting in bad performance most apparent in the ini\ntab, where sorting would stat the file system (so clicking on a column\nheader Bash would hang couple seconds).\nI proceeded unifying the List.SortItems() overrides\n(6f0adc9680127e7f197dc3c0a3b5dbb88d79ba4a), then moving the Tank\nmechanism to the ListControl class where it belongs\n(52a4a222ead2b0ab71462c9f819f436bfa245633) and finally moving SortItems\nto base: 42d213a4e7d39cbdc84b909b6cb5664449dcd597 - note OnColumnClick\ncallback to base and ignore the isinstance(self, Tank) - corrected\nlater. This made also various other fixups around the Sort API possible,\nnamely adding sort indicators in all Bash lists (only mod tabs\nhad them), fixing master lists sorting (and display) and the beginning\nof TankData param API deprecation:\n7a3b87253a5908ee286a894f0016e9fb8d4c88f2.\n\nSecond snug and a blocker for fixing performance was centralizing (and\ncleaning up) the RefreshUI family and underlying PopulateItem(s)\n(UpdateItem(s) in Tank). Some commits:\n\n- Moving RefreshUI to List: 39e1e6044f10f68928d5167be986c08305d403ca\n- List.PopulateItem(): f390ab7bae00014188caa6cb101f382a6b987214,\necf30e902fcf184741d8e90699877541dad6a6fa\n- UIList.PopulateItems(): 350075a63fe762e1b6029e57df51d203a96a3dd4\n- Tank and List `__init__()` eliminated:\na510b2377a45de58d4d54fc9637a8bce17080afb\n\nUnifying the RefreshUI API made finally possible to remove List itself:\nd94a09c439d3c84a92153764122614e065391f7f. More work is done - for\ninstance see some work on refreshing the details displayed in:\n3ff6cf2abeacd97b6da9bdf1b20da3367bcd0a06.\n\nOnce List was no more and Tank a relic of itself it was finally possible\nto tackle the delete API. First relevant merge is:\n02a5891c3f1a47e3f3763f772ed5cc767ec93415 but the API is yet in alpha\ndue to calling UI code from bosh - see:\n6452bcb4b44d4b434e8636b35b69351cb6742869 and its parent merge containing\n3da60e62ea37c486924b596be31b8b7108e07f89 (the ugly\nDataDict.delete_Refresh()). This API will hit beta once the data refresh\nmethods return deleted, modified and added - see how this precious info\nis currently discarded:\n\n\treturn bool(_added) or bool(_updated) or bool(_deleted)\n\nhttps://github.com/wrye-bash/wrye-bash/blob/b40b1a10ff414dd41dd412c8484ca253e42ca92c/Mopy/bash/bosh.py#L3887\n\nAs seen by profiling, the performance bottleneck was the\nlibloadorder32.dll we bundled with bash. Given the central place load\norder operations have in a mod manager application, the introduction of\na laggy dll had taken Bash's performance down on its knees since\n51f99f2b5deafd4971ad37e703452fe45a98c4d8.\nBut this was far from being the only problem. Due to the spaghetti\nnature of the code (throw some event programming in) Bash was very\ngenerous with its refreshes:\n\n- it would refresh its data three (3) times on boot\n- RefreshData callback was triggered whenever Bash took focus -\n_including_ after Bash itself displayed a dialog to the user\n- on Oblivion, while Bash had refreshed its mod infos it was _always_\nrequesting also a refresh from libloadorder, to be sure - so,\nfor instance, when just tabbing out and back in to Bash (with absolutely\nno changes in the Data dir) libloadorder was triggered and went through\nits refresh cycle - see ad05f44774db6e32363276c4d5b245f9cdc64cbd for the\nfix - refresh in BAIN, say, install operations was called twice, along\nwith a double call of modList RefreshUI\n- refreshing the mods panel would result in also refreshing the saves\npanel - even when the change that triggered the refresh did not affect\nsaves - see commits in: 63d8dec6d159b2485a60ab8d19f5d447c1b84c34\n\nNow, given that most of those refreshes ended up triggering a refresh\nfrom the libloadorder32.dll, Bash would take of the order of 10 seconds\nfor all but the most trivial operations. But even if libloadorder was\nlightning fast the double and triple refreshes were as much a bug as\nanything - so the dll lag was even a blessing in disguise as it made\napparent the underlying chaos.\n\nTo solve the dll issue one alternative would be to reimplement\nit in python. But given that the same dll is used by other mod managers\nand related apps I anyway had to know what's in there. So I ended up\nforking libloadorder and going through the C++ ~~pain~~ code:\nhttps://github.com/Utumno/libloadorder/\nI realized that some of the operations performed by the dll are\ninherently costly and would actually need a complete rewrite\nusing caches - for instance the mod validity checks (see\nhttps://github.com/Utumno/libloadorder/issues/3), which by the way\ninvolves yet another library and is not clear what is checked (as\nis not clear what Bash checks and if those checks are basically\nperformed twice - https://github.com/Utumno/libloadorder/issues/6).\nAs the situation was critical in Oblivion mainly (due to\nstating the filesystem for mod times) I explicitly bypassed the dll\nbecause I anyway have all the data needed to determine the load order -\n7cd653370e1ec082388af8eac17f389555fc9e8d - while I still use the dll for\nsaving it.\n\nLiblo 7.6.0 commit (f5de6c8119b380e5ac35038fc47ddbece952871c) apart from\nperformance fixups fixes some other issues with liblo 4 and 6 like\nwriting loadorder.txt when not there, return active plugins in order,\nadding files to libloadorder.txt that are added to Data, etc - see:\nhttps://github.com/Utumno/libloadorder/commit/7bb5cfba185dc563a22556f98c450536c76162d4\n\nBut rewriting the dll was not enough - on the Python side of things the\nload order internal API was a giant hack, complete with event handlers\nand absolutely no encapsulation, let alone proper caches. I introduced\na new module `load_order.py` (for first iteration and design decisions\nsee 98ed5496aed9660815134538d9af519544b97e62) to centralize load_order\nhandling - will be finalized in 307 but already Plugins is again\nencapsulated in ModInfos which serves as the basic internal load order\nAPI for the rest of Bash. Load order API will be final when implementing\nfeatures such as \"undo load order change\" is a breeze, but already makes\nimplementing minor load order related features much easier:\n14ecafcddd52a3c4c7c627d00f592e7ef5254f49.\n\nUsing the caches I introduced I was able to fix performance of\ngetOrdered() - was O(n^3\\*logn) instead of O(n\\*logn):\n5d7ed0b629caabd719c1627ee394bde7c1562de9\n\nThe double and triple refreshes were a deeper issue - the \"one file\nprogram\" thing - so rewriting refreshes (RefreshUI, the DataDicts\nrefresh, RefreshData etc) - was an ongoing effort throughout 306\ndevelopment, going hand to hand with the UI refactoring (see #163 for\nRefreshUI and #123 for links to some of the most relevant commits).\nIn short:\n\n- the refreshes on bash dialogs were taken care using a decorator to\nunbind RefreshData(): a71f3f2557ee9da84485351e180a6af4a163725d\n- the BAIN issues were addressed finally here:\n8107f7bd04684bf87351d382a88c33812cde33c6 - BAIN however needs to be\nsplit in a dedicated package to start properly fixing it.\n\nGoals for the next few releases:\n\n- cache ini reads\n- finalize then profile the load order handling API\n- profile the refresh of data on boot and optimize it\n- centralize refresh of data and UI so we can eventually\n- switch to an event based model of runtime refresh (watchdog ?)\n\nPycharm code inspection emits 2228 warnings in 306 as opposed to 4229\nin 305. Metrics are from Pycharm 4.5.4 - using this inspection:\nhttps://github.com/Utumno/wrye-bash-pycharm/blob/168253bca81313a3cc7dc85ee53747b116e984fb/.idea/inspectionProfiles/default_copy_no_typos.xml\non this scope:\nhttps://github.com/Utumno/wrye-bash-pycharm/blob/168253bca81313a3cc7dc85ee53747b116e984fb/.idea/scopes/wrye_bash_all_no_cint.xml\nWarnings come in various sizes and shapes but in general show\nlow code quality.\nSome I batch fixed (like 'Comparison to None performed with\nequality operator') but in general I was fixing warnings when visiting\nnearby code so the remaining ones mostly mark code areas that need\nattention. On the other end of the spectrum there are warnings that\ndeserve issues of their own (like 'Too broad exception clause' -\nnicknamed the most diabolical python anti-pattern - see #200).\nOther interesting cases were:\n\n- \"Function 'close' doesn't return anything\" led to a rewrite of the\narchives handling code: c29d7b85f0509d82b5e5fd2208f3c90c096f7462\n- copy paste unused variables were kind of a guide to otherwise heavily\nundocumented code - but also often pointed to bugs\n- \"method may be static\" (264 in 305, went down to 72 in 306) is a\nclassic example of a warning one fixes while editing the code - the\nremaining ones should be revisited for 307, along with their classes.\n- unused imports are on their way to extinction - the remaining cases\ninvolve `import *` patterns and normalizing the import style, which\nshall be done when package layout is frozen - and the ugly `__all__`\ndirectives one has to update on adding a menu item:\n6a2e4a9f72bd0b87c3c790e9712966e75e7c1df6 - UILists and their links\nbelong together.\n\nCruft removal got a dedicated issue so returning developers could\nreadily track when and why code they were familiar with got removed.\nCruft is not just unused classes, commented out code etc - it is also\ncompatibility with ancient Bash settings (will be removed in 307),\nnon working tabs (like the PM tab also to be removed in 307) and\ncompatibility code with pre 2.7 python (see\n6d0a944723b5173a361d77cab747eb17d3febf43). One major piece of cruft\nremoved in 306 was BALO: b5205915a3809e4a77a52e055eb206bc6ab4a771.\nAs you can see removing BALO was needed for tackling refresh - as it\nwas a complex, obsolete piece of code that greatly complicated both\nrefresh and load order handling - and even the Link API (see notoriously\ncomplex Mod_BaloGroups(ChoiceLink) subclass here:\naa5b89a5e0ba57ea57edb4a11782fecfded28d7c).\n\nAfter some discussion it was clear that PEP8'ing the code would be\na pointless effort at the state it was in - however word wrapping is\na _functional_ requirement and 79 chars is well thought of, even if you\nuse a wall projector for programming.\n\n305:\nTotal number of non-blank lines:  82463 in 29 files\n96.22 lines less than 80 characters (3120 lines exceed)\n98.63 lines less than 100 characters (1130 lines exceed)\n99.44 lines less than 120 characters (462 lines exceed)\n\n306:\nTotal number of non-blank lines:  85366 in 63 files\n97.89 lines less than 80 characters (1803 lines exceed)\n99.26 lines less than 100 characters (631 lines exceed)\n99.71 lines less than 120 characters (248 lines exceed)\n\nNote:\n- I do not include `cint.py` (and the `chardet` package which should\nbecome a submodule)\n- a big part of the line wrapping was made by manually correcting\nPycharm's formatter - so have a close look\n- the increase of line count is mainly due to\n21de440b098dd0cd56d511202a34b443dcaf67dd which adds 5130 lines most\n(4974) of it being static data in Mopy/bash/game/skyrim.py.\nConsidering there were 34 files added for 34 * 23 = 782 lines of licence\ntext and that wrapping should have produced another 1k lines at least\n_core Bash code was actually reduced by ~4000 lines_. That is more than\nwelcome and should be imitated - _less code more features_ is a great\nmotto.\n\nBooting process got a facelift to be finalized in 307. This involves\ngame loading (see 97fc9cf61af3832b196408bd93365ab83f01ca28), fixes to\nthe game detection algorithm (e19237c18f14de839d5724051ddea67a600a67fa)\nwhich used to run 3-5 times on boot, a fix for our custom importer\n(43e359aa00433aba3ec825f2d782f06e703389a9) compliments of mjpieters,\nand finally a reworking of boot error messages\n(8dbdd496fee7f1e9c13ae8dd2bdc1328462f4a77).\n\nAs reported in #203 \"WryeBash v304.2 works beautifully in Wine\" - the\nwindows only shell UI stuff broke it though. One of the last things\nI did for 306 was fixing this - now Bash runs again on WINE:\n124f314100e32a18cb3c339a17f6c434e48295f8. Still making it run correctly\nand in a second phase making Bash run _on bare Linux_ is a code quality\ngoal that got dedicated issues (#240, #241, #243)\n\n------------------------------------------------------------------------\n\nThis release is dedicated to Wrye.\n\nSpecial thanks to:\n- Sharlikran, Supierce, lojack5, Arthmoor, alt3rn1ty, psilocide\n(aka lefenger), leandor for testing, support and sharing their\nknowledge,\n- jfpelland, wduda, Isenr and valda for patches,\n- mjpieters for saving my sanity at SO a couple times as well as zed\nfor helping me rewrite the archives handling code.\n\n------------------------------------------------------------------------\n\nBuild with `2.7.10 (default, May 23 2015, 09:40:32) [MSC v.1500 32 bit (Intel)]`\n\nCloses #187.","distinct":true,"url":"https://api.github.com/repos/valda/wrye-bash/commits/9f02e3ef2bd0b718cf2cb8224028d364f3cfa526"},{"sha":"1bdc253e362857dc8a2a484be60bbcccd7891d82","author":{"email":"4940bdc6f784780ad32bf9f03596977cf7f253eb@gmail.com","name":"MrD"},"message":"bosh package:\n\nAnd let the splitting begin (after ripping out the messages tab)\n\nUnder #201.","distinct":true,"url":"https://api.github.com/repos/valda/wrye-bash/commits/1bdc253e362857dc8a2a484be60bbcccd7891d82"},{"sha":"9cb9a80aca34d739ce5e33561b630ef32b8576e7","author":{"email":"4940bdc6f784780ad32bf9f03596977cf7f253eb@gmail.com","name":"MrD"},"message":"bolt.Path optimization:\n\nThe bolt opt matters - compare:\n\nrefreshDataSizeCrc on a biggish package before the opt:\n\n         1179869 function calls in 1.390 seconds\n\n   Ordered by: cumulative time\n\n   ncalls  tottime  percall  cumtime  percall filename:lineno(function)\n        1    0.000    0.000    1.413    1.413 <string>:1(<module>)\n        1    0.191    0.191    1.413    1.413 __init__.py:5995(_refresh)\n    14389    0.050    0.000    0.923    0.000 bolt.py:451(GPath)\n    14388    0.013    0.000    0.683    0.000 bolt.py:532(__init__)\n    14388    0.075    0.000    0.666    0.000 bolt.py:543(__setstate__)\n    28776    0.362    0.000    0.419    0.000 ntpath.py:174(split)\n    14388    0.008    0.000    0.207    0.000 ntpath.py:206(basename)\n    14389    0.095    0.000    0.173    0.000 ntpath.py:415(normpath)\n    28776    0.107    0.000    0.137    0.000 {eval}\n    28776    0.018    0.000    0.126    0.000 ntpath.py:199(splitext)\n    28776    0.063    0.000    0.108    0.000 genericpath.py:93(_splitext)\n    57552    0.035    0.000    0.097    0.000 ntpath.py:43(normcase)\n    43165    0.064    0.000    0.086    0.000 ntpath.py:96(splitdrive)\n   115106    0.050    0.000    0.050    0.000 {method 'replace' of 'unicode' objects}\n    71944    0.050    0.000    0.050    0.000 {method 'lower' of 'unicode' objects}\n    86328    0.031    0.000    0.031    0.000 {method 'rfind' of 'unicode' objects}\n    28777    0.029    0.000    0.029    0.000 {method 'split' of 'unicode' objects}\n    57553    0.028    0.000    0.028    0.000 {method 'startswith' of 'unicode' objects}\n    28776    0.011    0.000    0.016    0.000 bolt.py:1015(__hash__)\n    71944    0.015    0.000    0.015    0.000 {isinstance}\n    28776    0.014    0.000    0.014    0.000 {max}\n    14388    0.007    0.000    0.014    0.000 __init__.py:5828(<lambda>)\n   187048    0.013    0.000    0.013    0.000 {len}\n    14388    0.007    0.000    0.013    0.000 __init__.py:5956(<lambda>)\n    14388    0.005    0.000    0.010    0.000 __init__.py:5830(<lambda>)\n    43164    0.009    0.000    0.009    0.000 __init__.py:5921(__skipExecutable)\n    14389    0.008    0.000    0.008    0.000 {method 'join' of 'unicode' objects}\n    14389    0.006    0.000    0.006    0.000 {method 'get' of 'dict' objects}\n    14388    0.005    0.000    0.005    0.000 {method 'endswith' of 'unicode' objects}\n    28776    0.005    0.000    0.005    0.000 {hash}\n    14388    0.004    0.000    0.004    0.000 __init__.py:5883(_processDocs)\n    14388    0.004    0.000    0.004    0.000 __init__.py:5893(_processBCF)\n    14388    0.004    0.000    0.004    0.000 __init__.py:5899(_processWizard)\n    14388    0.003    0.000    0.003    0.000 {method 'setdefault' of 'dict' objects}\n        1    0.000    0.000    0.000    0.000 __init__.py:5914(_init_executables_skips)\n        1    0.000    0.000    0.000    0.000 __init__.py:5875(_initComplexSkips)\n        2    0.000    0.000    0.000    0.000 bolt.py:1562(__setitem__)\n        9    0.000    0.000    0.000    0.000 gettext.py:219(ugettext)\n        1    0.000    0.000    0.000    0.000 __init__.py:5906(_init_skips)\n        5    0.000    0.000    0.000    0.000 bolt.py:1194(__getitem__)\n        2    0.000    0.000    0.000    0.000 {method 'update' of 'dict' objects}\n        1    0.000    0.000    0.000    0.000 bolt.py:1201(__len__)\n        1    0.000    0.000    0.000    0.000 bolt.py:579(sroot)\n        2    0.000    0.000    0.000    0.000 {method 'add' of 'set' objects}\n        1    0.000    0.000    0.000    0.000 __init__.py:6016(<genexpr>)\n        3    0.000    0.000    0.000    0.000 {method 'clear' of 'set' objects}\n        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}\n\nAfter opt:\n\n         1122310 function calls in 1.203 seconds\n\n   Ordered by: cumulative time\n\n   ncalls  tottime  percall  cumtime  percall filename:lineno(function)\n        1    0.000    0.000    1.203    1.203 <string>:1(<module>)\n        1    0.140    0.140    1.203    1.203 __init__.py:5827(_refresh)\n    14389    0.047    0.000    0.908    0.000 bolt.py:451(GPath)\n    14388    0.013    0.000    0.682    0.000 bolt.py:533(__init__)\n    14388    0.075    0.000    0.664    0.000 bolt.py:544(__setstate__)\n    28776    0.361    0.000    0.418    0.000 ntpath.py:174(split)\n    14388    0.008    0.000    0.206    0.000 ntpath.py:206(basename)\n    14389    0.095    0.000    0.163    0.000 ntpath.py:415(normpath)\n    28776    0.017    0.000    0.126    0.000 ntpath.py:199(splitext)\n    28776    0.064    0.000    0.109    0.000 genericpath.py:93(_splitext)\n    57552    0.035    0.000    0.096    0.000 ntpath.py:43(normcase)\n    43165    0.062    0.000    0.083    0.000 ntpath.py:96(splitdrive)\n    71944    0.049    0.000    0.049    0.000 {method 'lower' of 'unicode' objects}\n   115106    0.049    0.000    0.049    0.000 {method 'replace' of 'unicode' objects}\n    43165    0.038    0.000    0.038    0.000 {method 'split' of 'unicode' objects}\n   115105    0.032    0.000    0.032    0.000 {method 'startswith' of 'unicode' objects}\n    86328    0.030    0.000    0.030    0.000 {method 'rfind' of 'unicode' objects}\n    71944    0.015    0.000    0.015    0.000 {isinstance}\n    28776    0.010    0.000    0.015    0.000 bolt.py:1016(__hash__)\n    28776    0.014    0.000    0.014    0.000 {max}\n   187048    0.013    0.000    0.013    0.000 {len}\n    14388    0.007    0.000    0.007    0.000 {method 'join' of 'str' objects}\n    14388    0.006    0.000    0.006    0.000 {method 'endswith' of 'unicode' objects}\n    14389    0.006    0.000    0.006    0.000 {method 'join' of 'unicode' objects}\n    14389    0.006    0.000    0.006    0.000 {method 'get' of 'dict' objects}\n    28776    0.005    0.000    0.005    0.000 {hash}\n    28776    0.005    0.000    0.005    0.000 {method 'setdefault' of 'dict' objects}\n        2    0.000    0.000    0.000    0.000 bolt.py:1563(__setitem__)\n       12    0.000    0.000    0.000    0.000 bolt.py:1195(__getitem__)\n        1    0.000    0.000    0.000    0.000 bolt.py:1202(__len__)\n        1    0.000    0.000    0.000    0.000 bolt.py:580(sroot)\n        1    0.000    0.000    0.000    0.000 __init__.py:5859(<genexpr>)\n        2    0.000    0.000    0.000    0.000 {method 'add' of 'set' objects}\n        3    0.000    0.000    0.000    0.000 {method 'clear' of 'set' objects}\n        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}\n\nDiscussed in 3e09c66b6752b92ede8d67888a6d998806166a1c","distinct":true,"url":"https://api.github.com/repos/valda/wrye-bash/commits/9cb9a80aca34d739ce5e33561b630ef32b8576e7"},{"sha":"64be37162d735dc37e9514868c31dbc437983150","author":{"email":"4940bdc6f784780ad32bf9f03596977cf7f253eb@gmail.com","name":"MrD"},"message":"Messages to bosh/msgs.py","distinct":true,"url":"https://api.github.com/repos/valda/wrye-bash/commits/64be37162d735dc37e9514868c31dbc437983150"}]}