CEXT-Dan / PyRx

Python for AutoCAD
42 stars 7 forks source link

Python Packaging #78

Closed gswifort closed 2 months ago

gswifort commented 2 months ago

Originally posted by @gswifort in https://github.com/CEXT-Dan/PyRx/discussions/67#discussioncomment-9687805

gswifort commented 2 months ago

I have taken preliminary steps to pack and distribute the package. https://github.com/gswifort/PyRx/tree/73-cad-bundle-installer

  1. I created a main package called pyrx,
  2. I moved the stub files for PyAp, PyDb, PyEd etc. to pyrx/PyRxStubs. It was necessary to update the imports, for this I also updated genDoc.py,
  3. I moved the ActiveX files to the pyrx/activex directory,
  4. I moved the PyRxDebug.py file to pyrx/debug.py - I also improved it a bit,
  5. I added the pyrx/PyRxBin directory with .*rx files, in the future we plan to copy them (on python -m pyrx bundle --install) to the global directory (%localappdata%\Programs\PyRx\Bin\), according to #73,
  6. I added the files requirements.txt and requirements-dev.txt,
  7. I updated the .gitignore file, many entries are probably redundant there, but I used automatic generation,
  8. I added the setup.py file (please correct/complete the data) and MANIFEST.in,
  9. In the setup.py file I assumed that in the basic version wxpython is enough, while pywin32 is optional (pip install pyrx[activex]), I did not add debugpy at all, when trying to import import pyrx.debug will display an error with the message Optional dependency not installed. Install debugpy (python -m pip install debugpy),
  10. The package version will be read from the file pyrx/__init__.py, I assumed that the package version will be the same as the PyRx*.*rx version.

