mrkeyoor.com_
Sat 08 Aug 20:58 UTC
PyPIUtilsupdated 08 Aug 2026

giturlparse

giturlparse is a small, dependency-free Python parser for common Git remote URL shapes. It recognizes HTTPS, HTTP, SSH, SCP-style, and git protocol forms for GitHub, GitLab, Bitbucket, Assembla, and FriendCode-style hosts, then exposes host, owner, repository, groups, port, branch, and path attributes. A parsed result can also rewrite the same repository into supported clone URL forms such as SSH or HTTPS.

Verdict

A convenient parser for the common clone-URL cases, especially when zero dependencies matters. Guard invalid results, strip credentials immediately, and do not trust provider, branch, or path guesses for access control or exact web-URL interpretation.

API stability4/5The public surface is tiny: parse, validate, a dynamic result object, and rewrite properties. The README's core examples still match version 0.15.0, and the package has no dependency churn. Stability is not perfect because output depends on ordered provider regexes, and adding or changing a pattern can change which platform wins for an ambiguous URL without changing the method signatures.
Docs3/5The README lists every exposed attribute and demonstrates parse, rewrite, alternate URLs, and validation in a short page. It does not document failure behavior, the exceptions raised when rewriting an invalid result, ambiguity around branch names containing slashes, how self-hosted domains are classified, credential-redaction responsibilities, or the exact supported URL grammar.
Maintenance4/5PyPI shows version 0.15.0 released in June 2026, and the GitHub repository was pushed in August 2026, so the package is current and not archived. GitHub reports nineteen open items including both issues and pull requests. The maintainer footprint and one-hundred-star repository are small, but a dependency-free regex parser does not require a large release machine.
Ecosystem3/5The package recorded 5,295,752 downloads in the latest measured week and covers the dominant GitHub, GitLab, and Bitbucket clone formats plus several smaller providers. It has no plugin interface, no published typing marker, and no integration layer for provider APIs, so teams needing repository validation, forge metadata, or broad self-hosted support must combine it with other tools.

Use it if

  • You need to normalize user-supplied Git clone URLs before storing or comparing repository identities
  • You accept both SCP-style SSH remotes and ordinary URLs and want one owner and repository extraction path
  • You need quick SSH-to-HTTPS rewriting for known hosting services without invoking Git
  • A pure-Python package with no runtime dependencies is more important than exhaustive forge support or strict URL standards compliance
Skip it if

Setup reality

`pip install giturlparse` is the whole installation: version 0.15.0 requires Python 3.8 or newer and declares no runtime dependencies. The complexity is in deciding what inputs you trust. `parse()` always returns a GitUrlParsed object, even on failure, so check `.valid` before reading rewrite properties; an invalid result never gets the internal platform object that `url2https`, `urls`, and `normalized` require. Domain checking is on by default and helps select the right provider. Turning it off for a self-hosted forge is risky because the first broad regex can win: a Bitbucket-shaped URL can be labeled GitHub, while generic SSH URLs tend to be treated as GitLab. Web browsing URLs are not clone URLs. The package can capture GitHub and GitLab path fragments, but branch names containing slashes make clean separation impossible without a provider API. Rewrites add `.git` and drop embedded HTTPS credentials, which is often desirable but means the result is not a byte-for-byte transformation. Never persist or log `.data`, `.username`, `.access_token`, or the original URL until credentials are removed. There is no built-in redaction helper, URL allowlist, network validation, or check that the repository actually exists.

Patterns

Parse an SCP-style SSH remoteparse-ssh-remote

from giturlparse import parse

remote = parse('git@bitbucket.org:AaronO/some-repo.git')
if not remote.valid:
    raise ValueError('unsupported Git URL')
print(remote.host, remote.owner, remote.repo)

This Git syntax is not a conventional URI, which is the main reason to use a Git-aware parser instead of urllib.parse.

Reject unrecognized inputvalidate-before-use

