Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-fake-useragent for 
openSUSE:Factory checked in at 2023-12-02 17:13:41
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-fake-useragent (Old)
 and      /work/SRC/openSUSE:Factory/.python-fake-useragent.new.25432 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-fake-useragent"

Sat Dec  2 17:13:41 2023 rev:10 rq:1130471 version:1.4.0

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/python-fake-useragent/python-fake-useragent.changes  
    2023-08-10 15:33:35.036045326 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-fake-useragent.new.25432/python-fake-useragent.changes
   2023-12-02 17:14:04.055314938 +0100
@@ -1,0 +2,16 @@
+Sat Dec  2 14:16:36 UTC 2023 - Dirk Müller <[email protected]>
+
+- update to 1.4.0:
+  * python 3.12 support
+  * Introducing new `ua.getRandom`, `ua.getFirefox`,
+    `ua.getChrome`, `ua.getSafari`. And a generic method:
+    `ua.getBrowser(..)` (eg. `getBrowser('firefox')`)
+    These new properties above allows you to retrieve the whole
+    raw Python dictionary, instead of only the UA string.
+    These properties might return different key/values pairs in
+    the future! So `ua.random` is a more stable interface.
+  * Improved user-agent scraper (now also containing Safari
+    browser again)
+  * Updated browsers.json data file
+
+-------------------------------------------------------------------

Old:
----
  fake-useragent-1.2.1.tar.gz

New:
----
  fake-useragent-1.4.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-fake-useragent.spec ++++++
--- /var/tmp/diff_new_pack.wSkaXy/_old  2023-12-02 17:14:04.467330037 +0100
+++ /var/tmp/diff_new_pack.wSkaXy/_new  2023-12-02 17:14:04.467330037 +0100
@@ -19,7 +19,7 @@
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 %define skip_python2 1
 Name:           python-fake-useragent
-Version:        1.2.1
+Version:        1.4.0
 Release:        0
 Summary:        Useragent faker package for Python
 License:        Apache-2.0

++++++ fake-useragent-1.2.1.tar.gz -> fake-useragent-1.4.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fake-useragent-1.2.1/.github/workflows/action.yml 
new/fake-useragent-1.4.0/.github/workflows/action.yml
--- old/fake-useragent-1.2.1/.github/workflows/action.yml       2023-08-02 
16:01:31.000000000 +0200
+++ new/fake-useragent-1.4.0/.github/workflows/action.yml       2023-11-24 
22:04:08.000000000 +0100
@@ -16,7 +16,7 @@
     runs-on: ubuntu-latest # [macos-latest, windows-latest]
     strategy:
       matrix:
-        python-version: ["3.8", "3.9", "3.10", "3.11", "pypy-3.9"]
+        python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "pypy-3.9"]
     name: Python ${{ matrix.python-version }} Test
     steps:
       - uses: actions/checkout@v3
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fake-useragent-1.2.1/.github/workflows/ruff.yml 
new/fake-useragent-1.4.0/.github/workflows/ruff.yml
--- old/fake-useragent-1.2.1/.github/workflows/ruff.yml 2023-08-02 
16:01:31.000000000 +0200
+++ new/fake-useragent-1.4.0/.github/workflows/ruff.yml 2023-11-24 
22:04:08.000000000 +0100
@@ -9,11 +9,11 @@
       - master
 
 jobs:
-  ruff:
+  ruff-check:
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v3
       - name: Install dependencies
         run: pip install -r requirements.txt
-      - name: Ruff
-        run: ruff --format=github .
+      - name: Ruff Check
+        run: ruff check .
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fake-useragent-1.2.1/README.md 
new/fake-useragent-1.4.0/README.md
--- old/fake-useragent-1.2.1/README.md  2023-08-02 16:01:31.000000000 +0200
+++ new/fake-useragent-1.4.0/README.md  2023-11-24 22:04:08.000000000 +0100
@@ -8,6 +8,7 @@
 
 - Data is pre-downloaded from 
[techblog.willshouse.com](https://techblog.willshouse.com/2012/01/03/most-common-user-agents/)
 and the data is part of the package
 - Retrieves user-agent strings locally
+- Retrieve user-agent Python dictionary
 - Supports Python 3.x
 
 ### Installation
@@ -24,7 +25,7 @@
 
 ### Usage
 
-Simple usage example, see below for more examples:
+Simple usage examples below, see also next chapters in this readme for more 
advanced usages:
 
 ```py
 from fake_useragent import UserAgent
@@ -87,6 +88,37 @@
 
 _Hint:_ Of-course you can **combine all those arguments** to you liking!
 
+#### User-agent Python Dictionary
+
+Since version 1.3.0 we now also offer you the following "get" properties which 
return the whole Python dictionary of the UA, instead of only the user-agent 
string:
+
+> **Warning**
+> Raw JSON objects (in a Python dictionaries) are returned "as is".
+> Meaning, this data structure could change in the future!
+>
+> Be aware that these "get" properties below might not return the same 
key/value pairs in the future.
+> Use `ua.random` or alike as mentioned above, if you want to use a stable 
interface.
+
+```py
+from fake_useragent import UserAgent
+ua = UserAgent()
+
+# Random user-agent dictionary (object)
+ua.getRandom
+# {'percent': 0.8, 'useragent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 
Edg/116.0.1938.76', 'system': 'Edge 116.0 Win10', 'browser': 'edge', 'version': 
116.0, 'os': 'win10'}
+
+# More get properties:
+ua.getFirefox
+# {'percent': 0.3, 'useragent': 'Mozilla/5.0 (Windows NT 10.0; rv:109.0) 
Gecko/20100101 Firefox/118.0', 'system': 'Firefox 118.0 Win10', 'browser': 
'firefox', 'version': 118.0, 'os': 'win10'}
+ua.getChrome
+ua.getSafari
+ua.getEdge
+
+# And a method with an argument.
+# This is exactly the same as using: ua.getFirefox
+ua.getBrowser('firefox')
+```
+
 ### Notes
 
 You can override the fallback string using the `fallback` parameter, in very 
rare cases something failed:
@@ -132,10 +164,10 @@
 pip install --upgrade fake-useragent
 ```
 
