Coverage for Applications/PyCharm.app/Contents/plugins/python/helpers/pycharm/_jb_utils.py: 52%
71 statements
« prev ^ index » next coverage.py v7.3.1, created at 2023-09-19 10:04 +0530
« prev ^ index » next coverage.py v7.3.1, created at 2023-09-19 10:04 +0530
1# coding=utf-8
3__author__ = 'Ilya.Kazakevich'
4import fnmatch
5import os
6import sys
9class FileChangesTracker(object):
10 """
11 On the instantiation the class records the timestampts of files stored in the folder.
12 #get_changed_files() return the list of files that have a timestamp different from the one they had during the class instantiation
15 """
17 def __init__(self, folder, patterns="*"):
18 self.old_files = self._get_changes_from(folder, patterns)
19 self.folder = folder
20 self.patterns = patterns
22 def get_changed_files(self):
23 assert self.folder, "No changes recorded"
24 new_files = self._get_changes_from(self.folder, patterns=self.patterns)
25 return filter(lambda f: f not in self.old_files or self.old_files[f] != new_files[f], new_files.keys())
27 @staticmethod
28 def _get_changes_from(folder, patterns):
29 result = {}
30 for tmp_folder, sub_dirs, files in os.walk(folder):
31 sub_dirs[:] = [s for s in sub_dirs if not s.startswith(".")]
32 if any(fnmatch.fnmatch(os.path.basename(tmp_folder), p) for p in patterns):
33 for file in map(lambda f: os.path.join(tmp_folder, f), files):
34 try:
35 result.update({file: os.path.getmtime(file)})
36 except OSError: # on Windows long path may lead to it: PY-23386
37 message = "PyCharm can't check if the following file been updated: {0}\n".format(str(file))
38 sys.stderr.write(message)
39 return result
42def jb_escape_output(output):
43 """
44 Escapes text in manner that is supported on Java side with CommandLineConsoleApi.kt#jbFilter
45 Check jbFilter doc for more info
47 :param output: raw text
48 :return: escaped text
49 """
50 return "##[jetbrains{0}".format(output)
53class OptionDescription(object):
54 """
55 Wrapper for argparse/optparse option (see VersionAgnosticUtils#get_options)
56 """
58 def __init__(self, name, description, action=None):
59 self.name = name
60 self.description = description
61 self.action = action
64class VersionAgnosticUtils(object):
65 """
66 "six" emulator: this class fabrics appropriate tool to use regardless python version.
67 Use it to write code that works both on py2 and py3. # TODO: Use Six instead
68 """
70 @staticmethod
71 def is_py3k():
72 return sys.version_info >= (3, 0)
74 @staticmethod
75 def __new__(cls, *more):
76 """
77 Fabrics Py2 or Py3 instance based on py version
78 """
79 real_class = _Py3KUtils if VersionAgnosticUtils.is_py3k() else _Py2Utils
80 return super(cls, real_class).__new__(real_class, *more)
82 def to_unicode(self, obj):
83 """
85 :param obj: string to convert to unicode
86 :return: unicode string
87 """
89 raise NotImplementedError()
91 def get_options(self, *args):
92 """
93 Hides agrparse/optparse difference
95 :param args: OptionDescription
96 :return: options namespace
97 """
98 raise NotImplementedError()
101class _Py2Utils(VersionAgnosticUtils):
102 """
103 Util for Py2
104 """
106 def to_unicode(self, obj):
107 if isinstance(obj, unicode):
108 return obj
109 try:
110 return unicode(obj) # Obj may have its own __unicode__
111 except (UnicodeDecodeError, AttributeError):
112 return unicode(str(obj).decode("utf-8")) # or it may have __str__
114 def get_options(self, *args):
115 import optparse
117 parser = optparse.OptionParser()
118 for option in args:
119 assert isinstance(option, OptionDescription)
120 parser.add_option(option.name, help=option.description, action=option.action)
121 (options, _) = parser.parse_args()
122 return options
125class _Py3KUtils(VersionAgnosticUtils):
126 """
127 Util for Py3
128 """
130 def to_unicode(self, obj):
131 return str(obj)
133 def get_options(self, *args):
134 import argparse
136 parser = argparse.ArgumentParser()
137 for option in args:
138 assert isinstance(option, OptionDescription)
139 parser.add_argument(option.name, help=option.description, action=option.action)
140 return parser.parse_args()