All you need to do to build the package is activate the virtual environment and run the build.bat file (install the missing packages first (pip install -r requirements-dev.txt). Ready packages will be placed in the dist folder.

A few things to discuss:

CEXT-Dan commented 2 months ago

Wow, you’ve done a lot of amazing work!

I had started on guidelines, but it’s for the C++ stuff, not sure I’m qualified to make guidelines for proper Python lol. Honestly, I started reading PEP8, and I stopped when I got to the underscores, and 79 characters, really? I understand this is a requirement for some companies and Python users will absolutely die on that hill. This project should probably comply... mostly

The only real requirements I have are. Libraries- The must have some test coverage, must not hold on to references longer than necessary, or prevent objects from being garbage collected in a timely manner.

Black is a linter, right? I had installed super-linter and it kicked out all the autogenerated ActiveX stuff. Clang kicked out all the C++ boost::python stuff, which we need. I disabled it for now. I don’t have a problem enabling one for Python, if there’s a way to set it to ignore certain files.

Regarding isort, this changes the order of the imports, correct? This can cause issues as there’s a loading order. I.e.

import PyAp as Ap
import PyDb as Db 

and you will get

Command: PYLOAD PyErr extension class wrapper for base class class PyDbTransactionManager has not been created yet ,Traceback - At (M:\Dev\Projects\PyRxGit\PySamples_doit.py:2): pyload failed:

pyrx_onload. IMHO, that’s too many conditions, too many ways bugs can occur. People will have pyrx_onload files all over and one will eventually contain a stale condition. It should be in one place next to the main module, pyrx_onload can evaluate if it’s being launched from a venv or some other condition.

gswifort commented 2 months ago

Ok, you're quite right about pyrx_onload. So I would stick to the scenarios:

isort - yes, it sorts imports, where sorting should be skipped, we use the comment # isort: skip, I will check if it can be disabled for specific files.

black - it's a code formatter (not a linter) - it takes care of what PEP8 requires (although the line length mentioned is set to 88 characters by default), you don't have to remember it (although it's worth familiarizing yourself with). I know, the PEP8 requirements seem excessive, but if we don't have to take care of them ourselves, they are very good. I will also check if it can be disabled for specific files.

CEXT-Dan commented 2 months ago

An env variable to disable pyrx_onload would be good to have, something like PYRX_DISABLE_ONLOAD = True. If someone wants to debug a system without extra stuff loaded, it would be a good idea to have a way to turn it off.

gswifort commented 2 months ago

An env variable to disable pyrx_onload would be good to have, something like PYRX_DISABLE_ONLOAD = True. If someone wants to debug a system without extra stuff loaded, it would be a good idea to have a way to turn it off.

I agree - I had a similar idea, but I confirm that it is better to do it with a separate variable and not the same one as for setting the path of the pyrx_onload file.

CEXT-Dan commented 2 months ago

Yes, your idea, just inverted I added PYRX_DISABLE_ONLOAD, looks for “1” as a string, instead of “True”

 std::wstring buffer(5, 0);
 GetEnvironmentVariable(_T("PYRX_DISABLE_ONLOAD"), buffer.data(), buffer.size());;
 if (std::stoi(buffer) == 1)
     return;
gswifort commented 2 months ago

Skipping file formatting:

.vscode\settings.json:

{
    "isort.args": [
        "--skip-glob",
        "PyRxStubs/*.py*"
    ],
    "black-formatter.args": [
        "--force-exclude",
        "^/PyRxStubs/.*pyi?"
    ]
}

isort works with glob and black with re expressions

gswifort commented 2 months ago

So we can implement this when you make changes to pyrx_onload?

gswifort commented 2 months ago

You can use twine to publish to PyPI.

CEXT-Dan commented 2 months ago

Thinking about the formatting, all the ActiveX files, I.e. AxApp25.py, BxApp24.py, should be ignored, not reformatted. These are the ones that are generated with win32com’s makepy. For each new release I use WinMerge to move in the changes from the previous release, it’s a tedious task that takes hours. .PYI files are auto generated too, but I don’t have any issues with these being formatted

As a first step, there should only be one pyrx_onload.py, for all environments, it should reside next to the main module, I.e. PyRx25.0.arx. I have a couple of reasons for this

1, it’s not 100% ready and I am able to create some weird side effects with regards to timing OnPyLoadDwg, OnPyInitApp and PyRxLisp_mylisp functions load incorrectly on ZwCAD and BricsCAD.

2, I want users, or the installer to be able to overwrite the file, if necessary, without having to hunt down multiple copies.

3, I want to better understand the behavior. I.e. how relative paths and acedfind file will work.

gswifort commented 2 months ago

I don't quite understand what you use winMerge for?

CEXT-Dan commented 2 months ago

The ActiveX API is stable except for the GUIDs, and LCIDs I have hand modified the files to eliminate the need for users to create safe arrays by injecting converters into the function bodies So, when there’s an update from say AxApp24.py to AxApp25.py. I first auto generate the outline with the correct GUIDs, and LCIDs Then winMerge in my changes, carefully lol. In short if they are reformatted it would be a disaster, I would need to revert changes to these files

gswifort commented 2 months ago

pyrx_onload - we still don't have a solution to the problem we discussed here (I don't know if you intended to solve it). If we have modules installed globally (%localappdata%\Programs\...), then main module (e.g. PyRx25.0.arx) is ALWAYS loaded from there, regardless of where I load RxLoader25.0.arx from and whether I have a virtual environment activated or not. As a result, pyrx_onload.py is also loaded from the global directory. I think that the Loader location should not matter because in CAD we can have it automatically loaded when the application starts, but based on the active environment, the main module (PyRx25.0.arx) should be loaded locally or only if not found, globally. Assuming the current packaging structure (if not changed according to this thread), if we have a virtual environment activated, we should look for the global module (PyRx25.0.arx) here: %VIRTUAL_ENV%\Lib\site-packages\pyrx\PyRxBin \

CEXT-Dan commented 2 months ago

is ALWAYS loaded from there, regardless of where I load

This is correct, but only for the first releases. The env PYRX_DISABLE_ONLOAD was added to opt out