{"id":31756739,"url":"https://github.com/ebay/pyjami","last_synced_at":"2025-10-09T19:22:56.049Z","repository":{"id":63872508,"uuid":"546901811","full_name":"eBay/pyjami","owner":"eBay","description":"Python library which helps to automate the migration of Java classes/enums/interfaces.","archived":false,"fork":false,"pushed_at":"2024-12-16T01:58:54.000Z","size":298,"stargazers_count":4,"open_issues_count":8,"forks_count":3,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-09-21T23:55:04.840Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://opensource.ebay.com/pyjami/pyjami/java_symbol_migration_helpers.html","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/eBay.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2022-10-06T20:50:43.000Z","updated_at":"2024-09-20T16:59:13.000Z","dependencies_parsed_at":"2023-12-29T10:25:38.193Z","dependency_job_id":"ea95a516-bc8a-4f36-a438-81d5c84d0665","html_url":"https://github.com/eBay/pyjami","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/eBay/pyjami","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eBay%2Fpyjami","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eBay%2Fpyjami/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eBay%2Fpyjami/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eBay%2Fpyjami/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/eBay","download_url":"https://codeload.github.com/eBay/pyjami/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eBay%2Fpyjami/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279001978,"owners_count":26083243,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-09T02:00:07.460Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-10-09T19:22:53.516Z","updated_at":"2025-10-09T19:22:56.043Z","avatar_url":"https://github.com/eBay.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# **Py**thon-based **Ja**va code **mi**gration helper (Pyjami)\n[![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit\u0026logoColor=white)](https://github.com/pre-commit/pre-commit)\n[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)\n[![Code Coverage](coverage.svg)](https://github.com/dbrgn/coverage-badge)\n[![CodeQL](https://github.com/ebay/pyjami/workflows/CodeQL/badge.svg)](https://github.com/ebay/pyjami/actions?query=workflow%3ACodeQL)\n[![PyPI version](https://badge.fury.io/py/pyjami.svg)](https://badge.fury.io/py/pyjami)\n[![HitCount](https://hits.dwyl.com/ebay/pyjami.svg?style=flat)](http://hits.dwyl.com/ebay/pyjami)\n\nPython library which helps to automate the migration of Java classes/enums/interfaces.\n\n## Scenario\n\nWhen would you want to use this?\n\nYou have a Java project. You want to migrate 99+ classes/enums/interfaces in it. Let's say it contains a `com.foo.bar.MyClass`, and you want to replace all its usages with those of `org.example.newPackage.MyClass`.\n\nYour first instinct is a **find-and-replace**, but you'd have to deal with [wildcard imports](https://www.baeldung.com/java-wildcard-imports) and partially-qualified references at each level of the package.\n\nYou thought of **IntelliJ IDEA**. It offers a `Refactor` \u003e `Migrate Packages and Classes` feature, but:\n* You have a more **complicated mapping** to specify. Perhaps you want to migrate `lorem.Foo` to `ipsum.Foo`, but for `lorem.Bar`, you want to migrate it to `dolor.Bar`. To do so in IntelliJ IDEA, you'd have to manually punch in each mapping rule.\n* You don't want to migrate all of them in **one transaction**. Maybe you want to run unit tests after migrating each, committing the changes to a separate revision only if the tests all pass. IntelliJ IDEA doesn't offer such fine-grained control.\n* Or you simply can't use / would avoid IntelliJ IDEA for some reason.\n\nThat's when this toolkit comes to help.\n\n## Usage\n\n### Migrate one symbol\nPlease ensure that you've installed these executable programs:\n\n* `gnu-sed` (installed by default on most Linux distros; a manual step on macOS). This is because the BSD edition of `sed` does not support word boundaries (\"`\\b`\").\n* [`ripgrep`](https://github.com/BurntSushi/ripgrep), a line-oriented search tool that recursively searches the current directory for a regex pattern.\n\nTo migrate usages of `com.foo.bar.MyClass` to `org.example.newPackage.MyClass`, use `migrate(...)` in `java_symbol_migration_helpers.py`:\n\n```python\nfrom pathlib import Path\nfrom pyjami.java_symbol_migration_helpers import find_suitable_sed_command, migrate\nmigrate(\n    symbol=\"MyClass\",\n    path=\"src/main/com/foo/bar\",\n    old_package=\"com.foo.bar\",\n    new_package=\"org.example.newPackage\",\n    repo_dir=Path(\"repo/\"),\n    pom_dependency=\"\"\"\n        \u003cdependency\u003e\n            \u003c!-- New home for MyClass. --\u003e\n            \u003cgroupId\u003eorg.example\u003c/groupId\u003e\n            \u003cartifactId\u003enewPackage\u003c/artifactId\u003e\n        \u003c/dependency\u003e\n    \"\"\",\n    sed_executable=find_suitable_sed_command(),\n)\n```\n\n### Gather information for a list of symbols to migrate\n\nWe provide a `make_table()` function that gathers information about the symbols that are required in the migration process to follow.\n\nGiven an iterable (preferably a Pandas Series) of string, each of which being a symbol to migrate, this function returns a Pandas Dataframe with each line indicating the name, the java file path, and the package name of that symbol in the given directory.\n\nFor example, if you have `MyProject/Lorem.java` containing:\n\n```java\npackage com.example.MyProject;\n\nclass Lorem {...}\n```\n\nand you run:\n\n```python\nmake_table(\n    symbols_to_migrate=(\"Lorem\",),\n    search_within_directory=pathlib.Path(\"MyProject/\"),\n)\n```\n\nyou will get a table with one row of these values:\n\n- `symbol`: `Lorem`\n- `path`: `MyProject/Lorem.java`\n- `package`: `com.example.MyProject`\n\nThese are the required information to feed into `migrate()`.\n\nIn the case that multiple file paths are found for a given symbol, the first file path that is a child of the firstmost entry in `order_of_preference` is taken. When none is present, it's treated as if no file path is found for this symbol. Therefore, even if you don't have a preference of which directories to favor, you might still want to provide `order_of_preference` with at least a `search_within_directory`, so that at least some choice is taken.\n\n### Extra -- Sorting Components in an OpenAPI Contract\n\nThis is a common scenario to encounter when migrating handwritten Java code to a library generated from OpenAPI contract. In fact, this is the original case that kicked off this project.\n\nTherefore, Pyjami also provides tools that specifically help with OpenAPI migrations. For example, `sort_components_in_contract.py` sorts components (data models) in an OpenAPI contract YAML file topologically, so that you can migrate with confidence.\n\nSuppose your OpenAPI contract declares 2 components, `Pet` and `Pets`, with `Pets` referencing (\"depending on\") `Pet`:\n```yaml\nopenapi: \"3.0.0\"\ncomponents:\n  schemas:\n    Pet:\n      type: object\n    Pets:\n      type: array\n      items:\n        $ref: \"#/components/schemas/Pet\"\n```\n\nYou can get the optimal order to migrate these symbols using `sort_symbols(...)`:\n\n```python\n\u003e\u003e\u003e from pyjami.sort_components_in_contract import sort_symbols\n\u003e\u003e\u003e sort_symbols(\"contract.yaml\")\n(\"Pet\", \"Pets\")\n```\n\nThis ensures that, by the time you attempt to migrate `class Pets`, `class Pet` has already been migrated. This is particularly useful if you want to ensure that the migration of every single symbol should keep the unit tests intact.\n\n## Development\n\nThis repository uses [Poetry](https://python-poetry.org/) for managing dependencies and packaging.\n\n### Documentation\n\nRefer to `docs/index.html` for documentation. It's also published as GitHub pages [here](https://opensource.ebay.com/pyjami/pyjami/java_symbol_migration_helpers.html).\n\nPyjami's documentation is generated via the [`pdoc`](https://pdoc.dev/docs/pdoc.html) tool:\n\n```shell\npdoc ./pyjami -o ./docs\n```\n\n### Pre-Commit Hooks\n\nThe hooks are required for the team. Although skipping this step does not prevent you from making a commit, this step is critical in maintaining a uniform coding style across developers.\n\nFrom now on, whenever you make a new commit, you should see logs like this in your terminal:\n\n```\nCheck Yaml...............................................................Passed\nFix End of Files.........................................................Passed\nTrim Trailing Whitespace.................................................Passed\nblack....................................................................Passed\n```\n\nIf you see [Black](https://github.com/psf/black) failed and modified files:\n\n```\nCheck Yaml...............................................................Passed\nFix End of Files.........................................................Passed\nTrim Trailing Whitespace.................................................Passed\nblack....................................................................Failed\n- hook id: black\n- files were modified by this hook\n\nreformatted path/to/file.py\nAll done! ✨ 🍰 ✨\n1 file reformatted.\n```\n\nThen `git add` the auto-modified files and retry your `git commit` command.\n\nPlease report a bug if you do not see such messages.\n\n### Testing\n\nThis project uses [`pytest`](https://docs.pytest.org/) for running tests and [`pytest-cov`](https://pytest-cov.readthedocs.io/en/latest/) for collecting test coverage information.\n\nTo run the tests, run:\n\n```shell\npytest --cov=pyjami\n```\n\nYou'll see a report like this:\n\n```\n---------- coverage: platform darwin, python 3.10.6-final-0 ----------\nName                                      Stmts   Miss  Cover\n-------------------------------------------------------------\npyjami/__init__.py                            0      0   100%\npyjami/java_symbol_migration_helpers.py     150     18    88%\npyjami/sort_components_in_contract.py        53      8    85%\n-------------------------------------------------------------\nTOTAL                                       203     26    87%\n```\n\nThen, you can update the coverage badge:\n\n```shell\ncoverage-badge -o coverage.svg\n```\n\n### Releasing\n\nThis library is available as a package on PyPI [here](https://pypi.org/project/pyjami/). To release a new version:\n\n1. Bump the version number in `pyproject.toml` with a commit. Please follow [Semantic Versioning 2.0.0](https://semver.org/) specifications.\n2. Create a new release on GitHub [here](https://github.com/eBay/pyjami/releases).\n\nA GitHub workflow will be automatically triggered to build \u0026 publish this package to PyPI. Till eBay have an official account on PyPI, this action will keep on using a _PyPI API Token_ associated with Ming's personal PyPI account. The Token is stored on this GitHub repository as an Action Secret.\n\n# License\n\nApache 2.0.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Febay%2Fpyjami","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Febay%2Fpyjami","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Febay%2Fpyjami/lists"}