We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
S3 automatic backup fails when backup folder is empty
<!--
Welcome to the Frappe Framework issue tracker! Before creating an issue, please heed the following:

1. This tracker should only be used to report bugs and request features / enhancements to Frappe
    - For questions and general support, use https://stackoverflow.com/questions/tagged/frappe
    - For documentation issues, refer to https://frappeframework.com/docs/user/en or the developer cheetsheet https://github.com/frappe/frappe/wiki/Developer-Cheatsheet
2. Use the search function before creating a new issue. Duplicates will be closed and directed to
   the original discussion.
3. When making a bug report, make sure you provide all required information. The easier it is for
   maintainers to reproduce, the faster it'll be fixed.
4. If you think you know what the reason for the bug is, share it with us. Maybe put in a PR 😉
-->

## Description of the issue
`frappe.integrations.doctype.s3_backup_settings.s3_backup_settings.take_backups_s3` fails when the backup folder (site_name/private/backups/) is empty when the function is called. 

This occurs because `frappe.integrations.offsite_backup_utils.get_file_size` does not anticipate a situation where its `file_path` argument is invalid i.e `None`.

This bug affects v13 and v12.

## Context information (for bug reports)

**Output of `bench version`**
```
frappe 12.24.0
```

## Steps to reproduce the issue

1. Delete _all_ files in the backup folder
2. Call `take_backups_s3`
3.

### Observed result
When the scheduled backup task runs, you will receive an email with this kind of stack trace:
```
*Backup Upload Failed!*

Oops, your automated backup to Amazon S3 failed.

Error message: Traceback (most recent call last): File "/home/ubuntu/frappe-bench/apps/frappe/frappe/integrations/doctype/s3_backup_settings/s3_backup_settings.py", line 83, in take_backups_s3 validate_file_size() File "/home/ubuntu/frappe-bench/apps/frappe/frappe/integrations/offsite_backup_utils.py", line 105, in validate_file_size file_size = get_file_size(latest_file, unit="GB") File "/home/ubuntu/frappe-bench/apps/frappe/frappe/integrations/offsite_backup_utils.py", line 75, in get_file_size file_size = os.path.getsize(file_path) File "/usr/lib/python3.7/genericpath.py", line 50, in getsize return os.stat(filename).st_size TypeError: stat: path should be string, bytes, os.PathLike or integer, not NoneType

Please contact your system manager for more information.
```
If you call it in your console, it will fail silently but you will observe that no backup file is created nor uploaded to S3.

### Expected result


### Stacktrace / full error message

```
Traceback (most recent call last): File "/home/ubuntu/frappe-bench/apps/frappe/frappe/integrations/doctype/s3_backup_settings/s3_backup_settings.py", line 83, in take_backups_s3 validate_file_size() File "/home/ubuntu/frappe-bench/apps/frappe/frappe/integrations/offsite_backup_utils.py", line 105, in validate_file_size file_size = get_file_size(latest_file, unit="GB") File "/home/ubuntu/frappe-bench/apps/frappe/frappe/integrations/offsite_backup_utils.py", line 75, in get_file_size file_size = os.path.getsize(file_path) File "/usr/lib/python3.7/genericpath.py", line 50, in getsize return os.stat(filename).st_size TypeError: stat: path should be string, bytes, os.PathLike or integer, not NoneType
```

## Additional information