-Or if that isn't working, try to install the latest package version like this 
(`1.2.0` is an example, check what the [latest version is on 
PyPi](https://pypi.org/project/fake-useragent/#history)):
+Or if that isn't working, try to install the latest package version like this 
(`1.4.0` is an example, check what the [latest version is on 
PyPi](https://pypi.org/project/fake-useragent/#history)):
 
 ```sh
-pip install fake-useragent==1.2.0
+pip install fake-useragent==1.4.0
 ```
 
 Check version via the Python console:
@@ -178,15 +210,40 @@
 
 #### Linting
 
-To fix imports:
+To fix imports using ruff:
 
 ```sh
 pip install -r requirements.txt
-ruff --select="I" --fix .
+ruff check --select="I" --fix .
 ```
 
+Fix black code formatting errors:
+
+```sh
+pip install -r requirements.txt
+black .
+```
+
+_Note:_ When ruff v1.0 releases, we most likely move fully towards `ruff` 
instead of `black`.
+
 ### Changelog
 
+- 1.4.0 November 24, 2023
+
+  - Update all PIP packages
+  - Support Python 3.12 (thanks @vladkens)
+  - Fix package conflict in cache scraper
+  - Improve ruff CLI calls
+
+- 1.3.0 October 2, 2023
+
+  - Introducing new `ua.getRandom`, `ua.getFirefox`, `ua.getChrome`, 
`ua.getSafari`. And a generic method: `ua.getBrowser(..)` (eg. 
`getBrowser('firefox')`)
+    - These new properties above allows you to retrieve the whole raw Python 
dictionary, instead of only the UA string.
+    - These properties might return different key/values pairs in the future!
+  - Fix the `os` argument 'windows' to check for both `win10`and `win7` values 
(previously only checking on `win10`), thus returning more UAs
+  - Improved user-agent scraper (now also containing Safari browser again)
+  - Updated browsers.json data file
+
 - 1.2.1 August 2, 2023
 
   - Small improvements in the `min_percentage` check
@@ -198,6 +255,7 @@
   - Allow filters on browser, OS and usage percentage
   - Update the cache scraper to scape the new data source for user-agent 
strings
   - Adapted the code to work with the new JSON data format
+  - Parameter `use_external_data=True` and `verify_ssl` are **removed**. If 
you use those parameters, just remove it in your code!
 
 - 1.1.3 March 20, 2023
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fake-useragent-1.2.1/cache_scraper/requirements.txt 
new/fake-useragent-1.4.0/cache_scraper/requirements.txt
--- old/fake-useragent-1.2.1/cache_scraper/requirements.txt     2023-08-02 
16:01:31.000000000 +0200
+++ new/fake-useragent-1.4.0/cache_scraper/requirements.txt     2023-11-24 
22:04:08.000000000 +0100
@@ -1,15 +1,15 @@
-APScheduler==3.10.1
+APScheduler==3.10.4
 attrs==23.1.0
 Automat==22.10.0
-black==23.7.0
-certifi==2023.7.22
-cffi==1.15.1
-charset-normalizer==3.2.0
-click==8.1.6
-constantly==15.1.0
-cryptography==41.0.3
+black==23.11.0
+certifi==2023.11.17
+cffi==1.16.0
+charset-normalizer==3.3.2
+click==8.1.7
+constantly==23.10.4
+cryptography==41.0.5
 cssselect==1.2.0
-filelock==3.12.2
+filelock==3.13.1
 hyperlink==21.0.0
 idna==3.4
 incremental==22.10.0
@@ -18,31 +18,31 @@
 jmespath==1.0.1
 lxml==4.9.3
 mypy-extensions==1.0.0
-packaging==23.1
+packaging==23.2
 parsel==1.8.1
 pathspec==0.11.2
-platformdirs==3.10.0
-Protego==0.2.1
-pyasn1==0.5.0
+platformdirs==4.0.0
+Protego==0.3.0
+pyasn1==0.5.1
 pyasn1-modules==0.3.0
 pycparser==2.21
 PyDispatcher==2.0.7
-pyOpenSSL==23.2.0
+pyOpenSSL==23.3.0
 pyparsing==3.1.1
-pytz==2023.3
+pytz==2023.3.post1
 pytz-deprecation-shim==0.1.0.post0
 queuelib==1.6.2
 requests==2.31.0
 requests-file==1.5.1
-Scrapy==2.9.0
+Scrapy==2.11.0
 service-identity==23.1.0
 six==1.16.0
-tldextract==3.4.4
+tldextract==5.1.1
 tomli==2.0.1
 Twisted==22.10.0
-typing_extensions==4.7.1
+typing_extensions==4.8.0
 tzdata==2023.3
-tzlocal==5.0.1
-urllib3==2.0.4
-w3lib==2.1.1
-zope.interface==6.0
+tzlocal==5.2
+urllib3==2.1.0
+w3lib==2.1.2
+zope.interface==6.1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/fake-useragent-1.2.1/cache_scraper/useragentscraper/spiders/useragent.py 
new/fake-useragent-1.4.0/cache_scraper/useragentscraper/spiders/useragent.py
--- 
old/fake-useragent-1.2.1/cache_scraper/useragentscraper/spiders/useragent.py    
    2023-08-02 16:01:31.000000000 +0200
+++ 
new/fake-useragent-1.4.0/cache_scraper/useragentscraper/spiders/useragent.py    
    2023-11-24 22:04:08.000000000 +0100
@@ -24,10 +24,15 @@
                 agent["percent"] = float(agent["percent"][:-1])
                 # Add additional fields
                 agent["browser"] = browser.lower()  # To lower-case
-                agent["version"] = float(version)  # Convert to float
+                # If version equals Generic, just set version to: 1.0
+                if version == "Generic":
+                    agent["version"] = 1.0
+                else:
+                    agent["version"] = float(version)  # Convert to float
                 agent["os"] = os.lower()  # To lower-case
                 # Yield each agent object at the time
                 yield agent
             except ValueError:
                 # Ignore user-agent strings that could not be parsed (eg. bot 
agent strings)
+                # (eg. bot agent strings like headless chrome, but also Yandex 
Browser and iOS)
                 pass
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fake-useragent-1.2.1/pyproject.toml 
new/fake-useragent-1.4.0/pyproject.toml
--- old/fake-useragent-1.2.1/pyproject.toml     2023-08-02 16:01:31.000000000 
+0200
+++ new/fake-useragent-1.4.0/pyproject.toml     2023-11-24 22:04:08.000000000 
+0100
@@ -4,10 +4,10 @@
 
 [project]
 name = "fake-useragent"
-version = "1.2.1"
+version = "1.4.0"
 authors = [
-    {name = "Victor Kovtun", email = "[email protected]"},
     {name = "Melroy van den Berg", email = "[email protected]"},
+    {name = "Victor Kovtun", email = "[email protected]"}
 ]
 dependencies = [
     "importlib-resources >= 5.0; python_version < '3.10'",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fake-useragent-1.2.1/pytest.ini 
new/fake-useragent-1.4.0/pytest.ini
--- old/fake-useragent-1.2.1/pytest.ini 2023-08-02 16:01:31.000000000 +0200
+++ new/fake-useragent-1.4.0/pytest.ini 2023-11-24 22:04:08.000000000 +0100
@@ -1,2 +1,2 @@
 [pytest]
-addopts = -s --strict --keep-duplicates --cache-clear --verbose --maxfail=1 
--no-cov-on-fail --cov=fake_useragent --cov-report=term --cov-report=xml 
--cov-report=html --fulltrace
+addopts = -s --strict-markers --keep-duplicates --cache-clear --verbose 
--maxfail=1 --no-cov-on-fail --cov=fake_useragent --cov-report=term 
--cov-report=xml --cov-report=html --fulltrace
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fake-useragent-1.2.1/requirements.txt 
new/fake-useragent-1.4.0/requirements.txt
--- old/fake-useragent-1.2.1/requirements.txt   2023-08-02 16:01:31.000000000 
+0200
+++ new/fake-useragent-1.4.0/requirements.txt   2023-11-24 22:04:08.000000000 
+0100
@@ -1,35 +1,36 @@
 attrs==23.1.0
-black==23.7.0
-build==0.10.0
-cachetools==5.3.1
+black==23.11.0
+build==1.0.3
+cachetools==5.3.2
 chardet==5.2.0
-click==8.1.6
+click==8.1.7
 colorama==0.4.6
-coverage==7.2.7
+coverage==7.3.2
 distlib==0.3.7
-exceptiongroup==1.1.2
-fastjsonschema==2.18.0
-filelock==3.12.2
+exceptiongroup==1.2.0
+fastjsonschema==2.19.0
+filelock==3.13.1
 importlib-metadata==6.8.0
-importlib-resources==6.0.0
+importlib-resources==6.1.1
 iniconfig==2.0.0
 isort==5.12.0
 mypy-extensions==1.0.0
-packaging==23.1
+packaging==23.2
 pathspec==0.11.2
-pep517==0.13.0
-platformdirs==3.10.0
-pluggy==1.2.0
+pep517==0.13.1
+platformdirs==4.0.0
+pluggy==1.3.0
 py==1.11.0
 pyparsing==3.1.1
-pyproject_api==1.5.3
+pyproject-api==1.6.1
 pyproject_hooks==1.0.0
-pytest==7.4.0
+pytest==7.4.3
 pytest-cov==4.1.0
-ruff==0.0.282
+ruff==0.1.6
 six==1.16.0
 tomli==2.0.1
-tox==4.6.4
-validate-pyproject==0.13
-virtualenv==20.24.2
-zipp==3.16.2
+tox==4.11.3
+typing_extensions==4.8.0
+validate-pyproject==0.15
+virtualenv==20.24.7
+zipp==3.17.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/fake-useragent-1.2.1/src/fake_useragent/data/browsers.json 
new/fake-useragent-1.4.0/src/fake_useragent/data/browsers.json
--- old/fake-useragent-1.2.1/src/fake_useragent/data/browsers.json      
2023-08-02 16:01:31.000000000 +0200
+++ new/fake-useragent-1.4.0/src/fake_useragent/data/browsers.json      
2023-11-24 22:04:08.000000000 +0100
@@ -1,44 +1,52 @@
-{"percent": 22.5, "useragent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36", 
"system": "Chrome 114.0 Win10", "browser": "chrome", "version": 114.0, "os": 
"win10"}
-{"percent": 12.3, "useragent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 
10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 
Safari/537.36", "system": "Chrome 114.0 macOS", "browser": "chrome", "version": 
114.0, "os": "macos"}
-{"percent": 7.9, "useragent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; 
rv:109.0) Gecko/20100101 Firefox/115.0", "system": "Firefox 115.0 Win10", 
"browser": "firefox", "version": 115.0, "os": "win10"}
-{"percent": 7.0, "useragent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36", 
"system": "Chrome 115.0 Win10", "browser": "chrome", "version": 115.0, "os": 
"win10"}
-{"percent": 3.3, "useragent": "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) 
Gecko/20100101 Firefox/115.0", "system": "Firefox 115.0 Linux", "browser": 
"firefox", "version": 115.0, "os": "linux"}
-{"percent": 3.2, "useragent": "Mozilla/5.0 (X11; Linux x86_64) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36", 
"system": "Chrome 114.0 Linux", "browser": "chrome", "version": 114.0, "os": 
"linux"}
-{"percent": 2.7, "useragent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36", 
"system": "Chrome 115.0 macOS", "browser": "chrome", "version": 115.0, "os": 
"macos"}
-{"percent": 2.2, "useragent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; 
rv:109.0) Gecko/20100101 Firefox/114.0", "system": "Firefox 114.0 Win10", 
"browser": "firefox", "version": 114.0, "os": "win10"}
-{"percent": 1.7, "useragent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; 
rv:109.0) Gecko/20100101 Firefox/115.0", "system": "Firefox 115.0 macOS", 
"browser": "firefox", "version": 115.0, "os": "macos"}
-{"percent": 1.5, "useragent": "Mozilla/5.0 (Windows NT 10.0; rv:109.0) 
Gecko/20100101 Firefox/115.0", "system": "Firefox 115.0 Win10", "browser": 
"firefox", "version": 115.0, "os": "win10"}
-{"percent": 1.4, "useragent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 
Edg/114.0.1823.67", "system": "Edge 114.0 Win10", "browser": "edge", "version": 
114.0, "os": "win10"}
-{"percent": 1.3, "useragent": "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) 
Gecko/20100101 Firefox/114.0", "system": "Firefox 114.0 Linux", "browser": 
"firefox", "version": 114.0, "os": "linux"}
-{"percent": 1.2, "useragent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 
Edg/114.0.1823.82", "system": "Edge 114.0 Win10", "browser": "edge", "version": 
114.0, "os": "win10"}
-{"percent": 1.2, "useragent": "Mozilla/5.0 (X11; Linux x86_64) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36", 
"system": "Chrome 115.0 Linux", "browser": "chrome", "version": 115.0, "os": 
"linux"}
-{"percent": 1.2, "useragent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36", 
"system": "Chrome 109.0 Win10", "browser": "chrome", "version": 109.0, "os": 
"win10"}
-{"percent": 1.2, "useragent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; 
rv:109.0) Gecko/20100101 Firefox/115.0", "system": "Firefox 115.0 Linux", 
"browser": "firefox", "version": 115.0, "os": "linux"}
-{"percent": 0.9, "useragent": "Mozilla/5.0 (X11; Linux x86_64; rv:102.0) 
Gecko/20100101 Firefox/102.0", "system": "Firefox 102.0 Linux", "browser": 
"firefox", "version": 102.0, "os": "linux"}
-{"percent": 0.9, "useragent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36 
Edg/115.0.1901.183", "system": "Edge 115.0 Win10", "browser": "edge", 
"version": 115.0, "os": "win10"}
-{"percent": 0.8, "useragent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; 
rv:109.0) Gecko/20100101 Firefox/114.0", "system": "Firefox 114.0 macOS", 
"browser": "firefox", "version": 114.0, "os": "macos"}
-{"percent": 0.6, "useragent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; 
rv:102.0) Gecko/20100101 Firefox/102.0", "system": "Firefox 102.0 Win10", 
"browser": "firefox", "version": 102.0, "os": "win10"}
-{"percent": 0.6, "useragent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36 
Edg/115.0.1901.188", "system": "Edge 115.0 Win10", "browser": "edge", 
"version": 115.0, "os": "win10"}
-{"percent": 0.6, "useragent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36 
OPR/99.0.0.0", "system": "Chrome 113.0 Win10", "browser": "chrome", "version": 
113.0, "os": "win10"}
-{"percent": 0.5, "useragent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 
OPR/100.0.0.0", "system": "Chrome 114.0 Win10", "browser": "chrome", "version": 
114.0, "os": "win10"}
-{"percent": 0.5, "useragent": "Mozilla/5.0 (Windows NT 10.0; rv:114.0) 
Gecko/20100101 Firefox/114.0", "system": "Firefox 114.0 Win10", "browser": 
"firefox", "version": 114.0, "os": "win10"}
-{"percent": 0.5, "useragent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36", 
"system": "Chrome 113.0 Win10", "browser": "chrome", "version": 113.0, "os": 
"win10"}
-{"percent": 0.5, "useragent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 
Edg/114.0.1823.79", "system": "Edge 114.0 Win10", "browser": "edge", "version": 
114.0, "os": "win10"}
-{"percent": 0.5, "useragent": "Mozilla/5.0 (X11; Linux x86_64) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.75 Safari/537.36", 
"system": "Chrome 77.0 Linux", "browser": "chrome", "version": 77.0, "os": 
"linux"}
-{"percent": 0.4, "useragent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; 
rv:109.0) Gecko/20100101 Firefox/116.0", "system": "Firefox 116.0 Win10", 
"browser": "firefox", "version": 116.0, "os": "win10"}
-{"percent": 0.4, "useragent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36", 
"system": "Chrome 111.0 Win10", "browser": "chrome", "version": 111.0, "os": 
"win10"}
-{"percent": 0.4, "useragent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; 
rv:109.0) Gecko/20100101 Firefox/114.0", "system": "Firefox 114.0 Linux", 
"browser": "firefox", "version": 114.0, "os": "linux"}
-{"percent": 0.3, "useragent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36", 
"system": "Chrome 113.0 macOS", "browser": "chrome", "version": 113.0, "os": 
"macos"}
-{"percent": 0.3, "useragent": "Mozilla/5.0 (X11; CrOS x86_64 14541.0.0) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36", 
"system": "Chrome 114.0 ChromeOS", "browser": "chrome", "version": 114.0, "os": 
"chromeos"}
-{"percent": 0.3, "useragent": "Mozilla/5.0 (Windows NT 10.0; rv:102.0) 
Gecko/20100101 Firefox/102.0", "system": "Firefox 102.0 Win10", "browser": 
"firefox", "version": 102.0, "os": "win10"}
-{"percent": 0.3, "useragent": "Mozilla/5.0 (Windows NT 10.0; WOW64; x64) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.5666.197 Safari/537.36", 
"system": "Chrome 113.0 Win10", "browser": "chrome", "version": 113.0, "os": 
"win10"}
-{"percent": 0.2, "useragent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) 
AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.2 Safari/605.1.15", 
"system": "Safari 16.2 macOS", "browser": "safari", "version": 16.2, "os": 
"macos"}
-{"percent": 0.2, "useragent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 
Edg/114.0.1823.58", "system": "Edge 114.0 Win10", "browser": "edge", "version": 
114.0, "os": "win10"}
-{"percent": 0.2, "useragent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36", 
"system": "Chrome 79.0 macOS", "browser": "chrome", "version": 79.0, "os": 
"macos"}
-{"percent": 0.2, "useragent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36", 
"system": "Chrome 108.0 Win10", "browser": "chrome", "version": 108.0, "os": 
"win10"}
+{"percent": 21.4, "useragent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36", 
"system": "Chrome 116.0 Win10", "browser": "chrome", "version": 116.0, "os": 
"win10"}
+{"percent": 9.9, "useragent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36", 
"system": "Chrome 116.0 macOS", "browser": "chrome", "version": 116.0, "os": 
"macos"}
+{"percent": 8.8, "useragent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36", 
"system": "Chrome 117.0 Win10", "browser": "chrome", "version": 117.0, "os": 
"win10"}
+{"percent": 8.7, "useragent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; 
rv:109.0) Gecko/20100101 Firefox/117.0", "system": "Firefox 117.0 Win10", 
"browser": "firefox", "version": 117.0, "os": "win10"}
+{"percent": 4.1, "useragent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36", 
"system": "Chrome 117.0 macOS", "browser": "chrome", "version": 117.0, "os": 
"macos"}
+{"percent": 2.8, "useragent": "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) 
Gecko/20100101 Firefox/117.0", "system": "Firefox 117.0 Linux", "browser": 
"firefox", "version": 117.0, "os": "linux"}
+{"percent": 2.4, "useragent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) 
AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Safari/605.1.15", 
"system": "Safari Generic macOS", "browser": "safari", "version": 1.0, "os": 
"macos"}
+{"percent": 2.4, "useragent": "Mozilla/5.0 (X11; Linux x86_64) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36", 
"system": "Chrome 116.0 Linux", "browser": "chrome", "version": 116.0, "os": 
"linux"}
+{"percent": 2.0, "useragent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; 
rv:109.0) Gecko/20100101 Firefox/117.0", "system": "Firefox 117.0 macOS", 
"browser": "firefox", "version": 117.0, "os": "macos"}
+{"percent": 1.5, "useragent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; 
rv:109.0) Gecko/20100101 Firefox/118.0", "system": "Firefox 118.0 Win10", 
"browser": "firefox", "version": 118.0, "os": "win10"}
+{"percent": 1.5, "useragent": "Mozilla/5.0 (X11; Linux x86_64) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36", 
"system": "Chrome 117.0 Linux", "browser": "chrome", "version": 117.0, "os": 
"linux"}
+{"percent": 1.3, "useragent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; 
rv:109.0) Gecko/20100101 Firefox/117.0", "system": "Firefox 117.0 Linux", 
"browser": "firefox", "version": 117.0, "os": "linux"}
+{"percent": 1.1, "useragent": "Mozilla/5.0 (Windows NT 10.0; rv:109.0) 
Gecko/20100101 Firefox/117.0", "system": "Firefox 117.0 Win10", "browser": 
"firefox", "version": 117.0, "os": "win10"}
+{"percent": 0.9, "useragent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 
Edg/116.0.1938.69", "system": "Edge 116.0 Win10", "browser": "edge", "version": 
116.0, "os": "win10"}
+{"percent": 0.9, "useragent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36", 
"system": "Chrome 109.0 Win10", "browser": "chrome", "version": 109.0, "os": 
"win10"}
+{"percent": 0.8, "useragent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 
OPR/102.0.0.0", "system": "Chrome 116.0 Win10", "browser": "chrome", "version": 
116.0, "os": "win10"}
+{"percent": 0.8, "useragent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36 
OPR/101.0.0.0", "system": "Chrome 115.0 Win10", "browser": "chrome", "version": 
115.0, "os": "win10"}
+{"percent": 0.8, "useragent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 
Edg/116.0.1938.76", "system": "Edge 116.0 Win10", "browser": "edge", "version": 
116.0, "os": "win10"}
+{"percent": 0.7, "useragent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36", 
"system": "Chrome 115.0 macOS", "browser": "chrome", "version": 115.0, "os": 
"macos"}
+{"percent": 0.7, "useragent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36", 
"system": "Chrome 114.0 Win10", "browser": "chrome", "version": 114.0, "os": 
"win10"}
+{"percent": 0.7, "useragent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36 
Edg/117.0.2045.31", "system": "Edge 117.0 Win10", "browser": "edge", "version": 
117.0, "os": "win10"}
+{"percent": 0.7, "useragent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36", 
"system": "Chrome 115.0 Win10", "browser": "chrome", "version": 115.0, "os": 
"win10"}
+{"percent": 0.7, "useragent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 
Edg/116.0.1938.81", "system": "Edge 116.0 Win10", "browser": "edge", "version": 
116.0, "os": "win10"}
+{"percent": 0.6, "useragent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36 
Edg/117.0.2045.36", "system": "Edge 117.0 Win10", "browser": "edge", "version": 
117.0, "os": "win10"}
+{"percent": 0.6, "useragent": "Mozilla/5.0 (X11; Linux x86_64) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36", 
"system": "Chrome 115.0 Linux", "browser": "chrome", "version": 115.0, "os": 
"linux"}
+{"percent": 0.6, "useragent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; 
rv:109.0) Gecko/20100101 Firefox/116.0", "system": "Firefox 116.0 Win10", 
"browser": "firefox", "version": 116.0, "os": "win10"}
+{"percent": 0.6, "useragent": "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) 
Gecko/20100101 Firefox/118.0", "system": "Firefox 118.0 Linux", "browser": 
"firefox", "version": 118.0, "os": "linux"}
+{"percent": 0.5, "useragent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) 
AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15", 
"system": "Safari Generic macOS", "browser": "safari", "version": 1.0, "os": 
"macos"}
+{"percent": 0.5, "useragent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36 
Edg/117.0.2045.43", "system": "Edge 117.0 Win10", "browser": "edge", "version": 
117.0, "os": "win10"}
+{"percent": 0.5, "useragent": "Mozilla/5.0 (X11; Linux x86_64; rv:102.0) 
Gecko/20100101 Firefox/102.0", "system": "Firefox 102.0 Linux", "browser": 
"firefox", "version": 102.0, "os": "linux"}
+{"percent": 0.5, "useragent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; 
rv:109.0) Gecko/20100101 Firefox/118.0", "system": "Firefox 118.0 macOS", 
"browser": "firefox", "version": 118.0, "os": "macos"}
+{"percent": 0.4, "useragent": "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) 
Gecko/20100101 Firefox/116.0", "system": "Firefox 116.0 Linux", "browser": 
"firefox", "version": 116.0, "os": "linux"}
+{"percent": 0.4, "useragent": "Mozilla/5.0 (X11; Linux x86_64) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.75 Safari/537.36", 
"system": "Chrome 77.0 Linux", "browser": "chrome", "version": 77.0, "os": 
"linux"}
+{"percent": 0.4, "useragent": "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) 
Gecko/20100101 Firefox/115.0", "system": "Firefox 115.0 Linux", "browser": 
"firefox", "version": 115.0, "os": "linux"}
+{"percent": 0.4, "useragent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64; 
rv:109.0) Gecko/20100101 Firefox/115.0", "system": "Firefox 115.0 Win7", 
"browser": "firefox", "version": 115.0, "os": "win7"}
+{"percent": 0.4, "useragent": "Mozilla/5.0 (Windows NT 10.0; rv:102.0) 
Gecko/20100101 Firefox/102.0", "system": "Firefox 102.0 Win10", "browser": 
"firefox", "version": 102.0, "os": "win10"}
+{"percent": 0.4, "useragent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; 
rv:109.0) Gecko/20100101 Firefox/116.0", "system": "Firefox 116.0 Linux", 
"browser": "firefox", "version": 116.0, "os": "linux"}
+{"percent": 0.3, "useragent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36", 
"system": "Chrome 114.0 macOS", "browser": "chrome", "version": 114.0, "os": 
"macos"}
+{"percent": 0.3, "useragent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; 
rv:102.0) Gecko/20100101 Firefox/102.0", "system": "Firefox 102.0 Win10", 
"browser": "firefox", "version": 102.0, "os": "win10"}
+{"percent": 0.3, "useragent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36", 
"system": "Chrome 113.0 Win10", "browser": "chrome", "version": 113.0, "os": 
"win10"}
+{"percent": 0.3, "useragent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 
Edg/116.0.1938.62", "system": "Edge 116.0 Win10", "browser": "edge", "version": 
116.0, "os": "win10"}
+{"percent": 0.3, "useragent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; 
rv:109.0) Gecko/20100101 Firefox/115.0", "system": "Firefox 115.0 Win10", 
"browser": "firefox", "version": 115.0, "os": "win10"}
+{"percent": 0.3, "useragent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) 
AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.5.2 Safari/605.1.15", 
"system": "Safari Generic macOS", "browser": "safari", "version": 1.0, "os": 
"macos"}
+{"percent": 0.3, "useragent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36 
Edg/117.0.2045.41", "system": "Edge 117.0 Win10", "browser": "edge", "version": 
117.0, "os": "win10"}
+{"percent": 0.3, "useragent": "Mozilla/5.0 (X11; Linux x86_64) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36", 
"system": "Chrome 114.0 Linux", "browser": "chrome", "version": 114.0, "os": 
"linux"}
+{"percent": 0.3, "useragent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; 
rv:109.0) Gecko/20100101 Firefox/116.0", "system": "Firefox 116.0 macOS", 
"browser": "firefox", "version": 116.0, "os": "macos"}
+{"percent": 0.3, "useragent": "Mozilla/5.0 (Windows NT 10.0; rv:109.0) 
Gecko/20100101 Firefox/118.0", "system": "Firefox 118.0 Win10", "browser": 
"firefox", "version": 118.0, "os": "win10"}
+{"percent": 0.2, "useragent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36", 
"system": "Chrome 109.0 Win7", "browser": "chrome", "version": 109.0, "os": 
"win7"}
+{"percent": 0.2, "useragent": "Mozilla/5.0 (X11; CrOS x86_64 14541.0.0) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36", 
"system": "Chrome 116.0 ChromeOS", "browser": "chrome", "version": 116.0, "os": 
"chromeos"}
 {"percent": 0.2, "useragent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36", 
"system": "Chrome 112.0 Win10", "browser": "chrome", "version": 112.0, "os": 
"win10"}
-{"percent": 0.2, "useragent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36", 
"system": "Chrome 99.0 Win10", "browser": "chrome", "version": 99.0, "os": 
"win10"}
-{"percent": 0.2, "useragent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36", 
"system": "Chrome 112.0 macOS", "browser": "chrome", "version": 112.0, "os": 
"macos"}
-{"percent": 0.2, "useragent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 
Edg/114.0.1823.86", "system": "Edge 114.0 Win10", "browser": "edge", "version": 
114.0, "os": "win10"}
-{"percent": 0.2, "useragent": "Mozilla/5.0 (X11; Linux x86_64) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36", 
"system": "Chrome 112.0 Linux", "browser": "chrome", "version": 112.0, "os": 
"linux"}
-{"percent": 0.2, "useragent": "Mozilla/5.0 (X11; Linux x86_64) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36", 
"system": "Chrome 113.0 Linux", "browser": "chrome", "version": 113.0, "os": 
"linux"}
+{"percent": 0.2, "useragent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) 
AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.4 Safari/605.1.15", 
"system": "Safari Generic macOS", "browser": "safari", "version": 1.0, "os": 
"macos"}
+{"percent": 0.2, "useragent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) 
AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.5 Safari/605.1.15", 
"system": "Safari Generic macOS", "browser": "safari", "version": 1.0, "os": 
"macos"}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fake-useragent-1.2.1/src/fake_useragent/fake.py 
new/fake-useragent-1.4.0/src/fake_useragent/fake.py
--- old/fake-useragent-1.2.1/src/fake_useragent/fake.py 2023-08-02 
16:01:31.000000000 +0200
+++ new/fake-useragent-1.4.0/src/fake_useragent/fake.py 2023-11-24 
22:04:08.000000000 +0100
@@ -22,15 +22,15 @@
         self.browsers = browsers
 
         assert isinstance(os, (list, str)), "OS must be list or string"
