GeezerVison is showing github.com — chore: remove custom URL encoding · python-gitlab/python-gitlab@d99848c
File treeExpand file treeCollapse file tree Open diff view settings Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: gitlab/mixins.py +3-3Lines changed: 3 additions & 3 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -100,7 +100,7 @@ def get( | 100 | 100 | GitlabGetError: If the server cannot perform the request | 101 | 101 | """ | 102 | 102 | if not isinstance(id, int): | 103 | | - id = utils.clean_str_id(id) | | 103 | + id = utils.url_encode(id) | 104 | 104 | path = f"{self.path}/{id}" | 105 | 105 | if TYPE_CHECKING: | 106 | 106 | assert self._obj_cls is not None | @@ -444,7 +444,7 @@ def set(self, key: str, value: str, **kwargs: Any) -> base.RESTObject: | 444 | 444 | Returns: | 445 | 445 | The created/updated attribute | 446 | 446 | """ | 447 | | - path = f"{self.path}/{utils.clean_str_id(key)}" | | 447 | + path = f"{self.path}/{utils.url_encode(key)}" | 448 | 448 | data = {"value": value} | 449 | 449 | server_data = self.gitlab.http_put(path, post_data=data, **kwargs) | 450 | 450 | if TYPE_CHECKING: | @@ -478,7 +478,7 @@ def delete(self, id: Union[str, int], **kwargs: Any) -> None: | 478 | 478 | path = self.path | 479 | 479 | else: | 480 | 480 | if not isinstance(id, int): | 481 | | - id = utils.clean_str_id(id) | | 481 | + id = utils.url_encode(id) | 482 | 482 | path = f"{self.path}/{id}" | 483 | 483 | self.gitlab.http_delete(path, **kwargs) | 484 | 484 |
| |
Collapse file Copy file name to clipboardExpand all lines: gitlab/utils.py +20-3Lines changed: 20 additions & 3 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 15 | 15 | # You should have received a copy of the GNU Lesser General Public License | 16 | 16 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | 17 | 17 |
| | 18 | +import urllib.parse | 18 | 19 | from typing import Any, Callable, Dict, Optional | 19 | | -from urllib.parse import quote | 20 | 20 |
| 21 | 21 | import requests | 22 | 22 |
| @@ -56,8 +56,25 @@ def copy_dict(dest: Dict[str, Any], src: Dict[str, Any]) -> None: | 56 | 56 | dest[k] = v | 57 | 57 |
| 58 | 58 |
| 59 | | -def clean_str_id(id: str) -> str: | 60 | | - return quote(id, safe="") | | 59 | +def url_encode(id: str) -> str: | | 60 | + """Encode/quote the characters in the string so that they can be used in a path. | | 61 | +
| | 62 | + Reference to documentation on why this is necessary. | | 63 | +
| | 64 | + https://docs.gitlab.com/ee/api/index.html#namespaced-path-encoding | | 65 | +
| | 66 | + If using namespaced API requests, make sure that the NAMESPACE/PROJECT_PATH is | | 67 | + URL-encoded. For example, / is represented by %2F | | 68 | +
| | 69 | + https://docs.gitlab.com/ee/api/index.html#path-parameters | | 70 | +
| | 71 | + Path parameters that are required to be URL-encoded must be followed. If not, it | | 72 | + doesn’t match an API endpoint and responds with a 404. If there’s something in front | | 73 | + of the API (for example, Apache), ensure that it doesn’t decode the URL-encoded path | | 74 | + parameters. | | 75 | +
| | 76 | + """ | | 77 | + return urllib.parse.quote(id, safe="") | 61 | 78 |
| 62 | 79 |
| 63 | 80 | def remove_none_from_dict(data: Dict[str, Any]) -> Dict[str, Any]: | |
Collapse file Copy file name to clipboardExpand all lines: gitlab/v4/objects/features.py +2-1Lines changed: 2 additions & 1 deletion | Original file line number | Diff line number | Diff line change |
|---|
@@ -52,7 +52,8 @@ def set( | 52 | 52 | Returns: | 53 | 53 | The created/updated attribute | 54 | 54 | """ | 55 | | - path = f"{self.path}/{name.replace('/', '%2F')}" | | 55 | + name = utils.url_encode(name) | | 56 | + path = f"{self.path}/{name}" | 56 | 57 | data = { | 57 | 58 | "value": value, | 58 | 59 | "feature_group": feature_group, | |
Collapse file Copy file name to clipboardExpand all lines: gitlab/v4/objects/files.py +8-7Lines changed: 8 additions & 7 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -56,7 +56,7 @@ def save( # type: ignore | 56 | 56 | """ | 57 | 57 | self.branch = branch | 58 | 58 | self.commit_message = commit_message | 59 | | - self.file_path = self.file_path.replace("/", "%2F") | | 59 | + self.file_path = utils.url_encode(self.file_path) | 60 | 60 | super(ProjectFile, self).save(**kwargs) | 61 | 61 |
| 62 | 62 | @exc.on_http_error(exc.GitlabDeleteError) | @@ -76,7 +76,7 @@ def delete( # type: ignore | 76 | 76 | GitlabAuthenticationError: If authentication is not correct | 77 | 77 | GitlabDeleteError: If the server cannot perform the request | 78 | 78 | """ | 79 | | - file_path = self.get_id().replace("/", "%2F") | | 79 | + file_path = utils.url_encode(self.get_id()) | 80 | 80 | self.manager.delete(file_path, branch, commit_message, **kwargs) | 81 | 81 |
| 82 | 82 |
| @@ -144,7 +144,7 @@ def create( | 144 | 144 | assert data is not None | 145 | 145 | self._check_missing_create_attrs(data) | 146 | 146 | new_data = data.copy() | 147 | | - file_path = new_data.pop("file_path").replace("/", "%2F") | | 147 | + file_path = utils.url_encode(new_data.pop("file_path")) | 148 | 148 | path = f"{self.path}/{file_path}" | 149 | 149 | server_data = self.gitlab.http_post(path, post_data=new_data, **kwargs) | 150 | 150 | if TYPE_CHECKING: | @@ -173,7 +173,7 @@ def update( # type: ignore | 173 | 173 | """ | 174 | 174 | new_data = new_data or {} | 175 | 175 | data = new_data.copy() | 176 | | - file_path = file_path.replace("/", "%2F") | | 176 | + file_path = utils.url_encode(file_path) | 177 | 177 | data["file_path"] = file_path | 178 | 178 | path = f"{self.path}/{file_path}" | 179 | 179 | self._check_missing_update_attrs(data) | @@ -203,7 +203,8 @@ def delete( # type: ignore | 203 | 203 | GitlabAuthenticationError: If authentication is not correct | 204 | 204 | GitlabDeleteError: If the server cannot perform the request | 205 | 205 | """ | 206 | | - path = f"{self.path}/{file_path.replace('/', '%2F')}" | | 206 | + file_path = utils.url_encode(file_path) | | 207 | + path = f"{self.path}/{file_path}" | 207 | 208 | data = {"branch": branch, "commit_message": commit_message} | 208 | 209 | self.gitlab.http_delete(path, query_data=data, **kwargs) | 209 | 210 |
| @@ -238,7 +239,7 @@ def raw( | 238 | 239 | Returns: | 239 | 240 | The file content | 240 | 241 | """ | 241 | | - file_path = file_path.replace("/", "%2F").replace(".", "%2E") | | 242 | + file_path = utils.url_encode(file_path) | 242 | 243 | path = f"{self.path}/{file_path}/raw" | 243 | 244 | query_data = {"ref": ref} | 244 | 245 | result = self.gitlab.http_get( | @@ -265,7 +266,7 @@ def blame(self, file_path: str, ref: str, **kwargs: Any) -> List[Dict[str, Any]] | 265 | 266 | Returns: | 266 | 267 | A list of commits/lines matching the file | 267 | 268 | """ | 268 | | - file_path = file_path.replace("/", "%2F").replace(".", "%2E") | | 269 | + file_path = utils.url_encode(file_path) | 269 | 270 | path = f"{self.path}/{file_path}/blame" | 270 | 271 | query_data = {"ref": ref} | 271 | 272 | result = self.gitlab.http_list(path, query_data, **kwargs) | |
Collapse file Copy file name to clipboardExpand all lines: gitlab/v4/objects/repositories.py +1-1Lines changed: 1 addition & 1 deletion | Original file line number | Diff line number | Diff line change |
|---|
@@ -39,7 +39,7 @@ def update_submodule( | 39 | 39 | GitlabPutError: If the submodule could not be updated | 40 | 40 | """ | 41 | 41 |
| 42 | | - submodule = submodule.replace("/", "%2F") # .replace('.', '%2E') | | 42 | + submodule = utils.url_encode(submodule) | 43 | 43 | path = f"/projects/{self.get_id()}/repository/submodules/{submodule}" | 44 | 44 | data = {"branch": branch, "commit_sha": commit_sha} | 45 | 45 | if "commit_message" in kwargs: | |
Collapse file Copy file name to clipboardExpand all lines: tests/unit/test_utils.py +9-4Lines changed: 9 additions & 4 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 18 | 18 | from gitlab import utils | 19 | 19 |
| 20 | 20 |
| 21 | | -def test_clean_str_id(): | | 21 | +def test_url_encode(): | 22 | 22 | src = "nothing_special" | 23 | 23 | dest = "nothing_special" | 24 | | - assert dest == utils.clean_str_id(src) | | 24 | + assert dest == utils.url_encode(src) | 25 | 25 |
| 26 | 26 | src = "foo#bar/baz/" | 27 | 27 | dest = "foo%23bar%2Fbaz%2F" | 28 | | - assert dest == utils.clean_str_id(src) | | 28 | + assert dest == utils.url_encode(src) | 29 | 29 |
| 30 | 30 | src = "foo%bar/baz/" | 31 | 31 | dest = "foo%25bar%2Fbaz%2F" | 32 | | - assert dest == utils.clean_str_id(src) | | 32 | + assert dest == utils.url_encode(src) | | 33 | + | | 34 | + # periods/dots should not be modified | | 35 | + src = "docs/README.md" | | 36 | + dest = "docs%2FREADME.md" | | 37 | + assert dest == utils.url_encode(src) |
|