OS version / distribution, `Frappe` install method, etc.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `frappe/integrations/offsite_backup_utils.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 # Copyright (c) 2019, Frappe Technologies and contributors
3 # License: MIT. See LICENSE
4 
5 import frappe
6 import glob
7 import os
8 from frappe.utils import split_emails, cint
9 
10 def send_email(success, service_name, doctype, email_field, error_status=None):
11 	recipients = get_recipients(doctype, email_field)
12 	if not recipients:
13 		frappe.log_error(
14 			"No Email Recipient found for {0}".format(service_name),
15 			"{0}: Failed to send backup status email".format(service_name),
16 		)
17 		return
18 
19 	if success:
20 		if not frappe.db.get_single_value(doctype, "send_email_for_successful_backup"):
21 			return
22 
23 		subject = "Backup Upload Successful"
24 		message = """
25 <h3>Backup Uploaded Successfully!</h3>
26 <p>Hi there, this is just to inform you that your backup was successfully uploaded to your {0} bucket. So relax!</p>""".format(
27 			service_name
28 		)
29 	else:
30 		subject = "[Warning] Backup Upload Failed"
31 		message = """
32 <h3>Backup Upload Failed!</h3>
33 <p>Oops, your automated backup to {0} failed.</p>
34 <p>Error message: {1}</p>
35 <p>Please contact your system manager for more information.</p>""".format(
36 			service_name, error_status
37 		)
38 
39 	frappe.sendmail(recipients=recipients, subject=subject, message=message)
40 
41 
42 def get_recipients(doctype, email_field):
43 	if not frappe.db:
44 		frappe.connect()
45 
46 	return split_emails(frappe.db.get_value(doctype, None, email_field))
47 
48 
49 def get_latest_backup_file(with_files=False):
50 	from frappe.utils.backups import BackupGenerator
51 
52 	odb = BackupGenerator(
53 		frappe.conf.db_name,
54 		frappe.conf.db_name,
55 		frappe.conf.db_password,
56 		db_host=frappe.db.host,
57 		db_type=frappe.conf.db_type,
58 		db_port=frappe.conf.db_port,
59 	)
60 	database, public, private, config = odb.get_recent_backup(older_than=24 * 30)
61 
62 	if with_files:
63 		return database, config, public, private
64 
65 	return database, config
66 
67 
68 def get_file_size(file_path, unit):
69 	if not unit:
70 		unit = "MB"
71 
72 	file_size = os.path.getsize(file_path)
73 
74 	memory_size_unit_mapper = {"KB": 1, "MB": 2, "GB": 3, "TB": 4}
75 	i = 0
76 	while i < memory_size_unit_mapper[unit]:
77 		file_size = file_size / 1000.0
78 		i += 1
79 
80 	return file_size
81 
82 def get_chunk_site(file_size):
83 	''' this function will return chunk size in megabytes based on file size '''
84 
85 	file_size_in_gb = cint(file_size/1024/1024)
86 
87 	MB = 1024 * 1024
88 	if file_size_in_gb > 5000:
89 		return 200 * MB
90 	elif file_size_in_gb >= 3000:
91 		return 150 * MB
92 	elif file_size_in_gb >= 1000:
93 		return 100 * MB
94 	elif file_size_in_gb >= 500:
95 		return 50 * MB
96 	else:
97 		return 15 * MB
98 
99 def validate_file_size():
100 	frappe.flags.create_new_backup = True
101 	latest_file, site_config = get_latest_backup_file()
102 	file_size = get_file_size(latest_file, unit="GB")
103 
104 	if file_size > 1:
105 		frappe.flags.create_new_backup = False
106 
107 def generate_files_backup():
108 	from frappe.utils.backups import BackupGenerator
109 
110 	backup = BackupGenerator(frappe.conf.db_name, frappe.conf.db_name,
111 		frappe.conf.db_password, db_host = frappe.db.host,
112 		db_type=frappe.conf.db_type, db_port=frappe.conf.db_port)
113 
114 	backup.set_backup_file_name()
115 	backup.zip_files()
116
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/frappe/integrations/offsite_backup_utils.py b/frappe/integrations/offsite_backup_utils.py
--- a/frappe/integrations/offsite_backup_utils.py
+++ b/frappe/integrations/offsite_backup_utils.py
@@ -65,10 +65,7 @@
 	return database, config
 
 
-def get_file_size(file_path, unit):
-	if not unit:
-		unit = "MB"
-
+def get_file_size(file_path, unit='MB'):
 	file_size = os.path.getsize(file_path)
 
 	memory_size_unit_mapper = {"KB": 1, "MB": 2, "GB": 3, "TB": 4}
@@ -99,7 +96,7 @@
 def validate_file_size():
 	frappe.flags.create_new_backup = True
 	latest_file, site_config = get_latest_backup_file()
-	file_size = get_file_size(latest_file, unit="GB")
+	file_size = get_file_size(latest_file, unit="GB") if latest_file else 0
 
 	if file_size > 1:
 		frappe.flags.create_new_backup = False

{"golden_diff": "diff --git a/frappe/integrations/offsite_backup_utils.py b/frappe/integrations/offsite_backup_utils.py\n--- a/frappe/integrations/offsite_backup_utils.py\n+++ b/frappe/integrations/offsite_backup_utils.py\n@@ -65,10 +65,7 @@\n \treturn database, config\n \n \n-def get_file_size(file_path, unit):\n-\tif not unit:\n-\t\tunit = \"MB\"\n-\n+def get_file_size(file_path, unit='MB'):\n \tfile_size = os.path.getsize(file_path)\n \n \tmemory_size_unit_mapper = {\"KB\": 1, \"MB\": 2, \"GB\": 3, \"TB\": 4}\n@@ -99,7 +96,7 @@\n def validate_file_size():\n \tfrappe.flags.create_new_backup = True\n \tlatest_file, site_config = get_latest_backup_file()\n-\tfile_size = get_file_size(latest_file, unit=\"GB\")\n+\tfile_size = get_file_size(latest_file, unit=\"GB\") if latest_file else 0\n \n \tif file_size > 1:\n \t\tfrappe.flags.create_new_backup = False\n", "issue": "S3 automatic backup fails when backup folder is empty\n<!--\r\nWelcome to the Frappe Framework issue tracker! Before creating an issue, please heed the following:\r\n\r\n1. This tracker should only be used to report bugs and request features / enhancements to Frappe\r\n    - For questions and general support, use https://stackoverflow.com/questions/tagged/frappe\r\n    - For documentation issues, refer to https://frappeframework.com/docs/user/en or the developer cheetsheet https://github.com/frappe/frappe/wiki/Developer-Cheatsheet\r\n2. Use the search function before creating a new issue. Duplicates will be closed and directed to\r\n   the original discussion.\r\n3. When making a bug report, make sure you provide all required information. The easier it is for\r\n   maintainers to reproduce, the faster it'll be fixed.\r\n4. If you think you know what the reason for the bug is, share it with us. Maybe put in a PR \ud83d\ude09\r\n-->\r\n\r\n## Description of the issue\r\n`frappe.integrations.doctype.s3_backup_settings.s3_backup_settings.take_backups_s3` fails when the backup folder (site_name/private/backups/) is empty when the function is called. \r\n\r\nThis occurs because `frappe.integrations.offsite_backup_utils.get_file_size` does not anticipate a situation where its `file_path` argument is invalid i.e `None`.\r\n\r\nThis bug affects v13 and v12.\r\n\r\n## Context information (for bug reports)\r\n\r\n**Output of `bench version`**\r\n```\r\nfrappe 12.24.0\r\n```\r\n\r\n## Steps to reproduce the issue\r\n\r\n1. Delete _all_ files in the backup folder\r\n2. Call `take_backups_s3`\r\n3.\r\n\r\n### Observed result\r\nWhen the scheduled backup task runs, you will receive an email with this kind of stack trace:\r\n```\r\n*Backup Upload Failed!*\r\n\r\nOops, your automated backup to Amazon S3 failed.\r\n\r\nError message: Traceback (most recent call last): File \"/home/ubuntu/frappe-bench/apps/frappe/frappe/integrations/doctype/s3_backup_settings/s3_backup_settings.py\", line 83, in take_backups_s3 validate_file_size() File \"/home/ubuntu/frappe-bench/apps/frappe/frappe/integrations/offsite_backup_utils.py\", line 105, in validate_file_size file_size = get_file_size(latest_file, unit=\"GB\") File \"/home/ubuntu/frappe-bench/apps/frappe/frappe/integrations/offsite_backup_utils.py\", line 75, in get_file_size file_size = os.path.getsize(file_path) File \"/usr/lib/python3.7/genericpath.py\", line 50, in getsize return os.stat(filename).st_size TypeError: stat: path should be string, bytes, os.PathLike or integer, not NoneType\r\n\r\nPlease contact your system manager for more information.\r\n```\r\nIf you call it in your console, it will fail silently but you will observe that no backup file is created nor uploaded to S3.\r\n\r\n### Expected result\r\n\r\n\r\n### Stacktrace / full error message\r\n\r\n```\r\nTraceback (most recent call last): File \"/home/ubuntu/frappe-bench/apps/frappe/frappe/integrations/doctype/s3_backup_settings/s3_backup_settings.py\", line 83, in take_backups_s3 validate_file_size() File \"/home/ubuntu/frappe-bench/apps/frappe/frappe/integrations/offsite_backup_utils.py\", line 105, in validate_file_size file_size = get_file_size(latest_file, unit=\"GB\") File \"/home/ubuntu/frappe-bench/apps/frappe/frappe/integrations/offsite_backup_utils.py\", line 75, in get_file_size file_size = os.path.getsize(file_path) File \"/usr/lib/python3.7/genericpath.py\", line 50, in getsize return os.stat(filename).st_size TypeError: stat: path should be string, bytes, os.PathLike or integer, not NoneType\r\n```\r\n\r\n## Additional information\r\n\r\nOS version / distribution, `Frappe` install method, etc.\r\n\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n# Copyright (c) 2019, Frappe Technologies and contributors\n# License: MIT. See LICENSE\n\nimport frappe\nimport glob\nimport os\nfrom frappe.utils import split_emails, cint\n\ndef send_email(success, service_name, doctype, email_field, error_status=None):\n\trecipients = get_recipients(doctype, email_field)\n\tif not recipients:\n\t\tfrappe.log_error(\n\t\t\t\"No Email Recipient found for {0}\".format(service_name),\n\t\t\t\"{0}: Failed to send backup status email\".format(service_name),\n\t\t)\n\t\treturn\n\n\tif success:\n\t\tif not frappe.db.get_single_value(doctype, \"send_email_for_successful_backup\"):\n\t\t\treturn\n\n\t\tsubject = \"Backup Upload Successful\"\n\t\tmessage = \"\"\"\n<h3>Backup Uploaded Successfully!</h3>\n<p>Hi there, this is just to inform you that your backup was successfully uploaded to your {0} bucket. So relax!</p>\"\"\".format(\n\t\t\tservice_name\n\t\t)\n\telse:\n\t\tsubject = \"[Warning] Backup Upload Failed\"\n\t\tmessage = \"\"\"\n<h3>Backup Upload Failed!</h3>\n<p>Oops, your automated backup to {0} failed.</p>\n<p>Error message: {1}</p>\n<p>Please contact your system manager for more information.</p>\"\"\".format(\n\t\t\tservice_name, error_status\n\t\t)\n\n\tfrappe.sendmail(recipients=recipients, subject=subject, message=message)\n\n\ndef get_recipients(doctype, email_field):\n\tif not frappe.db:\n\t\tfrappe.connect()\n\n\treturn split_emails(frappe.db.get_value(doctype, None, email_field))\n\n\ndef get_latest_backup_file(with_files=False):\n\tfrom frappe.utils.backups import BackupGenerator\n\n\todb = BackupGenerator(\n\t\tfrappe.conf.db_name,\n\t\tfrappe.conf.db_name,\n\t\tfrappe.conf.db_password,\n\t\tdb_host=frappe.db.host,\n\t\tdb_type=frappe.conf.db_type,\n\t\tdb_port=frappe.conf.db_port,\n\t)\n\tdatabase, public, private, config = odb.get_recent_backup(older_than=24 * 30)\n\n\tif with_files:\n\t\treturn database, config, public, private\n\n\treturn database, config\n\n\ndef get_file_size(file_path, unit):\n\tif not unit:\n\t\tunit = \"MB\"\n\n\tfile_size = os.path.getsize(file_path)\n\n\tmemory_size_unit_mapper = {\"KB\": 1, \"MB\": 2, \"GB\": 3, \"TB\": 4}\n\ti = 0\n\twhile i < memory_size_unit_mapper[unit]:\n\t\tfile_size = file_size / 1000.0\n\t\ti += 1\n\n\treturn file_size\n\ndef get_chunk_site(file_size):\n\t''' this function will return chunk size in megabytes based on file size '''\n\n\tfile_size_in_gb = cint(file_size/1024/1024)\n\n\tMB = 1024 * 1024\n\tif file_size_in_gb > 5000:\n\t\treturn 200 * MB\n\telif file_size_in_gb >= 3000:\n\t\treturn 150 * MB\n\telif file_size_in_gb >= 1000:\n\t\treturn 100 * MB\n\telif file_size_in_gb >= 500:\n\t\treturn 50 * MB\n\telse:\n\t\treturn 15 * MB\n\ndef validate_file_size():\n\tfrappe.flags.create_new_backup = True\n\tlatest_file, site_config = get_latest_backup_file()\n\tfile_size = get_file_size(latest_file, unit=\"GB\")\n\n\tif file_size > 1:\n\t\tfrappe.flags.create_new_backup = False\n\ndef generate_files_backup():\n\tfrom frappe.utils.backups import BackupGenerator\n\n\tbackup = BackupGenerator(frappe.conf.db_name, frappe.conf.db_name,\n\t\tfrappe.conf.db_password, db_host = frappe.db.host,\n\t\tdb_type=frappe.conf.db_type, db_port=frappe.conf.db_port)\n\n\tbackup.set_backup_file_name()\n\tbackup.zip_files()\n", "path": "frappe/integrations/offsite_backup_utils.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n# Copyright (c) 2019, Frappe Technologies and contributors\n# License: MIT. See LICENSE\n\nimport frappe\nimport glob\nimport os\nfrom frappe.utils import split_emails, cint\n\ndef send_email(success, service_name, doctype, email_field, error_status=None):\n\trecipients = get_recipients(doctype, email_field)\n\tif not recipients:\n\t\tfrappe.log_error(\n\t\t\t\"No Email Recipient found for {0}\".format(service_name),\n\t\t\t\"{0}: Failed to send backup status email\".format(service_name),\n\t\t)\n\t\treturn\n\n\tif success:\n\t\tif not frappe.db.get_single_value(doctype, \"send_email_for_successful_backup\"):\n\t\t\treturn\n\n\t\tsubject = \"Backup Upload Successful\"\n\t\tmessage = \"\"\"\n<h3>Backup Uploaded Successfully!</h3>\n<p>Hi there, this is just to inform you that your backup was successfully uploaded to your {0} bucket. So relax!</p>\"\"\".format(\n\t\t\tservice_name\n\t\t)\n\telse:\n\t\tsubject = \"[Warning] Backup Upload Failed\"\n\t\tmessage = \"\"\"\n<h3>Backup Upload Failed!</h3>\n<p>Oops, your automated backup to {0} failed.</p>\n<p>Error message: {1}</p>\n<p>Please contact your system manager for more information.</p>\"\"\".format(\n\t\t\tservice_name, error_status\n\t\t)\n\n\tfrappe.sendmail(recipients=recipients, subject=subject, message=message)\n\n\ndef get_recipients(doctype, email_field):\n\tif not frappe.db:\n\t\tfrappe.connect()\n\n\treturn split_emails(frappe.db.get_value(doctype, None, email_field))\n\n\ndef get_latest_backup_file(with_files=False):\n\tfrom frappe.utils.backups import BackupGenerator\n\n\todb = BackupGenerator(\n\t\tfrappe.conf.db_name,\n\t\tfrappe.conf.db_name,\n\t\tfrappe.conf.db_password,\n\t\tdb_host=frappe.db.host,\n\t\tdb_type=frappe.conf.db_type,\n\t\tdb_port=frappe.conf.db_port,\n\t)\n\tdatabase, public, private, config = odb.get_recent_backup(older_than=24 * 30)\n\n\tif with_files:\n\t\treturn database, config, public, private\n\n\treturn database, config\n\n\ndef get_file_size(file_path, unit='MB'):\n\tfile_size = os.path.getsize(file_path)\n\n\tmemory_size_unit_mapper = {\"KB\": 1, \"MB\": 2, \"GB\": 3, \"TB\": 4}\n\ti = 0\n\twhile i < memory_size_unit_mapper[unit]:\n\t\tfile_size = file_size / 1000.0\n\t\ti += 1\n\n\treturn file_size\n\ndef get_chunk_site(file_size):\n\t''' this function will return chunk size in megabytes based on file size '''\n\n\tfile_size_in_gb = cint(file_size/1024/1024)\n\n\tMB = 1024 * 1024\n\tif file_size_in_gb > 5000:\n\t\treturn 200 * MB\n\telif file_size_in_gb >= 3000:\n\t\treturn 150 * MB\n\telif file_size_in_gb >= 1000:\n\t\treturn 100 * MB\n\telif file_size_in_gb >= 500:\n\t\treturn 50 * MB\n\telse:\n\t\treturn 15 * MB\n\ndef validate_file_size():\n\tfrappe.flags.create_new_backup = True\n\tlatest_file, site_config = get_latest_backup_file()\n\tfile_size = get_file_size(latest_file, unit=\"GB\") if latest_file else 0\n\n\tif file_size > 1:\n\t\tfrappe.flags.create_new_backup = False\n\ndef generate_files_backup():\n\tfrom frappe.utils.backups import BackupGenerator\n\n\tbackup = BackupGenerator(frappe.conf.db_name, frappe.conf.db_name,\n\t\tfrappe.conf.db_password, db_host = frappe.db.host,\n\t\tdb_type=frappe.conf.db_type, db_port=frappe.conf.db_port)\n\n\tbackup.set_backup_file_name()\n\tbackup.zip_files()\n", "path": "frappe/integrations/offsite_backup_utils.py"}]}