-        # OS replacement (windows -> win10)
         if isinstance(os, str):
             os = [os]
-        self.os = [
-            settings.OS_REPLACEMENTS[os_name]
-            if os_name in settings.OS_REPLACEMENTS
-            else os_name
-            for os_name in os
-        ]
+        # OS replacement (windows -> [win10, win7])
+        self.os = []
+        for os_name in os:
+            if os_name in settings.OS_REPLACEMENTS:
+                self.os.extend(settings.OS_REPLACEMENTS[os_name])
+            else:
+                self.os.append(os_name)
 
         assert isinstance(
             min_percentage, float
@@ -55,9 +55,72 @@
         # Next, load our local data file into memory (browsers.json)
         self.data_browsers = load()
 
+    # This method will return an object
+    # Usage: ua.getBrowser('firefox')
+    def getBrowser(self, request):
+        try:
+            # Handle request value
+            for value, replacement in settings.REPLACEMENTS.items():
+                request = request.replace(value, replacement)
+            request = request.lower()
+            request = settings.SHORTCUTS.get(request, request)
+
+            if request == "random":
+                # Filter the browser list based on the browsers array using 
lambda
+                # And based on OS list
+                # And percentage is bigger then min percentage
+                # And convert the iterator back to a list
+                filtered_browsers = list(
+                    filter(
+                        lambda x: x["browser"] in self.browsers
+                        and x["os"] in self.os
+                        and x["percent"] >= self.min_percentage,
+                        self.data_browsers,
+                    )
+                )
+            else:
+                # Or when random isn't select, we filter the browsers array 
based on the 'request' using lamba
+                # And based on OS list
+                # And percentage is bigger then min percentage
+                # And convert the iterator back to a list
+                filtered_browsers = list(
+                    filter(
+                        lambda x: x["browser"] == request
+                        and x["os"] in self.os
+                        and x["percent"] >= self.min_percentage,
+                        self.data_browsers,
+                    )
+                )
+
+            # Pick a random browser user-agent from the filtered browsers
+            # And return the full dict
+            return random.choice(filtered_browsers)  # noqa: S311
+        except (KeyError, IndexError):
+            if self.fallback is None:
+                raise FakeUserAgentError(
+                    f"Error occurred during getting browser: {request}"
+                )  # noqa
+            else:
+                logger.warning(
+                    f"Error occurred during getting browser: {request}, "
+                    "but was suppressed with fallback.",
+                )
+                # Return fallback object
+                return {
+                    "useragent": self.fallback,
+                    "system": "Chrome 114.0 Win10",
+                    "browser": "chrome",
+                    "version": 114.0,
+                    "os": "win10",
+                }
+
+    # This method will use the method below, returning a string
+    # Usage: ua['random']
     def __getitem__(self, attr):
         return self.__getattr__(attr)
 
+    # This method will returns a string
+    # Usage: ua.random
     def __getattr__(self, attr):
         if attr in self.safe_attrs:
             return super(UserAgent, self).__getattr__(attr)
@@ -140,6 +203,27 @@
     def random(self):
         return self.__getattr__("random")
 
+    # The following 'get' methods return an object rather than only the UA 
string
+    @property
+    def getFirefox(self):
+        return self.getBrowser("firefox")
+
+    @property
+    def getChrome(self):
+        return self.getBrowser("chrome")
+
+    @property
+    def getEdge(self):
+        return self.getBrowser("edge")
+
+    @property
+    def getSafari(self):
+        return self.getBrowser("safari")
+
+    @property
+    def getRandom(self):
+        return self.getBrowser("random")
+
 
 # common alias
 UserAgent = FakeUserAgent
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fake-useragent-1.2.1/src/fake_useragent/settings.py 
new/fake-useragent-1.4.0/src/fake_useragent/settings.py
--- old/fake-useragent-1.2.1/src/fake_useragent/settings.py     2023-08-02 
16:01:31.000000000 +0200
+++ new/fake-useragent-1.4.0/src/fake_useragent/settings.py     2023-11-24 
22:04:08.000000000 +0100
@@ -12,7 +12,7 @@
 }
 
 OS_REPLACEMENTS = {
-    "windows": "win10",
+    "windows": ["win10", "win7"],
 }
 
 SHORTCUTS = {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fake-useragent-1.2.1/src/fake_useragent/utils.py 
new/fake-useragent-1.4.0/src/fake_useragent/utils.py
--- old/fake-useragent-1.2.1/src/fake_useragent/utils.py        2023-08-02 
16:01:31.000000000 +0200
+++ new/fake-useragent-1.4.0/src/fake_useragent/utils.py        2023-11-24 
22:04:08.000000000 +0100
@@ -9,19 +9,13 @@
 
 from fake_useragent.log import logger
 
-# Fallback method for retrieving data file
-try:
-    from pkg_resources import resource_filename
-except ImportError:
-    pass
-
 str_types = (str,)
 
 
 # Load all lines from browser.json file
 # Returns array of objects
 def load():
-    data = []
+    data, ret = [], None
     try:
         json_lines = (
             
ilr.files("fake_useragent.data").joinpath("browsers.json").read_text()
@@ -37,6 +31,8 @@
             exc_info=exc,
         )
         try:
+            from pkg_resources import resource_filename
+
             with open(
                 resource_filename("fake_useragent", "data/browsers.json")
             ) as file:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fake-useragent-1.2.1/tests/test_fake.py 
new/fake-useragent-1.4.0/tests/test_fake.py
--- old/fake-useragent-1.2.1/tests/test_fake.py 2023-08-02 16:01:31.000000000 
+0200
+++ new/fake-useragent-1.4.0/tests/test_fake.py 2023-11-24 22:04:08.000000000 
+0100
@@ -28,6 +28,17 @@
         self.assertTrue(ua.random)
         self.assertIsInstance(ua.random, str)
 
+        self.assertTrue(ua.getChrome)
+        self.assertIsInstance(ua.getChrome, dict)
+        self.assertTrue(ua.getEdge)
+        self.assertIsInstance(ua.getEdge, dict)
+        self.assertTrue(ua.getFirefox)
+        self.assertIsInstance(ua.getFirefox, dict)
+        self.assertTrue(ua.getSafari)
+        self.assertIsInstance(ua.getSafari, dict)
+        self.assertTrue(ua.getRandom)
+        self.assertIsInstance(ua.getRandom, dict)
+
     def test_fake_probe_user_agent_browsers(self):
         ua = UserAgent()
         ua.edge  # noqa: B018
@@ -41,6 +52,11 @@
         ua.safari  # noqa: B018
         ua.random  # noqa: B018
         ua["random"]  # noqa: B018
+        ua.getEdge  # noqa: B018
+        ua.getChrome  # noqa: B018
+        ua.getFirefox  # noqa: B018
+        ua.getSafari  # noqa: B018
+        ua.getRandom  # noqa: B018
 
     def test_fake_data_browser_type(self):
         ua = UserAgent()
@@ -53,6 +69,13 @@
         self.assertEqual(ua.non_existing, fallback)
         self.assertEqual(ua["non_existing"], fallback)
 
+    def test_fake_fallback_dictionary(self):
+        fallback = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"
+
+        ua = UserAgent()
+        self.assertIsInstance(ua.getBrowser("non_existing"), dict)
+        self.assertEqual(ua.getBrowser("non_existing").get("useragent"), 
fallback)
+
     def test_fake_fallback_str_types(self):
         with pytest.raises(AssertionError):
             UserAgent(fallback=True)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fake-useragent-1.2.1/tests/test_utils.py 
new/fake-useragent-1.4.0/tests/test_utils.py
--- old/fake-useragent-1.2.1/tests/test_utils.py        2023-08-02 
16:01:31.000000000 +0200
+++ new/fake-useragent-1.4.0/tests/test_utils.py        2023-11-24 
22:04:08.000000000 +0100
@@ -26,6 +26,10 @@
         self.assertIsInstance(data[0], object)
         self.assertIsInstance(data[0]["useragent"], str)
 
+    # https://github.com/python/cpython/issues/95299
+    @unittest.skipIf(
+        sys.version_info >= (3, 12), "not compatible with Python 3.12 (or 
higher)"
+    )
     def test_utils_load_pkg_resource_fallback(self):
         # By default use_local_file is also True during production
         # We will not allow the default importlib resources to be used, by 
triggering an Exception
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fake-useragent-1.2.1/tox.ini 
new/fake-useragent-1.4.0/tox.ini
--- old/fake-useragent-1.2.1/tox.ini    2023-08-02 16:01:31.000000000 +0200
+++ new/fake-useragent-1.4.0/tox.ini    2023-11-24 22:04:08.000000000 +0100
@@ -1,6 +1,6 @@
 [tox]
 envlist =
-    py3{8,9,10,11}
+    py3{8,9,10,11,12}
     pypy3
 isolated_build = True
 skip_missing_interpreters = True

Reply via email to