from giturlparse import validate

if not validate(candidate):
    raise ValueError('Expected a supported Git remote URL')

Validation checks only whether required fields were parsed. It does not make a network request or prove that the repository exists.

Convert a clone URL to HTTPSrewrite-to-https

from giturlparse import parse

remote = parse('git@github.com:octo/example.git')
https_url = remote.url2https if remote.valid else None
print(https_url)

Always test valid first; rewrite properties on an invalid parse can fail because there is no matched platform formatter.

Convert an HTTPS remote to SSHrewrite-to-ssh

from giturlparse import parse

remote = parse('https://github.com/octo/example')
ssh_url = remote.url2ssh
# git@github.com:octo/example.git

The formatter adds .git when missing. It does not check whether SSH access or the repository itself is available.

List supported clone URL variantslist-clone-forms

from giturlparse import parse

remote = parse('https://github.com/octo/example.git')
if remote.valid:
    for protocol, url in remote.urls.items():
        print(protocol, url)

The available keys depend on the matched provider. A result does not necessarily support all of http, https, ssh, and git.

Normalize while keeping the parsed protocolnormalize-remote

from giturlparse import parse

remote = parse('https://github.com/octo/example')
normalized = remote.normalized if remote.valid else None
# https://github.com/octo/example.git

Normalization can add .git and preserve provider-specific path fragments; it is not guaranteed to equal the canonical repository homepage.

Extract nested GitLab groupsread-gitlab-groups

from giturlparse import parse

remote = parse('https://gitlab.com/company/platform/api.git')
print(remote.owner)   # company
print(remote.groups)  # ['platform']
print(remote.repo)    # api

groups is GitLab-specific. For other providers it normally returns an empty list.

Inspect a GitHub blob URLinspect-github-path

from giturlparse import parse

page = parse('https://github.com/octo/example/blob/main/src/app.py')
print(page.repo)      # example
print(page.path)      # main/src/app.py

The path includes the branch segment. The parser leaves branch empty here because slash-containing refs cannot be separated reliably from file paths.

Attempt parsing a self-hosted forgeallow-self-hosted-domain

from giturlparse import parse

remote = parse('ssh://git@git.example.com/team/repo.git', check_domain=False)
if not remote.valid:
    raise ValueError('unrecognized remote')
print(remote.platform, remote.owner, remote.repo)

Disabling domain checks permits broader matches but can guess the wrong provider. Treat platform as a hint and verify allowed hosts separately.

Rewrite a repository under another ownerchange-repository-owner

from giturlparse import parse

remote = parse('https://github.com/old-org/example.git')
remote.owner = 'new-org'
print(remote.url)
# https://github.com/new-org/example.git

The owner setter updates the stored URL using the current protocol; it does not rename or verify anything on the remote host.

Drop credentials before loggingstrip-embedded-credentials

from giturlparse import parse

remote = parse('https://build-user:secret@github.com/octo/example.git')
if not remote.valid:
    raise ValueError('unsupported URL')
safe_url = remote.url2https
print(safe_url)

The original url, username, access_token, and data attributes still contain or expose the secret. Do not log the result object itself.

Create a comparison keybuild-repository-key

from giturlparse import parse

def repository_key(url: str) -> tuple[str, str, str]:
    remote = parse(url)
    if not remote.valid:
        raise ValueError('unsupported Git URL')
    return remote.host.lower(), remote.owner.lower(), remote.repo.removesuffix('.git').lower()

Case sensitivity varies by hosting service. Lowercasing is suitable only if your allowed providers treat repository identities case-insensitively.

Alternatives

PackageRegistryPick it when
git-url-parsePyPIYou want a similarly focused parser and are willing to compare its provider coverage and result model
GitPythonPyPIYou need to inspect real repositories and configured remotes, not just parse URL text
dulwichPyPIYou need a pure-Python Git implementation that can validate or operate on repositories as well as their remotes