28
28
from io import BytesIO
29
29
from xml .dom import minidom
30
30
31
+ from typing_extensions import deprecated
32
+
31
33
from selenium .common .exceptions import WebDriverException
32
34
33
35
WEBDRIVER_PREFERENCES = "webdriver_prefs.json"
34
- EXTENSION_NAME = "[email protected] "
35
36
36
37
38
+ @deprecated ("Addons must be added after starting the session" )
37
39
class AddonFormatError (Exception ):
38
40
"""Exception for not well-formed add-on manifest files."""
39
41
40
42
41
43
class FirefoxProfile :
42
- ANONYMOUS_PROFILE_NAME = "WEBDRIVER_ANONYMOUS_PROFILE"
43
44
DEFAULT_PREFERENCES = None
44
45
45
46
def __init__ (self , profile_directory = None ):
@@ -52,61 +53,60 @@ def __init__(self, profile_directory=None):
52
53
This defaults to None and will create a new
53
54
directory when object is created.
54
55
"""
55
- if not FirefoxProfile .DEFAULT_PREFERENCES :
56
- with open (
57
- os .path .join (os .path .dirname (__file__ ), WEBDRIVER_PREFERENCES ), encoding = "utf-8"
58
- ) as default_prefs :
59
- FirefoxProfile .DEFAULT_PREFERENCES = json .load (default_prefs )
60
-
61
- self .default_preferences = copy .deepcopy (FirefoxProfile .DEFAULT_PREFERENCES ["mutable" ])
62
- self .profile_dir = profile_directory
63
- self .tempfolder = None
64
- if not self .profile_dir :
65
- self .profile_dir = self ._create_tempfolder ()
66
- else :
67
- self .tempfolder = tempfile .mkdtemp ()
68
- newprof = os .path .join (self .tempfolder , "webdriver-py-profilecopy" )
56
+ self ._desired_preferences = {}
57
+ if profile_directory :
58
+ newprof = os .path .join (tempfile .mkdtemp (), "webdriver-py-profilecopy" )
69
59
shutil .copytree (
70
- self . profile_dir , newprof , ignore = shutil .ignore_patterns ("parent.lock" , "lock" , ".parentlock" )
60
+ profile_directory , newprof , ignore = shutil .ignore_patterns ("parent.lock" , "lock" , ".parentlock" )
71
61
)
72
- self .profile_dir = newprof
73
- os .chmod (self .profile_dir , 0o755 )
74
- self ._read_existing_userjs (os .path .join (self .profile_dir , "user.js" ))
75
- self .extensionsDir = os .path .join (self .profile_dir , "extensions" )
76
- self .userPrefs = os .path .join (self .profile_dir , "user.js" )
77
- if os .path .isfile (self .userPrefs ):
78
- os .chmod (self .userPrefs , 0o644 )
62
+ self ._profile_dir = newprof
63
+ os .chmod (self ._profile_dir , 0o755 )
64
+ else :
65
+ self ._profile_dir = tempfile .mkdtemp ()
66
+ if not FirefoxProfile .DEFAULT_PREFERENCES :
67
+ with open (
68
+ os .path .join (os .path .dirname (__file__ ), WEBDRIVER_PREFERENCES ), encoding = "utf-8"
69
+ ) as default_prefs :
70
+ FirefoxProfile .DEFAULT_PREFERENCES = json .load (default_prefs )
71
+
72
+ self ._desired_preferences = copy .deepcopy (FirefoxProfile .DEFAULT_PREFERENCES ["mutable" ])
73
+ for key , value in FirefoxProfile .DEFAULT_PREFERENCES ["frozen" ].items ():
74
+ self ._desired_preferences [key ] = value
79
75
80
76
# Public Methods
81
77
def set_preference (self , key , value ):
82
78
"""Sets the preference that we want in the profile."""
83
- self .default_preferences [key ] = value
79
+ self ._desired_preferences [key ] = value
84
80
85
- def add_extension (self , extension ):
81
+ @deprecated ("Addons must be added after starting the session" )
82
+ def add_extension (self , extension = None ):
86
83
self ._install_extension (extension )
87
84
88
85
def update_preferences (self ):
89
- for key , value in FirefoxProfile .DEFAULT_PREFERENCES ["frozen" ].items ():
90
- # Do not update key that is being set by the user using
91
- # set_preference as users are unaware of the freeze properties
92
- # and it leads to an inconsistent behavior
93
- if key not in self .default_preferences :
94
- self .default_preferences [key ] = value
95
- self ._write_user_prefs (self .default_preferences )
86
+ """Writes the desired user prefs to disk."""
87
+ user_prefs = os .path .join (self ._profile_dir , "user.js" )
88
+ if os .path .isfile (user_prefs ):
89
+ os .chmod (user_prefs , 0o644 )
90
+ self ._read_existing_userjs (user_prefs )
91
+ with open (user_prefs , "w" , encoding = "utf-8" ) as f :
92
+ for key , value in self ._desired_preferences .items ():
93
+ f .write (f'user_pref("{ key } ", { json .dumps (value )} );\n ' )
96
94
97
95
# Properties
98
96
99
97
@property
100
98
def path (self ):
101
99
"""Gets the profile directory that is currently being used."""
102
- return self .profile_dir
100
+ return self ._profile_dir
103
101
104
102
@property
103
+ @deprecated ("The port is stored in the Service class" )
105
104
def port (self ):
106
105
"""Gets the port that WebDriver is working on."""
107
106
return self ._port
108
107
109
108
@port .setter
109
+ @deprecated ("The port is stored in the Service class" )
110
110
def port (self , port ) -> None :
111
111
"""Sets the port that WebDriver will be running on."""
112
112
if not isinstance (port , int ):
@@ -121,20 +121,24 @@ def port(self, port) -> None:
121
121
self .set_preference ("webdriver_firefox_port" , self ._port )
122
122
123
123
@property
124
+ @deprecated ("Allowing untrusted certs is toggled in the Options class" )
124
125
def accept_untrusted_certs (self ):
125
- return self .default_preferences ["webdriver_accept_untrusted_certs" ]
126
+ return self ._desired_preferences ["webdriver_accept_untrusted_certs" ]
126
127
127
128
@accept_untrusted_certs .setter
129
+ @deprecated ("Allowing untrusted certs is toggled in the Options class" )
128
130
def accept_untrusted_certs (self , value ) -> None :
129
131
if not isinstance (value , bool ):
130
132
raise WebDriverException ("Please pass in a Boolean to this call" )
131
133
self .set_preference ("webdriver_accept_untrusted_certs" , value )
132
134
133
135
@property
136
+ @deprecated ("Allowing untrusted certs is toggled in the Options class" )
134
137
def assume_untrusted_cert_issuer (self ):
135
- return self .default_preferences ["webdriver_assume_untrusted_issuer" ]
138
+ return self ._desired_preferences ["webdriver_assume_untrusted_issuer" ]
136
139
137
140
@assume_untrusted_cert_issuer .setter
141
+ @deprecated ("Allowing untrusted certs is toggled in the Options class" )
138
142
def assume_untrusted_cert_issuer (self , value ) -> None :
139
143
if not isinstance (value , bool ):
140
144
raise WebDriverException ("Please pass in a Boolean to this call" )
@@ -143,9 +147,10 @@ def assume_untrusted_cert_issuer(self, value) -> None:
143
147
144
148
@property
145
149
def encoded (self ) -> str :
146
- """A zipped, base64 encoded string of profile directory for use with
147
- remote WebDriver JSON wire protocol."""
148
- self .update_preferences ()
150
+ """Updates preferences and creates a zipped, base64 encoded string of
151
+ profile directory."""
152
+ if self ._desired_preferences :
153
+ self .update_preferences ()
149
154
fp = BytesIO ()
150
155
with zipfile .ZipFile (fp , "w" , zipfile .ZIP_DEFLATED ) as zipped :
151
156
path_root = len (self .path ) + 1 # account for trailing slash
@@ -155,32 +160,21 @@ def encoded(self) -> str:
155
160
zipped .write (filename , filename [path_root :])
156
161
return base64 .b64encode (fp .getvalue ()).decode ("UTF-8" )
157
162
158
- def _create_tempfolder (self ):
159
- """Creates a temp folder to store User.js and the extension."""
160
- return tempfile .mkdtemp ()
161
-
162
- def _write_user_prefs (self , user_prefs ):
163
- """Writes the current user prefs dictionary to disk."""
164
- with open (self .userPrefs , "w" , encoding = "utf-8" ) as f :
165
- for key , value in user_prefs .items ():
166
- f .write (f'user_pref("{ key } ", { json .dumps (value )} );\n ' )
167
-
168
163
def _read_existing_userjs (self , userjs ):
164
+ """Reads existing preferences and adds them to desired preference
165
+ dictionary."""
169
166
pref_pattern = re .compile (r'user_pref\("(.*)",\s(.*)\)' )
170
- try :
171
- with open (userjs , encoding = "utf-8" ) as f :
172
- for usr in f :
173
- matches = pref_pattern .search (usr )
174
- try :
175
- self .default_preferences [matches .group (1 )] = json .loads (matches .group (2 ))
176
- except Exception :
177
- warnings .warn (
178
- f"(skipping) failed to json.loads existing preference: { matches .group (1 ) + matches .group (2 )} "
179
- )
180
- except Exception :
181
- # The profile given hasn't had any changes made, i.e no users.js
182
- pass
167
+ with open (userjs , encoding = "utf-8" ) as f :
168
+ for usr in f :
169
+ matches = pref_pattern .search (usr )
170
+ try :
171
+ self ._desired_preferences [matches .group (1 )] = json .loads (matches .group (2 ))
172
+ except Exception :
173
+ warnings .warn (
174
+ f"(skipping) failed to json.loads existing preference: { matches .group (1 ) + matches .group (2 )} "
175
+ )
183
176
177
+ @deprecated ("Addons must be added after starting the session" )
184
178
def _install_extension (self , addon , unpack = True ):
185
179
"""Installs addon from a filepath, url or directory of addons in the
186
180
profile.
@@ -212,11 +206,12 @@ def _install_extension(self, addon, unpack=True):
212
206
assert addon_id , f"The addon id could not be found: { addon } "
213
207
214
208
# copy the addon to the profile
215
- addon_path = os .path .join (self .extensionsDir , addon_id )
209
+ extensions_dir = os .path .join (self ._profile_dir , "extensions" )
210
+ addon_path = os .path .join (extensions_dir , addon_id )
216
211
if not unpack and not addon_details ["unpack" ] and xpifile :
217
- if not os .path .exists (self . extensionsDir ):
218
- os .makedirs (self . extensionsDir )
219
- os .chmod (self . extensionsDir , 0o755 )
212
+ if not os .path .exists (extensions_dir ):
213
+ os .makedirs (extensions_dir )
214
+ os .chmod (extensions_dir , 0o755 )
220
215
shutil .copy (xpifile , addon_path + ".xpi" )
221
216
else :
222
217
if not os .path .exists (addon_path ):
@@ -226,6 +221,7 @@ def _install_extension(self, addon, unpack=True):
226
221
if tmpdir :
227
222
shutil .rmtree (tmpdir )
228
223
224
+ @deprecated ("Addons must be added after starting the session" )
229
225
def _addon_details (self , addon_path ):
230
226
"""Returns a dictionary of details about the addon.
231
227
0 commit comments