├── .travis.yml
├── CHANGELOG.md
├── CONTRIBUTING.md
├── Dockerfile-py2.7
├── LICENSE
├── QtPyConvert_CLA_Corporate.md
├── QtPyConvert_CLA_Individual.md
├── README.md
├── _resources
└── logo.gif
├── requirements.txt
├── src
├── bin
│ ├── qresource_convert
│ └── qt_py_convert
└── python
│ └── qt_py_convert
│ ├── __init__.py
│ ├── _modules
│ ├── __init__.py
│ ├── expand_stars
│ │ ├── __init__.py
│ │ └── process.py
│ ├── from_imports
│ │ ├── __init__.py
│ │ └── process.py
│ ├── imports
│ │ ├── __init__.py
│ │ └── process.py
│ ├── psep0101
│ │ ├── __init__.py
│ │ ├── _c_args.py
│ │ ├── _conversion_methods.py
│ │ ├── _qsignal.py
│ │ └── process.py
│ └── unsupported
│ │ ├── __init__.py
│ │ └── process.py
│ ├── color.py
│ ├── diff.py
│ ├── general.py
│ ├── log.py
│ ├── mappings.py
│ └── run.py
└── tests
├── test_core
├── __init__.py
├── test_binding_supported.py
└── test_replacements.py
├── test_psep0101
├── __init__.py
├── test_qsignal.py
└── test_qvariant.py
└── test_qtcompat
├── __init__.py
└── test_compatibility_members.py
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: python
2 |
3 | sudo: required
4 | dist: trusty
5 |
6 | python:
7 | - 2.7
8 | # - 3.5
9 |
10 | services:
11 | - docker
12 |
13 | install:
14 | - docker build -f Dockerfile-py${TRAVIS_PYTHON_VERSION} -t digitaldomain/qt_py_convert .
15 |
16 | # Enable virtual framebuffer, this way we can instantiate
17 | # a QApplication and create widgets.
18 | # https://docs.travis-ci.com/user/gui-and-headless-browsers/
19 | before_script:
20 | - "export DISPLAY=:99.0"
21 | - "sh -e /etc/init.d/xvfb start"
22 | - sleep 3 # give xvfb some time to start
23 |
24 | script:
25 | - docker run --rm -v $(pwd):/QtPyConvert digitaldomain/qt_py_convert
26 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 | All notable changes to `qt_py_convert` are documented in this file.
3 |
4 | The `qt_py_convert` package adheres to [Semantic Versioning](http://semver.org/).
5 |
6 |
7 |
23 |
24 |
25 | ## [Unreleased]
26 |
27 | [Nothing yet]
28 |
29 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | ## Contributing to QtPyConvert
2 |
3 | Thanks for taking the time to contribute!
4 |
5 | In here you'll find a series of guidelines for how you can make QtPyConvert better suit your needs and the needs of the target audience - film, games and tv.
6 |
7 | QtPyConvert was born to help companies with large legacy codebases convert their code in a timely manner and also to help the industry standardize on [Qt.py](https://github.com.mottosso/Qt.py).
8 |
9 | **Table of contents**
10 |
11 | - [Development goals](#development-goals)
12 | - [Converting Binding Support](#converting-binding-support)
13 | - [Incompatibility Warnings](#incompatibility-warnings)
14 | - [Keep it simple](#keep-it-simple)
15 | - [Normalize Imports](#normalize-imports)
16 | - [How can I contribute?](#how-can-i-contribute)
17 | - [Reporting Bugs](#reporting-bugs)
18 | - [Suggesting Enhancements](#suggesting-enhancements)
19 | - [Your First Code Contribution](#your-first-code-contribution)
20 | - [Pull Requests](#pull-requests)
21 | - [Style](#style)
22 | - [Commits](#commits)
23 | - [Version bumping](#version-bumping)
24 | - [Making a release](#making-a-release)
25 |
26 |
27 |
28 | ### Development Goals
29 |
30 | QtPyConvert aims to help in the conversion of old Qt for Python code by automating the large majority of the work for you. It does this efficiently by leaving much of the work up to the Qt.py developers and using the resulting abstraction layer as a guideline and framework.
31 |
32 |
33 | Convert any code using any of the four major Qt for Python bindings into the standardized [Qt.py abstraction layer](https://github.com/mottosso/Qt.py).
34 |
35 | Warn users about incompatibilities or unsupported code. (WIP)
36 |
37 | Standardize Qt imports to maintain sanity in code comprehension.
38 | > Removing start imports and deep class/module imports
39 |
40 |
41 | | Goal | Description
42 | |:---------------------------|:---------------
43 | | [*Convert code from any of the four major bindings.*](#converting-binding-support) | We should support everything that Qt.py does.
44 | | [*Warn about incompatibilities.*](#incompatibility-warnings) | If code cannot be converted or functionality is unsupported in Qt.py, we should warn.
45 | | [*Keep it simple*](#keep-it-simple) | Limit the heavy lifting, PEP008.
46 | | [*Normalize import format*](#normalize-imports) | Imports should be *sane* and normalized..
47 |
48 | Each of these deserve some explanation and rationale.
49 |
50 |
51 |
52 | ##### Converting Binding Support
53 |
54 | Running QtPyConvert should work on any source file, even if it doesn't use any Qt code. It should also have first party support for any bindings that Qt.py supports. Additional support for custom bindings either developed inhouse or online see pycode.qt, should have a way to be defined either through environment variables or a supplimentary site package that we look for.
55 |
56 |
57 |
58 | ##### Incompatibility Warnings
59 |
60 | Several patterns are unsupported using Qt.py, these include but are not limited to **QVariants**, **QStrings**, and other Api-1.0 code. These should either be automatically converted, or at the very least, printed out as a warning that the user can look into themselves.
61 | Ideally, it would be good to let users know about deprecated Qt code and provide a flag to attempt converting this as well.
62 |
63 | ##### Keep it simple
64 |
65 | QtPyConvert is mainly a conversion wrapper around Qt.py.
66 | It tries to read what Qt.py is doing by looking at it's private values.
67 |
68 | Ideally we don't want QtPyConvert doing much conversion logic related to the actual mapping of methods and classes.
69 | Instead, we want to pay attention to api1.0 to api2.0 problems, Qt4 to Qt5 deprecation problems and to a certain extent, the Qt.py QtCompat changes.
70 |
71 |
72 |
73 | ##### Normalize Imports
74 |
75 | One of the design decisions that was made early on was to normalize all Qt imports.
76 | This was partially due to preference and partially to step around the complications that would arise from keeping all of the deep level imports.
77 |
78 | ```python
79 | # *Wrong*
80 | from PyQt4.QtCore import Qt
81 | from PyQt4.QtGui import QCheckBox as chk
82 | from PyQt4.QtCore.Qt import Unchecked, Checked
83 |
84 | def click(state):
85 | print("Foo!")
86 |
87 | c = chk()
88 | c.clicked.stateChanged(click, Qt.QueuedConnection)
89 | c.setCheckState(UnChecked)
90 | ```
91 | ```python
92 | # *Right*
93 | from Qt import QtCore, QtWidgets
94 |
95 | def click(state):
96 | print("Foo!")
97 |
98 | c = QtWidgets.QCheckBox()
99 | c.clicked.stateChanged(click, QtCore.Qt.QueuedConnection)
100 | c.setCheckState(QtCore.Qt.UnChecked)
101 | ```
102 |
103 | This is one of the most notable *opinions* that QtPyConvert will enforce upon your code.
104 | Another notable one that it will enforce is shown below
105 | ```python
106 | from PyQt4.QtGui import *
107 | from PyQt4.QtCore import *
108 | from PyQt4.QtCore.Qt import *
109 |
110 | app = QApplication([])
111 | app.setLayoutDirection(RightToLeft)
112 | widget = QWidget()
113 | widget.show()
114 | app.exec_()
115 | ```
116 |
117 | ```python
118 | from Qt import QtWidgets, QtCore
119 |
120 | app = QtWidgets.QApplication([])
121 | app.setLayoutDirection(QtCore.Qt.RightToLeft)
122 | widget = QtWidgets.QWidget()
123 | widget.show()
124 | app.exec_()
125 | ```
126 |
127 | It is bad practice to use star imports and unless you tell it not to, QtPyConvert will resolve your imports and pare them down.
128 |
129 |
130 |
131 | ## How can I contribute?
132 |
133 | Contribution comes in many flavors, some of which is simply notifying us of problems or successes, so we know what to change and not to change.
134 |
135 | ### Contributor License Agreement
136 |
137 | Before contributing code to QtPyConvert, we ask that you sign a Contributor License Agreement (CLA). At the root of the repo you can find the two possible CLAs:
138 |
139 | - QtPyConvert_CLA_Corporate.md: please sign this one for corporate use
140 | - QtPyConvert_CLA_Individual.md: please sign this one if you're an individual contributor
141 |
142 | Once your CLA is signed, send it to opensource@d2.com (please make sure to include your github username) and wait for confirmation that we've received it. After that, you can submit pull requests.
143 |
144 |
145 | ### Reporting bugs
146 |
147 | Bug reports must include:
148 |
149 | 1. Description
150 | 2. Expected results
151 | 3. Short reproducible
152 |
153 | ### Suggesting enhancements
154 |
155 | Feature requests must include:
156 |
157 | 1. Goal (what the feature aims to solve)
158 | 2. Motivation (why *you* think this is necessary)
159 | 3. Suggested implementation (pseudocode)
160 |
161 | Questions may also be submitted as issues.
162 |
163 | ### Pull requests
164 |
165 | Code contributions are made by (1) forking this project and (2) making a modification to it. Ideally we would prefer it preceded by an issue where we discuss the feature or problem on a conceptual level before attempting an implementation of it.
166 |
167 | This is where we perform code review - where we take a moment to look through and discuss potential design decisions made towards the goal you aim.
168 |
169 | Your code will be reviewed and merged once it:
170 |
171 | 1. Does something useful
172 | 1. Provides a use case and example
173 | 1. Includes tests to exercise the change
174 | 1. Is up to par with surrounding code
175 |
176 | The parent project ever only contains a single branch, a branch containing the latest working version of the project.
177 |
178 | We understand and recognise that "forking" and "pull-requests" can be a daunting aspect for a beginner, so don't hesitate to ask. A pull-request should normally follow an issue where you elaborate on your desires; this is also a good place to ask about these things.
179 |
180 |
181 |
182 | ## Style
183 |
184 | Here's how we expect your code to look and feel like.
185 |
186 | ### Commits
187 |
188 | Commits should be well contained, as small as possible (but no smaller) and its messages should be in present-tense, imperative-style.
189 |
190 | E.g.
191 |
192 | ```bash
193 | # No
194 | Changed this and did that
195 |
196 | # No
197 | Changes this and does that
198 |
199 | # Yes
200 | Change this and do that
201 | ```
202 |
203 | The reason is that, each commit is like an action. An event. And it is perfectly possible to "cherry-pick" a commit onto any given branch. In this style, it makes more sense what exactly the commit will do to your code.
204 |
205 | - Cherry pick "Add this and remove that"
206 | - Cherry pick "Remove X and replace with Y"
207 |
208 | ### Version bumping
209 |
210 | This project uses [semantic versioning](http://semver.org/) and is updated *after* a new release has been made.
211 |
212 | For example, if the project had 100 commits at the time of the latest release and has 103 commits now, then it's time to increment. If however you modify the project and it has not yet been released, then your changes are included in the overall next release.
213 |
214 | The goal is to make a new release per increment.
215 |
216 | ### Making a Release
217 |
218 | Once the project has gained features, had bugs sorted out and is in a relatively stable state, it's time to make a new release.
219 |
220 | - [https://github.com/DigitalDomain/QtPyConvert/releases](https://github.com/DigitalDomain/QtPyConvert/releases)
221 |
222 | Each release should come with:
223 |
224 | - An short summary of what has changed.
225 | - A full changelog, including links to resolved issues.
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 | Good luck and see you soon!
234 |
235 |
236 |
237 |
238 |
--------------------------------------------------------------------------------
/Dockerfile-py2.7:
--------------------------------------------------------------------------------
1 | FROM ubuntu:16.04
2 |
3 |
4 | RUN apt-get update && \
5 | apt-get install -y \
6 | software-properties-common && \
7 | add-apt-repository -y ppa:thopiekar/pyside-git && \
8 | apt-get update && apt-get install -y \
9 | python \
10 | python-dev \
11 | python-pip \
12 | python-qt4 \
13 | python-pyqt5 \
14 | python-pyside \
15 | python-pyside2 \
16 | xvfb
17 |
18 | # Nose is the Python test-runner
19 | # RUN pip install -r /QtPyConvert/requirements.txt
20 |
21 | # Enable additional output from Qt.py
22 | ENV QT_VERBOSE true
23 |
24 | # Xvfb
25 | ENV DISPLAY :99
26 | ENV PYTHONPATH="${PYTHONPATH}:/workspace/QtPyConvert/src/python"
27 |
28 | WORKDIR /workspace/QtPyConvert/src/python
29 | ENTRYPOINT cp -r /QtPyConvert /workspace && \
30 | Xvfb :99 -screen 0 1024x768x16 2>/dev/null & \
31 | sleep 3 && \
32 | pip install -r /workspace/QtPyConvert/requirements.txt && \
33 | python /workspace/QtPyConvert/tests/test_core/test_binding_supported.py && \
34 | python /workspace/QtPyConvert/tests/test_core/test_replacements.py && \
35 | python /workspace/QtPyConvert/tests/test_psep0101/test_qsignal.py && \
36 | python /workspace/QtPyConvert/tests/test_psep0101/test_qvariant.py && \
37 | python /workspace/QtPyConvert/tests/test_qtcompat/test_compatibility_members.py
38 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | # Copyright 2018 Digital Domain 3.0
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "Apache License")
4 | # with the following modification; you may not use this file except in
5 | # compliance with the Apache License and the following modification to it:
6 | # Section 6. Trademarks. is deleted and replaced with:
7 | #
8 | # 6. Trademarks. This License does not grant permission to use the trade
9 | # names, trademarks, service marks, or product names of the Licensor
10 | # and its affiliates, except as required to comply with Section 4(c) of
11 | # the License and to reproduce the content of the NOTICE file.
12 | #
13 | # You may obtain a copy of the Apache License at
14 | #
15 | # http://www.apache.org/licenses/LICENSE-2.0
16 | #
17 | # Unless required by applicable law or agreed to in writing, software
18 | # distributed under the Apache License with the above modification is
19 | # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20 | # KIND, either express or implied. See the Apache License for the specific
21 | # language governing permissions and limitations under the Apache License.
--------------------------------------------------------------------------------
/QtPyConvert_CLA_Corporate.md:
--------------------------------------------------------------------------------
1 | QtPyConvert
2 | Digial Domain 3.0
3 |
4 | Software Grant and Corporate Contributor License Agreement ("Agreement")
5 |
6 | Thank you for your interest in the QtPyConvert Project ("Project"), a Digital Domain 3.0 open source initiative. In order to clarify the intellectual property license granted with Contributions from any person or entity, Digital Domain 3.0 must have a Contributor License Agreement ("CLA" or "Agreement") on file that has been signed by each Contributor, indicating agreement to the license terms below.
7 |
8 | This CLA is modified from the Apache CLA found here: http://www.apache.org/licenses.
9 |
10 | This license is for your protection as a Contributor as well as the protection of Digital Domain 3.0 and its users; it does not change your rights to use your own Contributions for any other purpose. This version of the Agreement allows an entity (the "Corporation") to submit Contributions to Digital Domain 3.0, to authorize Contributions by its designated employees to Digital Domain 3.0, and to grant copyright and patent licenses thereto.
11 |
12 | If you have not already done so, please complete and sign, then scan and email a pdf file of this Agreement to opensource@d2.com. If necessary, send an original signed Agreement to:
13 |
14 | Digial Domain 3.0
15 | Attn: The QtPyConvert Project
16 | 12641 Beatrice Street
17 | Los Angeles, CA 90066
18 | U.S.A.
19 |
20 | Please read this document carefully before signing and keep a copy for your records.
21 |
22 | Corporation name: ________________________________________________
23 | Corporation address: ________________________________________________ ________________________________________________
24 | ________________________________________________
25 | Point of Contact: ________________________________________________
26 | E-Mail: ________________________________________________
27 | Telephone: ________________________________________________
28 |
29 | You accept and agree to the following terms and conditions for Your present and future Contributions submitted to Digital Domain 3.0. Except for the license granted herein to Digital Domain 3.0 and recipients of software distributed by Digital Domain 3.0, You reserve all right, title, and interest in and to Your Contributions.
30 |
31 | 1. Definitions.
32 | "You" (or "Your") shall mean the copyright owner or legal entity authorized by the copyright owner that is making this Agreement with Digital Domain 3.0. For legal entities, the entity making a Contribution and all other entities that control, are controlled by, or are under common control with that entity are considered to be a single Contributor. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
33 | "Contribution" shall mean the code, documentation or other original works of authorship expressly identified in Schedule B, as well as any original work of authorship, including any modifications or additions to an existing work, that is intentionally submitted by You to Digital Domain 3.0 for inclusion in, or documentation of, any of the products owned or managed by Digital Domain 3.0 (the "Work"). For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to Digital Domain 3.0 or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, Digital Domain 3.0 for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by You as "Not a Contribution".
34 |
35 | 2. Grant of Copyright License. Subject to the terms and conditions of this Agreement, You hereby grant to Digital Domain 3.0 and to recipients of software distributed by Digital Domain 3.0 a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute Your Contributions and such derivative works.
36 |
37 | 3. Grant of Patent License. Subject to the terms and conditions of this Agreement, You hereby grant to Digital Domain 3.0 and to recipients of software distributed by Digital Domain 3.0 a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer Your Contribution(s) and the Work, where such license applies only to those patent claims licensable by You that are necessarily infringed by Your Contribution(s) alone or by combination of Your Contribution(s) with the Work to which such Contribution(s) was submitted. If any entity institutes patent litigation against You or any other entity (including a cross-claim or counterclaim in a lawsuit) alleging that your Contribution, or the Work to which you have contributed, constitutes direct or contributory patent infringement, then any patent licenses granted to that entity under this Agreement for that Contribution or Work shall terminate as of the date such litigation is filed.
38 |
39 | 4. You represent that You are legally entitled to grant the above license. You represent further that each employee of the Corporation designated on Schedule A below (or in a subsequent written modification to that Schedule) is authorized to submit Contributions on behalf of the Corporation.
40 |
41 | 5. You represent that each of Your Contributions is Your original creation (see section 7 for submissions on behalf of others).
42 |
43 | 6. You are not expected to provide support for Your Contributions, except to the extent You desire to provide support. You may provide support for free, for a fee, or not at all. Unless required by applicable law or agreed to in writing, You provide Your Contributions on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE.
44 |
45 | 7. Should You wish to submit work that is not Your original creation, You may submit it to Digital Domain 3.0 separately from any Contribution, identifying the complete details of its source and of any license or other restriction (including, but not limited to, related patents, trademarks, and license agreements) of which you are personally aware, and conspicuously marking the work as "Submitted on behalf of a third-party: [named here\]."
46 |
47 | 8. It is your responsibility to notify Digital Domain 3.0 when any change is required to the list of designated employees authorized to submit Contributions on behalf of the Corporation, or to the Corporation's Point of Contact with Digital Domain 3.0.
48 |
49 | 9. This Agreement DOES NOT grant permission to use the trade names, trademarks, service marks, content or product names of Digital Domain 3.0 and its affiliates, or any other contributor to the Project.
50 |
51 | Please sign: __________________________________ Date: _______________
52 | Title: __________________________________
53 | Corporation: __________________________________
54 |
55 | Schedule A
56 | [Initial list of designated employees. NB: authorization is not tied to particular Contributions.\]
57 |
58 | Schedule B
59 | [Identification of optional concurrent software grant. Would be left blank or omitted if there is no concurrent software grant.\]
60 |
--------------------------------------------------------------------------------
/QtPyConvert_CLA_Individual.md:
--------------------------------------------------------------------------------
1 | QtPyConvert
2 | Digial Domain 3.0
3 |
4 | Individual Contributor License Agreement ("Agreement") V2.0
5 |
6 | Thank you for your interest in the QtPyConvert Project (the "Project"), a Digial Domain 3.0 open source initiative. In order to clarify the intellectual property license granted with Contributions from any person or entity, Digial Domain 3.0 must have a Contributor License Agreement ("CLA" or "Agreement") on file that has been signed by each Contributor, indicating agreement to the license terms below.
7 |
8 | This CLA is modified from the Apache CLA found here: http://www.apache.org/licenses.
9 |
10 | This license is for your protection as a Contributor as well as the protection of Digial Domain 3.0 and its users; it does not change your rights to use your own Contributions for any other purpose. If you have not already done so, please complete and sign, then scan and email a pdf file of this Agreement to opensource@d2.com. If necessary, send an original signed Agreement to:
11 |
12 | Digial Domain 3.0
13 | Attn: The QtPyConvert Project
14 | 12641 Beatrice Street
15 | Los Angeles, CA 90066
16 | U.S.A.
17 |
18 | Please read this document carefully before signing and keep a copy for your records.
19 |
20 | Full name: _______________________________________________________
21 | Mailing Address: _________________________________________________
22 | _________________________________________________
23 | Country: _________________________________________________________
24 | Telephone: _______________________________________________________
25 | E-Mail: __________________________________________________________
26 |
27 | You accept and agree to the following terms and conditions for Your present and future Contributions submitted to Digial Domain 3.0. Except for the license granted herein to Digial Domain 3.0 and recipients of software distributed by Digial Domain 3.0, You reserve all right, title, and interest in and to Your Contributions.
28 |
29 | 1. Definitions.
30 | "You" (or "Your") shall mean the copyright owner or legal entity authorized by the copyright owner that is making this Agreement with Digial Domain 3.0. For legal entities, the entity making a Contribution and all other entities that control, are controlled by, or are under common control with that entity are considered to be a single Contributor. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
31 | "Contribution" shall mean any original work of authorship, including any modifications or additions to an existing work, that is intentionally submitted by You to Digial Domain 3.0 for inclusion in, or documentation of, any of the products owned or managed by Digial Domain 3.0 (the "Work"). For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to Digial Domain 3.0 or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, Digial Domain 3.0 for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by You as "Not a Contribution."
32 |
33 | 2. Grant of Copyright License. Subject to the terms and conditions of this Agreement, You hereby grant to Digial Domain 3.0 and to recipients of software distributed by Digial Domain 3.0 a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute Your Contributions and such derivative works.
34 |
35 | 3. Grant of Patent License. Subject to the terms and conditions of this Agreement, You hereby grant to Digial Domain 3.0 and to recipients of software distributed by Digial Domain 3.0 a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer Your Contribution(s) and the Work, where such license applies only to those patent claims licensable by You that are necessarily infringed by Your Contribution(s) alone or by combination of Your Contribution(s) with the Work to which such Contribution(s) was submitted. If any entity institutes patent litigation against You or any other entity (including a cross-claim or counterclaim in a lawsuit) alleging that your Contribution, or the Work to which you have contributed, constitutes direct or contributory patent infringement, then any patent licenses granted to that entity under this Agreement for that Contribution or Work shall terminate as of the date such litigation is filed.
36 |
37 | 4. You represent that you are legally entitled to grant the above license. If your employer(s) has rights to intellectual property that you create that includes your Contributions, you represent that you have received permission to make Contributions on behalf of that employer, that your employer has waived such rights for your Contributions to Digial Domain 3.0, or that your employer has executed a separate Corporate CLA with Digial Domain 3.0.
38 |
39 | 5. You represent that each of Your Contributions is Your original creation (see section 7 for submissions on behalf of others). You represent that Your Contribution submissions include complete details of any third-party license or other restriction (including, but not limited to, related patents and trademarks) of which you are personally aware and which are associated with any part of Your Contributions.
40 |
41 | 6. You are not expected to provide support for Your Contributions, except to the extent You desire to provide support. You may provide support for free, for a fee, or not at all. Unless required by applicable law or agreed to in writing, You provide Your Contributions on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE.
42 |
43 | 7. Should You wish to submit work that is not Your original creation, You may submit it to Digial Domain 3.0 separately from any Contribution, identifying the complete details of its source and of any license or other restriction (including, but not limited to, related patents, trademarks, and license agreements) of which you are personally aware, and conspicuously marking the work as "Submitted on behalf of a third-party: [named here\]".
44 |
45 | 8. You agree to notify Digial Domain 3.0 of any facts or circumstances of which you become aware that would make these representations inaccurate in any respect.
46 |
47 | 9. This Agreement DOES NOT grant permission to use the trade names, trademarks, service marks, content or product names of Digial Domain 3.0 and its affiliates, or any other contributor to the Project.
48 |
49 |
50 | Please sign: __________________________________ Date: ________________
51 |
52 |
53 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # QtPyConvert
3 |
4 | * [Project Goals](#project-goals)
5 | * [Getting Started](#getting-started)
6 | * [Prerequisites](#prerequisites)
7 | * [Usage](#usage)
8 | * [Customization](#customization)
9 | * [Converting](#converting)
10 | * [Project Information](#project-information)
11 | * [Built With](#built-with)
12 | * [Contributing](#contributing)
13 | * [Versioning](#versioning)
14 | * [Authors](#authors)
15 | * [License](#license)
16 | * [Acknowledgments](#acknowledgments)
17 |
18 |
19 |
20 |
21 | An automatic Python Qt binding transpiler to the [Qt.py abstraction layer](https://github.com/mottosso/Qt.py). It aims to help in your modernization of your Python Qt code. QtPyConvert supports the following bindings out of the box:
22 | * [PyQt4](https://www.riverbankcomputing.com/software/pyqt/download)
23 | * [PySide](http://pyside.github.io/docs/pyside/)
24 | * [PyQt5](https://www.riverbankcomputing.com/software/pyqt/download5)
25 | * [PySide2](https://wiki.qt.io/PySide2)
26 |
27 | It also has experimental support for defining your own bindings.
28 | > See [customization](#customization) for more information
29 |
30 |
31 | ## Project Goals
32 | Convert any code using any of the four major Qt for Python bindings into the standardized [Qt.py abstraction layer](https://github.com/mottosso/Qt.py).
33 |
34 | Warn users about incompatibilities or unsupported code. (WIP)
35 |
36 | Standardize Qt imports to maintain sanity in code comprehension.
37 | > Removing start imports and deep class/module imports
38 |
39 | ## Getting Started
40 |
41 | When using **QtPyConvert**, developers should be aware of any [shortcomings](https://github.com/mottosso/Qt.py/blob/master/CAVEATS.md) of Qt.py or its [subset](https://github.com/mottosso/Qt.py#subset-or-common-members) of [supported features](https://github.com/mottosso/Qt.py#class-specific-compatibility-objects).
42 |
43 | Basically read the README in the Qt.py project and be aware of what it does and does not do.
44 |
45 | ### Prerequisites
46 |
47 | **QtPyConvert** reads the private values of the [Qt.py project](https://github.com/mottosso/Qt.py) to build it's internal conversion processes. To install this run
48 | ```
49 | pip install Qt.py
50 | ```
51 | **QtPyConvert** also uses [RedBaron](https://github.com/PyCQA/Redbaron) as an alternate abstract syntax tree.
52 | Redbaron allows us to modify the source code and write it back out again, preserving all comments and formatting.
53 | ```
54 | pip install redbaron
55 | ```
56 |
57 | We also provide a requirements.txt file which you could install instead by...
58 | ```
59 | pip install -r requirements.txt
60 | ```
61 |
62 | You should also have access to any of your source bindings so that Qy.py can import them freely.
63 |
64 | A full list of dependencies is as follows:
65 | - rebaron
66 | - baron
67 | - rply
68 | - appdirs
69 | - qt_py
70 | - argparse
71 |
72 |
73 | ### Usage
74 | ```bash
75 | $ qt_py_convert [-h] [-r] [--stdout] [--write-path WRITE_PATH] [--backup]
76 | [--show-lines] [--to-method-support] [--explicit-signals-flag]
77 | files_or_directories [files_or_directories ...]
78 | ```
79 |
80 | | Argument | Description |
81 | | ------------------------- | ------------- |
82 | | -h,--help | Show the help message and exit. |
83 | | files_or_directories | Pass explicit files or directories to run. **NOTE:** If **"-"** is passed instead of files_or_directories, QtPyConvert will attempt to read from stdin instead. **Useful for pipelining proesses together** |
84 | | -r,--recursive | Recursively search for python files to convert. Only applicable when passing a directory. |
85 | | --stdout | Boolean flag which will write the resulting file to stdout instead of on disk. |
86 | | --write-path | If provided, QtPyConvert will treat "--write-path" as a relative root and write modified files from there. |
87 | | --backup | Create a hidden backup of the original source code beside the newly converted file. |
88 | | --show-lines | Turn on printing of line numbers while replacing statements. Ends up being much slower. |
89 | | --to-method-support | **EXPERIMENTAL**: An attempt to replace all api1.0 style "*toString*", "*toInt*", "*toBool*", "*toPyObject*", "*toAscii*" methods that are unavailable in api2.0. |
90 | | --explicit-signals-flag | **EXPERIMENTAL**: Modification on the api1.0 style signal conversion logic. It will explicitly slice into the QtCore.Signal object to find the signal with the matching signature. This is a fairly unknown feature of PySide/PyQt and is usually worked around by the developer. However, this should be safe to turn on whichever the case. |
91 |
92 |
93 | ### Customization
94 |
95 | QtPyConvert supports some custom bindings if you are willing to do a little bit of work.
96 |
97 | This is done through environment variables:
98 |
99 | | Key | Value | Description |
100 | | ----------------------------- | ------------------------------------------------------------------------------ | ----------- |
101 | | QT_CUSTOM_BINDINGS_SUPPORT | The names of custom abstraction layers or bindings separated by **os.pathsep** | This can be used if you have code that was already doing it's own abstraction and you want to move to the Qt.py layer. |
102 | | QT_CUSTOM_MISPLACED_MEMBERS | This is a json dictionary that you have saved into your environment variables. | This json dictionary should look similar to the Qt.py _misplaced_members dictionary but instead of mapping to Qt.py it maps the source bindings to your abstraction layer. |
103 |
104 | > **Note** This feature is *experimental* and has only been used internally a few times. Support for this feature will probably be slower than support for the core functionality of QyPyConvert.
105 |
106 | ## Troubleshooting
107 |
108 | QtPyConvert is still a bit of a work in progress, there are things that it cannot yet convert with 100% certainty.
109 | The following is a guide of common problems that you might have pop up.
110 |
111 | ### During Conversion
112 |
113 | #### baron.parser.ParsingError
114 |
115 | The most common thing that you will probably see is a Baron parsing error.
116 | ```bash
117 | Traceback (most recent call last):
118 | File "/usr/bin/qt_py_convert", line 47, in
119 | main(args.file_or_directory, args.recursive, args.write)
120 | File "/usr/bin/qt_py_convert", line 40, in main
121 | process_folder(path, recursive=recursive, write=write)
122 | File "/usr/lib/python2.7/site-packages/qt_py_convert/run.py", line 310, in process_folder
123 | process_folder(os.path.join(folder, fn), recursive, write, fast_exit)
124 | File "/usr/lib/python2.7/site-packages/qt_py_convert/run.py", line 310, in process_folder
125 | process_folder(os.path.join(folder, fn), recursive, write, fast_exit)
126 | File "/usr/lib/python2.7/site-packages/qt_py_convert/run.py", line 310, in process_folder
127 | process_folder(os.path.join(folder, fn), recursive, write, fast_exit)
128 | File "/usr/lib/python2.7/site-packages/qt_py_convert/run.py", line 310, in process_folder
129 | process_folder(os.path.join(folder, fn), recursive, write, fast_exit)
130 | File "/usr/lib/python2.7/site-packages/qt_py_convert/run.py", line 302, in process_folder
131 | os.path.join(folder, fn), write=write, fast_exit=fast_exit
132 | File "/usr/lib/python2.7/site-packages/qt_py_convert/run.py", line 282, in process_file
133 | aliases, mappings, modified_code = run(source, fast_exit=fast_exit)
134 | File "/usr/lib/python2.7/site-packages/qt_py_convert/run.py", line 264, in run
135 | psep0101.process(red)
136 | File "/usr/lib/python2.7/site-packages/qt_py_convert/_modules/psep0101/process.py", line 215, in process
137 | getattr(Processes, issue)(red, psep_issues[issue]) if psep_issues[issue] else None
138 | File "/usr/lib/python2.7/site-packages/qt_py_convert/_modules/psep0101/process.py", line 34, in _process_qvariant
139 | node.parent.replace(changed)
140 | File "/usr/lib/python2.7/site-packages/redbaron/base_nodes.py", line 1016, in replace
141 | new_node = self._convert_input_to_node_object(new_node, parent=None, on_attribute=None, generic=True)
142 | File "/usr/lib/python2.7/site-packages/redbaron/base_nodes.py", line 156, in _convert_input_to_node_object
143 | return Node.from_fst(baron.parse(value)[0], parent=parent, on_attribute=on_attribute)
144 | File "/usr/lib/python2.7/site-packages/baron/baron.py", line 57, in parse
145 | to_return = _parse(tokens, print_function)
146 | File "/usr/lib/python2.7/site-packages/baron/baron.py", line 26, in _parse
147 | raise e
148 | baron.parser.ParsingError: Error, got an unexpected token RIGHT_SQUARE_BRACKET here:
149 | 1 self.user_data[index.row(]<---- here
150 |
151 | The token RIGHT_SQUARE_BRACKET should be one of those: BACKQUOTE, BINARY, BINARY_RAW_STRING, BINARY_STRING, COMMA, COMPLEX, DOUBLE_STAR, FLOAT, FLOAT_EXPONANT, FLOAT_EXPONANT_COMPLEX, HEXA, INT, LAMBDA, LEFT_BRACKET, LEFT_PARENTHESIS, LEFT_SQUARE_BRACKET, LONG, MINUS, NAME, NOT, OCTA, PLUS, RAW_STRING, RIGHT_PARENTHESIS, STAR, STRING, TILDE, UNICODE_RAW_STRING, UNICODE_STRING
152 |
153 | It is not normal that you see this error, it means that Baron has failed to parse valid Python code. It would be kind if you can extract the snippet of your code that makes Baron fail and open a bug here: https://github.com/Psycojoker/baron/issues
154 |
155 | Sorry for the inconvenience.
156 | ```
157 |
158 |
159 | Because we are using an alternate Python AST, there are sometimes issues on edge cases of code.
160 | Unfortunately, Baron get's confused sometimes when it tries to send us a helpful traceback and the error is usually earlier than it thinks.
161 | There are two usual suspects when getting a Baron ParsingError.
162 |
163 |
164 | ##### Incorrectly indented comments
165 |
166 | This is a problem that will popup with Baron because it actually pays attention to the comments, whereas Python just throws them out.
167 | If you are getting an error similar to the above, you will want to look higher in the script for incorrectly indented comments, multiline and single line ones.
168 |
169 | ##### Bare print statements
170 |
171 | This is less common than the indented comments issue but has still shown up in a few cases for us internally.
172 | There are times where Baron cannot parse a print statement and turning it into a print function by enclosing it in parenthesis seems to fix it.
173 |
174 |
175 | #### Qt.py does not support uic.loadUiType
176 | The Qt.py module does not support uic.loadUiType.
177 | Please see [https://github.com/mottosso/Qt.py/issues/237](https://github.com/mottosso/Qt.py/issues/237)
178 |
179 |
180 | ### During Runtime
181 |
182 | #### QLayout.setMargin
183 | As of Qt 4.7 QLayout.setMargin has been set to obsolete which means that it will be removed.
184 | As it turns out, they removed it in Qt5.
185 | The obsoleted page is [here](http://doc.qt.io/archives/qt-4.8/qlayout-obsolete.html)
186 |
187 | Obsoleted code
188 | > layout = QLayout()
189 | > layout.setMargin(10)
190 |
191 | Replacement code
192 | > layout = QLayout()
193 | > layout.setContentsMargins(10, 10, 10, 10)
194 |
195 |
196 | ## Future Features
197 |
198 | There are several things that we would love to have support for in QtPyConvert but we just haven't gotten around to yet for various reasons.
199 |
200 | - Warnings about deprecated/obsoleted method calls in Qt4 code.
201 | - There were many method calls that were removed in Qt5 and most people were unaware that they should be using something else when they wrote the Qt4 code.
202 | There are lists on the Qt5 docs about what was deprecated and what the replacements are (if any) in Qt5 code. It would be nice if we could warn the user about these when we detect them and potentially automatically fix some of them too.
203 | - In a perfect world we would be able to dynamically build the list of these by scraping the Qt website too.
204 | - Better support for api-v1.0 method removal.
205 | Currently we are basially looking for the method names because they are quite unique.
206 | Ideally it'd be great if we could somehow record the type of the object at least in locals and then if that object was a QString for example, see if it is using any methods that aren't on a builtin string type.
207 | - Better support for the QtCompat..method replacements.
208 | Much of this would require the previous feature to be somewhat figured out.
209 | We would need to at least minimally track variable types.
210 |
211 |
212 |
213 | ## Project Information
214 |
215 | ### Built With
216 |
217 | * [Qt.py](https://github.com/mottosso/Qt.py) - The Qt abstraction library that we port code to.
218 | * [RedBaron](https://github.com/PyCQA/Redbaron) - The alternate Python AST which allows us to modify and preserve comments + formatting.
219 |
220 | ### Contributing
221 |
222 | Please read [CONTRIBUTING.md](https://github.com/DigitalDomain/QtPyConvert/blob/master/CONTRIBUTING.md) for details on our code of conduct, and the process for submitting pull requests to us.
223 |
224 | ### Versioning
225 |
226 | We use [semantic versioning](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/DigitalDomain/QtPyConvert/tags).
227 |
228 | ### Authors
229 |
230 | * **Alex Hughes** - Initial work - [Digital Domain](https://digitaldomain.com)
231 | * **Rafe Sacks** - Prototyping help - [Digital Domain](https://digitaldomain.com)
232 |
233 | See also the list of [contributors](https://github.com/DigitalDomain/QtPyConvert/contributors) who participated in this project.
234 |
235 | ### License
236 |
237 | This project is licensed under a modified Apache 2.0 license - see the [LICENSE](https://github.com/DigitalDomain/QtPyConvert/blob/master/LICENSE) file for details
238 |
239 | ### Acknowledgments
240 |
241 | * [The developers of Qt.py](https://github.com/mottosso/Qt.py/contributors)
242 | * [The developers of RedBaron](https://github.com/PyCQA/redbaron/contributors)
243 | * etc
244 |
--------------------------------------------------------------------------------
/_resources/logo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/digitaldomain/QtPyConvert/2a2d2b9121004c27598f9e1031cf6ebf41c0895a/_resources/logo.gif
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | Qt.py>=1.2.0.b2
2 | redbaron
3 |
--------------------------------------------------------------------------------
/src/bin/qresource_convert:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # Copyright 2018 Digital Domain 3.0
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "Apache License")
5 | # with the following modification; you may not use this file except in
6 | # compliance with the Apache License and the following modification to it:
7 | # Section 6. Trademarks. is deleted and replaced with:
8 | #
9 | # 6. Trademarks. This License does not grant permission to use the trade
10 | # names, trademarks, service marks, or product names of the Licensor
11 | # and its affiliates, except as required to comply with Section 4(c) of
12 | # the License and to reproduce the content of the NOTICE file.
13 | #
14 | # You may obtain a copy of the Apache License at
15 | #
16 | # http://www.apache.org/licenses/LICENSE-2.0
17 | #
18 | # Unless required by applicable law or agreed to in writing, software
19 | # distributed under the Apache License with the above modification is
20 | # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 | # KIND, either express or implied. See the Apache License for the specific
22 | # language governing permissions and limitations under the Apache License.
23 | import argparse
24 | import contextlib
25 | from cStringIO import StringIO
26 | import os
27 | import subprocess
28 | import sys
29 |
30 |
31 | import qt_py_convert.run
32 | import qt_py_convert.general
33 |
34 |
35 | PYQT4 = "PyQt4"
36 | PYQt5 = "PyQt5"
37 | PYSIDE = "PySide"
38 | PYSIDE2 = "PySide2"
39 | PyUIC4 = "pyuic4"
40 | PyRCC4 = "pyrcc4"
41 | PyUIC5 = "pyuic5"
42 | PyRCC5 = "pyrcc5"
43 | PySideUIC = "pyside-uic"
44 | PySideRCC = "pyside-rcc"
45 | PySide2UIC = "pyside2-uic"
46 | PySide2RCC = "pyside2-rcc"
47 |
48 | QRESOURCE_ENVIRON = "QRESOURCE_CONVERTER_DEFAULT"
49 |
50 | mappings = {
51 | PYQT4: (PyUIC4, PyRCC4),
52 | PYQt5: (PyUIC5, PyRCC5),
53 | PYSIDE: (PySideUIC, PySideRCC),
54 | PYSIDE2: (PySide2UIC, PySide2RCC),
55 | }
56 |
57 |
58 | class UICConversionError(ValueError):
59 | """If we were unable to convert the uic into a python file."""
60 |
61 |
62 | def _is_uic(path):
63 | if os.path.splitext(path)[-1] in (".ui", ".uic"):
64 | return True
65 | return False
66 |
67 |
68 | def execute_convert(application, path, output=None):
69 | if application is None:
70 | # Query Environ.
71 | application = os.environ.get(QRESOURCE_ENVIRON, PYQT4)
72 |
73 | uic, rcc = mappings[application]
74 |
75 | if _is_uic(path):
76 | binary = uic
77 | else:
78 | binary = rcc
79 |
80 | command = [binary, path]
81 | if output:
82 | command.extend(["-o", output])
83 | proc = subprocess.Popen(
84 | command,
85 | stdout=subprocess.PIPE,
86 | stderr=subprocess.PIPE,
87 | )
88 | out, err = proc.communicate()
89 | has_errors = False
90 |
91 | if output:
92 | message = output
93 | else:
94 | message = out
95 |
96 | if proc.returncode:
97 | has_errors = True
98 | return has_errors, err, message
99 | else:
100 | return has_errors, None, message
101 |
102 |
103 | @contextlib.contextmanager
104 | def stdout_redirector():
105 | stdout, stderr = sys.stdout, sys.stderr
106 | out = StringIO()
107 | err = StringIO()
108 | sys.stdout = out
109 | sys.stderr = err
110 | yield
111 | sys.stdout = stdout
112 | sys.stderr = stderr
113 |
114 |
115 | def parse_args():
116 | parser = argparse.ArgumentParser(
117 | "qresource_convert"
118 | )
119 |
120 | parser.add_argument(
121 | "-c", "--converter",
122 | action="store",
123 | choices=tuple(mappings.keys()),
124 | default=None,
125 | dest="converter"
126 | )
127 | parser.add_argument(
128 | "file",
129 | help="Pass explicit files or a directories to run.",
130 | )
131 | parser.add_argument(
132 | "-o",
133 | required=False,
134 | help="Filepath to write results to."
135 | )
136 | args = parser.parse_args()
137 | return args
138 |
139 |
140 | def main():
141 | args = parse_args()
142 | has_errors, errors, message = execute_convert(
143 | args.converter, args.file, output=args.o
144 | )
145 |
146 | if has_errors:
147 | raise UICConversionError(errors)
148 |
149 | if not args.o:
150 | with stdout_redirector():
151 | # In memory
152 | _, _, output = qt_py_convert.run.run(
153 | message, skip_lineno=True, tometh_flag=True
154 | )
155 | else:
156 | with stdout_redirector():
157 | qt_py_convert.run.process_file(
158 | message,
159 | write_mode=qt_py_convert.general.WriteFlag.WRITE_TO_FILE,
160 | skip_lineno=True,
161 | tometh_flag=True
162 | )
163 | output = message
164 |
165 | sys.stdout.write(output)
166 |
167 |
168 | if __name__ == "__main__":
169 | main()
170 |
--------------------------------------------------------------------------------
/src/bin/qt_py_convert:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # Copyright 2018 Digital Domain 3.0
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "Apache License")
5 | # with the following modification; you may not use this file except in
6 | # compliance with the Apache License and the following modification to it:
7 | # Section 6. Trademarks. is deleted and replaced with:
8 | #
9 | # 6. Trademarks. This License does not grant permission to use the trade
10 | # names, trademarks, service marks, or product names of the Licensor
11 | # and its affiliates, except as required to comply with Section 4(c) of
12 | # the License and to reproduce the content of the NOTICE file.
13 | #
14 | # You may obtain a copy of the Apache License at
15 | #
16 | # http://www.apache.org/licenses/LICENSE-2.0
17 | #
18 | # Unless required by applicable law or agreed to in writing, software
19 | # distributed under the Apache License with the above modification is
20 | # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 | # KIND, either express or implied. See the Apache License for the specific
22 | # language governing permissions and limitations under the Apache License.
23 | import os
24 | import sys
25 |
26 | import argparse
27 |
28 | from qt_py_convert.run import process_file, process_folder
29 | from qt_py_convert.general import WriteFlag
30 |
31 |
32 | def parse():
33 | parser = argparse.ArgumentParser(
34 | "qt_py_convert"
35 | )
36 |
37 | parser.add_argument(
38 | "files_or_directories",
39 | nargs="+",
40 | help="Pass explicit files or a directories to run. "
41 | "NOTE: If \"-\" is passed instead of files_or_directories, "
42 | "qt_py_convert will attempt to read from stdin. "
43 | "Useful for pipelining processes"
44 | )
45 | parser.add_argument(
46 | "-r", "--recursive",
47 | action="store_true",
48 | help="Recursively search for python files to convert. "
49 | "Only applicable when passing a directory.",
50 | )
51 | parser.add_argument(
52 | "--stdout",
53 | action="store_true",
54 | help="Boolean flag which will write the resulting file to stdout "
55 | "instead of on disk."
56 | )
57 | parser.add_argument(
58 | "--write-path",
59 | required=False,
60 | default=None,
61 | help="If provided, QtPyConvert will treat \"--write-path\" as a "
62 | "relative root and write modified files from there."
63 | )
64 | parser.add_argument(
65 | "--backup",
66 | action="store_true",
67 | help="When combined with the \"--stdout\" flag it will not produce "
68 | "\"*.bak\" files for converted files.",
69 | )
70 | parser.add_argument(
71 | "--show-lines",
72 | action="store_true",
73 | help="Turn on printing the line numbers that things are replaced at. "
74 | "Ends up being much slower to process.",
75 | )
76 | parser.add_argument(
77 | "--to-method-support",
78 | action="store_true",
79 | help="EXPERIMENTAL: An attempt to replace all api1.0 style "
80 | "\"toString\", \"toInt\", \"toFloat\", \"toBool\", \"toPyObject\""
81 | ", \"toAscii\" methods that are unavailable in api2.0.",
82 | )
83 | parser.add_argument(
84 | "--explicit-signals-flag",
85 | action="store_true",
86 | help="EXPERIMENTAL: Modification on the api1.0 style signal conversion"
87 | " logic. It will explicitly slice into the QtCore.Signal object "
88 | "to find the signal with the matching signature.\n"
89 | "This is a fairly unknown feature of PySide/PyQt and is usually "
90 | "worked around by the developer. However, this should be safe to "
91 | "turn on whichever the case.",
92 | )
93 |
94 | return parser.parse_args()
95 |
96 |
97 | def _resolve_stdin(paths):
98 | """
99 | _resolve_stdin allows us to have "-" in our files_or_directories and have
100 | it expand to input from stdin.
101 | This allows us to pipe into qt_py_convert.
102 |
103 | :param paths: List of strings. It wll replace any strings matching "-"
104 | with sys.stdin.
105 | :type paths: list[str...]
106 | :return: List that has been modified to include stdin.
107 | :rtype: list[str...]
108 | """
109 | _stdin = None
110 | _inserted = 0
111 | for index, path in enumerate(paths[:]):
112 | if path == "-": # Insert stdin anytime we see "-"
113 | _index = index+_inserted # Calculated index after insertions.
114 | paths.pop(_index) # Remove the "-"
115 | if _stdin is None: # If we haven't pulled from stdin yet.
116 | _stdin = [
117 | x.strip("\n").strip("\r") # Strip \n and \r
118 | for x in list(sys.stdin) # Iterate through stdin.
119 | ]
120 | # Generate a new list.
121 | # Basically if I could do an "insert" and an "expand" at once.
122 | paths = paths[:_index] + _stdin + paths[_index:]
123 | # We have inserted x - 1 because we popped.
124 | _inserted += len(_stdin) - 1
125 | return paths
126 |
127 |
128 | def main(pathlist, recursive=True, path=None, no_write=False, backup=False, stdout=False, show_lines=True, tometh=False):
129 | # if len(pathlist) == 1:
130 | # if pathlist[0] == "-": # Support for piping on unix.
131 | # pathlist = sys.stdin
132 |
133 | pathlist = _resolve_stdin(pathlist)
134 |
135 | output = 0
136 | if stdout:
137 | output |= WriteFlag.WRITE_TO_STDOUT
138 | else:
139 | output |= WriteFlag.WRITE_TO_FILE
140 |
141 | for src_path in pathlist:
142 | # print("Processing %s" % path)
143 | abs_path = os.path.abspath(src_path)
144 | if os.path.isdir(abs_path):
145 | process_folder(
146 | src_path,
147 | recursive=recursive,
148 | write_mode=output,
149 | path=(path, abs_path),
150 | backup=backup,
151 | skip_lineno=not show_lines,
152 | tometh_flag=tometh
153 | )
154 | else:
155 | process_file(
156 | src_path,
157 | write_mode=output,
158 | path=(path, abs_path),
159 | backup=backup,
160 | skip_lineno=not show_lines,
161 | tometh_flag=tometh
162 | )
163 |
164 |
165 | if __name__ == "__main__":
166 | args = parse()
167 | main(
168 | pathlist=args.files_or_directories,
169 | recursive=args.recursive,
170 | path=args.write_path,
171 | backup=args.backup,
172 | stdout=args.stdout,
173 | show_lines=args.show_lines,
174 | tometh=args.to_method_support,
175 | )
176 |
--------------------------------------------------------------------------------
/src/python/qt_py_convert/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2018 Digital Domain 3.0
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "Apache License")
4 | # with the following modification; you may not use this file except in
5 | # compliance with the Apache License and the following modification to it:
6 | # Section 6. Trademarks. is deleted and replaced with:
7 | #
8 | # 6. Trademarks. This License does not grant permission to use the trade
9 | # names, trademarks, service marks, or product names of the Licensor
10 | # and its affiliates, except as required to comply with Section 4(c) of
11 | # the License and to reproduce the content of the NOTICE file.
12 | #
13 | # You may obtain a copy of the Apache License at
14 | #
15 | # http://www.apache.org/licenses/LICENSE-2.0
16 | #
17 | # Unless required by applicable law or agreed to in writing, software
18 | # distributed under the Apache License with the above modification is
19 | # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20 | # KIND, either express or implied. See the Apache License for the specific
21 | # language governing permissions and limitations under the Apache License.
22 | __version__ = "3.1.0"
23 | """
24 | An automatic Python Qt binding transpiler to the Qt.py abstraction layer.
25 | It aims to help in your modernization of your Python Qt code.
26 | QtPyConvert supports the following bindings out of the box:
27 |
28 | - PyQt4
29 | - PySide
30 | - PyQt5
31 | - PySide2
32 | """
33 |
--------------------------------------------------------------------------------
/src/python/qt_py_convert/_modules/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2018 Digital Domain 3.0
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "Apache License")
4 | # with the following modification; you may not use this file except in
5 | # compliance with the Apache License and the following modification to it:
6 | # Section 6. Trademarks. is deleted and replaced with:
7 | #
8 | # 6. Trademarks. This License does not grant permission to use the trade
9 | # names, trademarks, service marks, or product names of the Licensor
10 | # and its affiliates, except as required to comply with Section 4(c) of
11 | # the License and to reproduce the content of the NOTICE file.
12 | #
13 | # You may obtain a copy of the Apache License at
14 | #
15 | # http://www.apache.org/licenses/LICENSE-2.0
16 | #
17 | # Unless required by applicable law or agreed to in writing, software
18 | # distributed under the Apache License with the above modification is
19 | # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20 | # KIND, either express or implied. See the Apache License for the specific
21 | # language governing permissions and limitations under the Apache License.
22 |
--------------------------------------------------------------------------------
/src/python/qt_py_convert/_modules/expand_stars/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2018 Digital Domain 3.0
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "Apache License")
4 | # with the following modification; you may not use this file except in
5 | # compliance with the Apache License and the following modification to it:
6 | # Section 6. Trademarks. is deleted and replaced with:
7 | #
8 | # 6. Trademarks. This License does not grant permission to use the trade
9 | # names, trademarks, service marks, or product names of the Licensor
10 | # and its affiliates, except as required to comply with Section 4(c) of
11 | # the License and to reproduce the content of the NOTICE file.
12 | #
13 | # You may obtain a copy of the Apache License at
14 | #
15 | # http://www.apache.org/licenses/LICENSE-2.0
16 | #
17 | # Unless required by applicable law or agreed to in writing, software
18 | # distributed under the Apache License with the above modification is
19 | # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20 | # KIND, either express or implied. See the Apache License for the specific
21 | # language governing permissions and limitations under the Apache License.
22 | from qt_py_convert._modules.expand_stars.process import process
23 |
--------------------------------------------------------------------------------
/src/python/qt_py_convert/_modules/expand_stars/process.py:
--------------------------------------------------------------------------------
1 | # Copyright 2018 Digital Domain 3.0
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "Apache License")
4 | # with the following modification; you may not use this file except in
5 | # compliance with the Apache License and the following modification to it:
6 | # Section 6. Trademarks. is deleted and replaced with:
7 | #
8 | # 6. Trademarks. This License does not grant permission to use the trade
9 | # names, trademarks, service marks, or product names of the Licensor
10 | # and its affiliates, except as required to comply with Section 4(c) of
11 | # the License and to reproduce the content of the NOTICE file.
12 | #
13 | # You may obtain a copy of the Apache License at
14 | #
15 | # http://www.apache.org/licenses/LICENSE-2.0
16 | #
17 | # Unless required by applicable law or agreed to in writing, software
18 | # distributed under the Apache License with the above modification is
19 | # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20 | # KIND, either express or implied. See the Apache License for the specific
21 | # language governing permissions and limitations under the Apache License.
22 | """
23 | The imports module is designed to fix the import statements.
24 | """
25 | import traceback
26 |
27 | from qt_py_convert.general import ALIAS_DICT, change, supported_binding
28 | from qt_py_convert.color import color_text, ANSI
29 | from qt_py_convert.log import get_logger
30 |
31 |
32 | EXPAND_STARS_LOG = get_logger("expand_stars")
33 |
34 |
35 | class Processes(object):
36 | """Processes class for expand_stars"""
37 | @staticmethod
38 | def _get_children(binding, levels=None):
39 | """
40 | You have done the following:
41 | >>> from . import *
42 |
43 | And I hate you a little bit.
44 | I am changing it to the following:
45 | >>> from import
46 |
47 | But I don't know what the heck you used in the *
48 | So I am just getting everything bootstrapped in. Sorry-not-sorry
49 | """
50 | def _module_filtering(key):
51 | import __builtin__
52 | if key.startswith("__"):
53 | return False
54 | elif key in dir(__builtin__):
55 | return False
56 | return True
57 |
58 | def _members(_mappings, _module_, module_name):
59 | members = filter(_module_filtering, dir(_module))
60 | for member in members:
61 | mappings[member] = "{mod}.{member}".format(
62 | mod=module_name,
63 | member=member
64 | )
65 |
66 | mappings = {}
67 | if levels is None:
68 | levels = []
69 | try:
70 | _temp = __import__(binding, fromlist=levels)
71 | except ImportError as err:
72 | strerr = str(err).replace("No module named", "")
73 |
74 | msg = (
75 | "Attempting to resolve a * import from the {mod} "
76 | "module failed.\n"
77 | "This is usually because the module could not be imported. "
78 | "Please check that this script can import it. The error was:\n"
79 | "{err}"
80 | ).format(mod=strerr, err=str(err))
81 | traceback.print_exc()
82 | raise ImportError(msg)
83 | if not levels:
84 | _module = _temp
85 | _members(mappings, _module, module_name=binding)
86 | else:
87 | for level in levels:
88 | _module = getattr(_temp, level)
89 | _members(mappings, _module, module_name=level)
90 | return mappings
91 |
92 | @classmethod
93 | def _process_star(cls, red, stars, skip_lineno=False):
94 | """
95 | _process_star is designed to replace from X import * methods.
96 |
97 | :param red: redbaron process. Unused in this method.
98 | :type red: redbardon.RedBaron
99 | :param stars: List of redbaron nodes that matched for this proc.
100 | :type stars: list
101 | """
102 | mappings = {}
103 | for star in stars:
104 | from_import = star.parent
105 | binding = from_import.value[0]
106 | second_level_modules = None
107 | if len(star.parent.value) > 1:
108 | second_level_modules = [star.parent.value[1].dumps()]
109 | if len(star.parent.value) > 2:
110 | pass
111 |
112 | children = cls._get_children(binding.dumps(), second_level_modules)
113 | if second_level_modules is None:
114 | second_level_modules = children
115 | text = "from {binding} import {slm}".format(
116 | binding="Qt",
117 | slm=", ".join([name for name in second_level_modules])
118 | )
119 |
120 | change(
121 | logger=EXPAND_STARS_LOG,
122 | node=star.parent,
123 | replacement=text,
124 | skip_lineno=skip_lineno
125 | )
126 | mappings.update(children)
127 | # star.replace(
128 | # text
129 | # )
130 | return mappings
131 |
132 | EXPAND_STR = "EXPAND"
133 | EXPAND = _process_star
134 |
135 |
136 | def star_process(store):
137 | """
138 | star_process is one of the more complex handlers for the _modules.
139 |
140 | :param store: Store is the issues dict defined in "process"
141 | :type store: dict
142 | :return: The filter_function callable.
143 | :rtype: callable
144 | """
145 | def filter_function(value):
146 | for target in value.parent.targets:
147 | if target.type == "star" and supported_binding(value.dumps()):
148 | store[Processes.EXPAND_STR].add(value)
149 | return True
150 |
151 | return filter_function
152 |
153 |
154 | def process(red, skip_lineno=False, **kwargs):
155 | """
156 | process is the main function for the import process.
157 |
158 | :param red: Redbaron ast.
159 | :type red: redbaron.redbaron
160 | :param skip_lineno: An optional performance flag. By default, when the
161 | script replaces something, it will tell you which line it is
162 | replacing on. This can be useful for tracking the places that
163 | changes occurred. When you turn this flag on however, it will not
164 | show the line numbers. This can give great performance increases
165 | because redbaron has trouble calculating the line number sometimes.
166 | :type skip_lineno: bool
167 | :param kwargs: Any other kwargs will be ignored.
168 | :type kwargs: dict
169 | """
170 | issues = {
171 | Processes.EXPAND_STR: set(),
172 | }
173 | EXPAND_STARS_LOG.warning(color_text(
174 | text="\"import star\" used. We are bootstrapping code!",
175 | color=ANSI.colors.red,
176 | ))
177 | EXPAND_STARS_LOG.warning(color_text(
178 | text="This will be very slow. It's your own fault.",
179 | color=ANSI.colors.red,
180 | ))
181 | values = red.find_all("FromImportNode", value=star_process(issues))
182 |
183 | mappings = getattr(Processes, Processes.EXPAND_STR)(
184 | red, issues[Processes.EXPAND_STR], skip_lineno=skip_lineno
185 | )
186 | return ALIAS_DICT, mappings
187 |
--------------------------------------------------------------------------------
/src/python/qt_py_convert/_modules/from_imports/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2018 Digital Domain 3.0
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "Apache License")
4 | # with the following modification; you may not use this file except in
5 | # compliance with the Apache License and the following modification to it:
6 | # Section 6. Trademarks. is deleted and replaced with:
7 | #
8 | # 6. Trademarks. This License does not grant permission to use the trade
9 | # names, trademarks, service marks, or product names of the Licensor
10 | # and its affiliates, except as required to comply with Section 4(c) of
11 | # the License and to reproduce the content of the NOTICE file.
12 | #
13 | # You may obtain a copy of the Apache License at
14 | #
15 | # http://www.apache.org/licenses/LICENSE-2.0
16 | #
17 | # Unless required by applicable law or agreed to in writing, software
18 | # distributed under the Apache License with the above modification is
19 | # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20 | # KIND, either express or implied. See the Apache License for the specific
21 | # language governing permissions and limitations under the Apache License.
22 | from qt_py_convert._modules.from_imports.process import process
23 |
--------------------------------------------------------------------------------
/src/python/qt_py_convert/_modules/from_imports/process.py:
--------------------------------------------------------------------------------
1 | # Copyright 2018 Digital Domain 3.0
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "Apache License")
4 | # with the following modification; you may not use this file except in
5 | # compliance with the Apache License and the following modification to it:
6 | # Section 6. Trademarks. is deleted and replaced with:
7 | #
8 | # 6. Trademarks. This License does not grant permission to use the trade
9 | # names, trademarks, service marks, or product names of the Licensor
10 | # and its affiliates, except as required to comply with Section 4(c) of
11 | # the License and to reproduce the content of the NOTICE file.
12 | #
13 | # You may obtain a copy of the Apache License at
14 | #
15 | # http://www.apache.org/licenses/LICENSE-2.0
16 | #
17 | # Unless required by applicable law or agreed to in writing, software
18 | # distributed under the Apache License with the above modification is
19 | # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20 | # KIND, either express or implied. See the Apache License for the specific
21 | # language governing permissions and limitations under the Apache License.
22 | """
23 | The from_imports module is designed to fix the from import statements.
24 | """
25 | from qt_py_convert._modules.expand_stars import process as stars_process
26 | from qt_py_convert.general import __supported_bindings__, ALIAS_DICT, change, \
27 | supported_binding
28 | from qt_py_convert.log import get_logger
29 |
30 |
31 | FROM_IMPORTS_LOG = get_logger("from_imports")
32 | IGNORED_IMPORT_TARGETS = ("right_parenthesis", "left_parenthesis")
33 |
34 |
35 | class Processes(object):
36 | """Processes class for from_imports"""
37 | @staticmethod
38 | def _get_import_parts(node, binding):
39 | return node.dumps().replace(binding, "").lstrip(".").split(".")
40 |
41 | @staticmethod
42 | def _no_second_level_module(node, _parts, skip_lineno=False):
43 | text = "from Qt import {key}".format(
44 | key=", ".join([target.value for target in node.targets])
45 | )
46 |
47 | change(
48 | logger=FROM_IMPORTS_LOG,
49 | node=node,
50 | replacement=text,
51 | skip_lineno=skip_lineno
52 | )
53 |
54 | node.replace(text)
55 |
56 | @classmethod
57 | def _process_import(cls, red, objects, skip_lineno=False):
58 | """
59 | _process_import is designed to replace from import methods.
60 |
61 | :param red: redbaron process. Unused in this method.
62 | :type red: redbardon.RedBaron
63 | :param objects: List of redbaron nodes that matched for this proc.
64 | :type objects: list
65 | :param skip_lineno: Global "skip_lineno" flag.
66 | :type skip_lineno: bool
67 | """
68 | binding_aliases = ALIAS_DICT
69 | mappings = {}
70 |
71 | # Replace each node
72 | for node, binding in objects:
73 | from_import_parts = cls._get_import_parts(node, binding)
74 | if len(from_import_parts) and from_import_parts[0]:
75 | second_level_module = from_import_parts[0]
76 | else:
77 | cls._no_second_level_module(
78 | node.parent,
79 | from_import_parts,
80 | skip_lineno=skip_lineno
81 | )
82 | binding_aliases["bindings"].add(binding)
83 | for target in node.parent.targets:
84 | binding_aliases["root_aliases"].add(target.value)
85 | continue
86 |
87 | for _from_as_name in node.parent.targets:
88 | if _from_as_name.type in IGNORED_IMPORT_TARGETS:
89 | continue
90 | if _from_as_name.type == "star":
91 | # TODO: Make this a flag and make use the expand module.
92 | _, star_mappings = stars_process(
93 | red
94 | )
95 | mappings.update(star_mappings)
96 | else:
97 | key = _from_as_name.target or _from_as_name.value
98 | value = ".".join(from_import_parts)+"."+_from_as_name.value
99 | mappings[key] = value
100 |
101 | replacement = "from Qt import {key}".format(
102 | key=second_level_module
103 | )
104 | change(
105 | logger=FROM_IMPORTS_LOG,
106 | node=node.parent,
107 | replacement=replacement,
108 | skip_lineno=skip_lineno
109 | )
110 | node.parent.replace(replacement)
111 | binding_aliases["bindings"].add(binding)
112 | for target in node.parent.targets:
113 | binding_aliases["root_aliases"].add(target.value)
114 | if binding not in binding_aliases:
115 | binding_aliases[binding] = set()
116 | binding_aliases[binding] = binding_aliases[binding].union(
117 | set([target.value for target in node.parent.targets])
118 | )
119 | return binding_aliases, mappings
120 |
121 | FROM_IMPORT_STR = "FROM_IMPORT"
122 | FROM_IMPORT = _process_import
123 |
124 |
125 | def import_process(store):
126 | """
127 | import_process is one of the more complex handlers for the _modules.
128 |
129 | :param store: Store is the issues dict defined in "process"
130 | :type store: dict
131 | :return: The filter_function callable.
132 | :rtype: callable
133 | """
134 | def filter_function(value):
135 | """
136 | filter_function takes an AtomTrailersNode or a DottedNameNode and will
137 | filter them out if they match something that has changed in psep0101
138 | """
139 | _raw_module = value.dumps()
140 | # See if that import is in our __supported_bindings__
141 | matched_binding = supported_binding(_raw_module)
142 | if matched_binding:
143 | store[Processes.FROM_IMPORT_STR].add(
144 | (value, matched_binding)
145 | )
146 | return True
147 |
148 | return filter_function
149 |
150 |
151 | def process(red, skip_lineno=False, **kwargs):
152 | """
153 | process is the main function for the import process.
154 |
155 | :param red: Redbaron ast.
156 | :type red: redbaron.redbaron
157 | :param skip_lineno: An optional performance flag. By default, when the
158 | script replaces something, it will tell you which line it is
159 | replacing on. This can be useful for tracking the places that
160 | changes occurred. When you turn this flag on however, it will not
161 | show the line numbers. This can give great performance increases
162 | because redbaron has trouble calculating the line number sometimes.
163 | :type skip_lineno: bool
164 | :param kwargs: Any other kwargs will be ignored.
165 | :type kwargs: dict
166 | """
167 | issues = {
168 | Processes.FROM_IMPORT_STR: set(),
169 | }
170 | red.find_all("FromImportNode", value=import_process(issues))
171 |
172 | key = Processes.FROM_IMPORT_STR
173 |
174 | if issues[key]:
175 | return getattr(Processes, key)(red, issues[key], skip_lineno=skip_lineno)
176 | else:
177 | return ALIAS_DICT, {}
178 |
--------------------------------------------------------------------------------
/src/python/qt_py_convert/_modules/imports/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2018 Digital Domain 3.0
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "Apache License")
4 | # with the following modification; you may not use this file except in
5 | # compliance with the Apache License and the following modification to it:
6 | # Section 6. Trademarks. is deleted and replaced with:
7 | #
8 | # 6. Trademarks. This License does not grant permission to use the trade
9 | # names, trademarks, service marks, or product names of the Licensor
10 | # and its affiliates, except as required to comply with Section 4(c) of
11 | # the License and to reproduce the content of the NOTICE file.
12 | #
13 | # You may obtain a copy of the Apache License at
14 | #
15 | # http://www.apache.org/licenses/LICENSE-2.0
16 | #
17 | # Unless required by applicable law or agreed to in writing, software
18 | # distributed under the Apache License with the above modification is
19 | # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20 | # KIND, either express or implied. See the Apache License for the specific
21 | # language governing permissions and limitations under the Apache License.
22 | from qt_py_convert._modules.imports.process import process
23 |
--------------------------------------------------------------------------------
/src/python/qt_py_convert/_modules/imports/process.py:
--------------------------------------------------------------------------------
1 | # Copyright 2018 Digital Domain 3.0
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "Apache License")
4 | # with the following modification; you may not use this file except in
5 | # compliance with the Apache License and the following modification to it:
6 | # Section 6. Trademarks. is deleted and replaced with:
7 | #
8 | # 6. Trademarks. This License does not grant permission to use the trade
9 | # names, trademarks, service marks, or product names of the Licensor
10 | # and its affiliates, except as required to comply with Section 4(c) of
11 | # the License and to reproduce the content of the NOTICE file.
12 | #
13 | # You may obtain a copy of the Apache License at
14 | #
15 | # http://www.apache.org/licenses/LICENSE-2.0
16 | #
17 | # Unless required by applicable law or agreed to in writing, software
18 | # distributed under the Apache License with the above modification is
19 | # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20 | # KIND, either express or implied. See the Apache License for the specific
21 | # language governing permissions and limitations under the Apache License.
22 | """
23 | The imports module is designed to fix the import statements.
24 | """
25 | from qt_py_convert.general import __supported_bindings__, ALIAS_DICT, change, \
26 | supported_binding
27 | from qt_py_convert.log import get_logger
28 |
29 | IMPORTS_LOG = get_logger("imports")
30 |
31 |
32 | class Processes(object):
33 | """Processes class for import"""
34 | @staticmethod
35 | def _build_child_name(child):
36 | return ".".join([child_part.dumps() for child_part in child.value])
37 |
38 | @staticmethod
39 | def _no_second_level_module(node, _child_parts, skip_lineno=False):
40 | replacement = "import Qt"
41 | change(
42 | logger=IMPORTS_LOG,
43 | node=node,
44 | replacement=replacement,
45 | skip_lineno=skip_lineno
46 | )
47 | node.replace(replacement)
48 |
49 | @classmethod
50 | def _process_import(cls, red, objects, skip_lineno=False):
51 | """
52 | _process_import is designed to replace import methods.
53 |
54 | :param red: redbaron process. Unused in this method.
55 | :type red: redbardon.RedBaron
56 | :param objects: List of redbaron nodes that matched for this proc.
57 | :type objects: list
58 | :param skip_lineno: Global "skip_lineno" flag.
59 | :type skip_lineno: bool
60 | """
61 | binding_aliases = ALIAS_DICT
62 | mappings = {}
63 |
64 | # Replace each node
65 | for node, binding in objects:
66 | for child_index, child in enumerate(node):
67 | _child_name = cls._build_child_name(child)
68 | _child_as_name = child.target
69 | if _child_name.split(".")[0] not in __supported_bindings__ \
70 | and _child_as_name not in __supported_bindings__:
71 | # Only one of our multi import node's children is relevant.
72 | continue
73 |
74 | _child_parts = _child_name.replace(binding, "")
75 | _child_parts = _child_parts.lstrip(".").split(".")
76 |
77 | # Check to see if there is a second level module
78 | if len(_child_parts) and _child_parts[0]:
79 | second_level_module = _child_parts[0]
80 | else:
81 | if len(node) == 1:
82 | # Only one in the import: "import PySide"
83 | cls._no_second_level_module(node.parent, _child_parts)
84 | else:
85 | # Multiple in the import: "import PySide, os"
86 | node_parent = node.parent
87 | node.pop(child_index)
88 | repl = node.parent.dumps() + "\nimport Qt"
89 |
90 | change(
91 | logger=IMPORTS_LOG,
92 | node=node_parent,
93 | replacement=repl,
94 | skip_lineno=skip_lineno
95 | )
96 |
97 | node.parent.replace(repl)
98 | if _child_as_name:
99 | mappings[_child_as_name] = "Qt"
100 | else:
101 | mappings[_child_name] = "Qt"
102 | binding_aliases["bindings"].add(binding)
103 | continue
104 |
105 | mappings[_child_as_name or _child_name] = ".".join(
106 | _child_parts
107 | )
108 |
109 | change(
110 | logger=IMPORTS_LOG,
111 | node=node.parent,
112 | replacement="from Qt import {key}".format(
113 | key=second_level_module
114 | ),
115 | skip_lineno=skip_lineno
116 | )
117 |
118 | node.parent.replace(
119 | "from Qt import {key}".format(key=second_level_module)
120 | )
121 | binding_aliases["bindings"].add(binding)
122 | binding_aliases["root_aliases"].add(second_level_module)
123 | if binding not in binding_aliases:
124 | binding_aliases[binding] = set()
125 | binding_aliases[binding].add(second_level_module)
126 | return binding_aliases, mappings
127 |
128 | IMPORT_STR = "IMPORT"
129 | IMPORT = _process_import
130 |
131 |
132 | def import_process(store):
133 | """
134 | import_process is one of the more complex handlers for the _modules.
135 |
136 | :param store: Store is the issues dict defined in "process"
137 | :type store: dict
138 | :return: The filter_function callable.
139 | :rtype: callable
140 | """
141 | def filter_function(value):
142 | """
143 | filter_function takes an AtomTrailersNode or a DottedNameNode and will filter them out if they match something that
144 | has changed in psep0101
145 | """
146 | _raw_module = value.dumps().split(".")[0]
147 | # See if that import is in our __supported_bindings__
148 | matched_binding = supported_binding(_raw_module)
149 | if matched_binding:
150 | store[Processes.IMPORT_STR].add(
151 | (value, matched_binding)
152 | )
153 | return True
154 | return filter_function
155 |
156 |
157 | def process(red, skip_lineno=False, **kwargs):
158 | """
159 | process is the main function for the import process.
160 |
161 | :param red: Redbaron ast.
162 | :type red: redbaron.redbaron
163 | :param skip_lineno: An optional performance flag. By default, when the
164 | script replaces something, it will tell you which line it is
165 | replacing on. This can be useful for tracking the places that
166 | changes occurred. When you turn this flag on however, it will not
167 | show the line numbers. This can give great performance increases
168 | because redbaron has trouble calculating the line number sometimes.
169 | :type skip_lineno: bool
170 | :param kwargs: Any other kwargs will be ignored.
171 | :type kwargs: dict
172 | """
173 | issues = {
174 | Processes.IMPORT_STR: set(),
175 | }
176 | red.find_all("ImportNode", value=import_process(issues))
177 | key = Processes.IMPORT_STR
178 |
179 | if issues[key]:
180 | return getattr(Processes, key)(red, issues[key], skip_lineno=skip_lineno)
181 | else:
182 | return ALIAS_DICT, {}
183 |
--------------------------------------------------------------------------------
/src/python/qt_py_convert/_modules/psep0101/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2018 Digital Domain 3.0
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "Apache License")
4 | # with the following modification; you may not use this file except in
5 | # compliance with the Apache License and the following modification to it:
6 | # Section 6. Trademarks. is deleted and replaced with:
7 | #
8 | # 6. Trademarks. This License does not grant permission to use the trade
9 | # names, trademarks, service marks, or product names of the Licensor
10 | # and its affiliates, except as required to comply with Section 4(c) of
11 | # the License and to reproduce the content of the NOTICE file.
12 | #
13 | # You may obtain a copy of the Apache License at
14 | #
15 | # http://www.apache.org/licenses/LICENSE-2.0
16 | #
17 | # Unless required by applicable law or agreed to in writing, software
18 | # distributed under the Apache License with the above modification is
19 | # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20 | # KIND, either express or implied. See the Apache License for the specific
21 | # language governing permissions and limitations under the Apache License.
22 | from qt_py_convert._modules.psep0101.process import process
23 |
--------------------------------------------------------------------------------
/src/python/qt_py_convert/_modules/psep0101/_c_args.py:
--------------------------------------------------------------------------------
1 | # Copyright 2018 Digital Domain 3.0
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "Apache License")
4 | # with the following modification; you may not use this file except in
5 | # compliance with the Apache License and the following modification to it:
6 | # Section 6. Trademarks. is deleted and replaced with:
7 | #
8 | # 6. Trademarks. This License does not grant permission to use the trade
9 | # names, trademarks, service marks, or product names of the Licensor
10 | # and its affiliates, except as required to comply with Section 4(c) of
11 | # the License and to reproduce the content of the NOTICE file.
12 | #
13 | # You may obtain a copy of the Apache License at
14 | #
15 | # http://www.apache.org/licenses/LICENSE-2.0
16 | #
17 | # Unless required by applicable law or agreed to in writing, software
18 | # distributed under the Apache License with the above modification is
19 | # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20 | # KIND, either express or implied. See the Apache License for the specific
21 | # language governing permissions and limitations under the Apache License.
22 | try:
23 | import __builtin__ as builtins
24 | except ImportError:
25 | import builtins
26 |
27 | def pythonize_arg(arg):
28 | if arg in dir(builtins):
29 | return arg
30 | elif "[" in arg or "list" in arg.lower():
31 | return "list"
32 | elif arg == "QString":
33 | return "str"
34 | elif arg == "QVariant":
35 | return "object"
36 | elif arg.startswith("Q"):
37 | return arg
38 | else:
39 | return "object"
40 |
41 |
42 | def parse_args(arg_str):
43 | args = arg_str.split(",")
44 | _final = []
45 | for arg in args:
46 | if not arg:
47 | continue
48 | arg_c = arg.strip("&").strip().split(" ")[-1]
49 |
50 | arg_c = pythonize_arg(arg_c)
51 |
52 | _final.append(arg_c)
53 | final_args = ", ".join(_final)
54 | return final_args
55 |
--------------------------------------------------------------------------------
/src/python/qt_py_convert/_modules/psep0101/_conversion_methods.py:
--------------------------------------------------------------------------------
1 | # Copyright 2018 Digital Domain 3.0
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "Apache License")
4 | # with the following modification; you may not use this file except in
5 | # compliance with the Apache License and the following modification to it:
6 | # Section 6. Trademarks. is deleted and replaced with:
7 | #
8 | # 6. Trademarks. This License does not grant permission to use the trade
9 | # names, trademarks, service marks, or product names of the Licensor
10 | # and its affiliates, except as required to comply with Section 4(c) of
11 | # the License and to reproduce the content of the NOTICE file.
12 | #
13 | # You may obtain a copy of the Apache License at
14 | #
15 | # http://www.apache.org/licenses/LICENSE-2.0
16 | #
17 | # Unless required by applicable law or agreed to in writing, software
18 | # distributed under the Apache License with the above modification is
19 | # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20 | # KIND, either express or implied. See the Apache License for the specific
21 | # language governing permissions and limitations under the Apache License.
22 | import re
23 |
24 |
25 | def to_methods(function_str):
26 | """
27 | to_methods is a helper function that aims to replace all the "toX" methods
28 | from PyQt4-apiV1.0.
29 |
30 | :param function_str: String that represents something that may have the
31 | toX methods in it.
32 | :type function_str: str
33 | :return: A string that, if a method was found, has been cleaned.
34 | :rtype: str
35 | """
36 | match = re.match(
37 | r"""
38 | (?P