From 0aab5b84c5cacd78c08b1449d37bc7c880ecafbf Mon Sep 17 00:00:00 2001 From: Christian Swinehart Date: Fri, 15 Jul 2022 15:27:30 -0400 Subject: [PATCH 01/32] use api token for pypi access --- .github/workflows/publish.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index f17785d..0bd0c9a 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -23,11 +23,11 @@ jobs: - name: Upload to PyPI env: - TWINE_USERNAME: samizdat - TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} - TWINE_REPOSITORY: https://pypi.org/legacy/ + TWINE_USERNAME: __token__ + TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }} + TWINE_REPOSITORY: https://upload.pypi.org/legacy/ TWINE_NON_INTERACTIVE: 1 run: | - pip3 install twine + pip3 install -U pip twine twine check dist/* twine upload dist/* From 24d214c521a52367f80d1c6ea44ba48e2bd3aa9c Mon Sep 17 00:00:00 2001 From: Christian Swinehart Date: Fri, 15 Jul 2022 15:41:19 -0400 Subject: [PATCH 02/32] debugging publish workflow --- .github/workflows/publish.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 0bd0c9a..d5450f4 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -15,6 +15,7 @@ jobs: - name: Run Tests run: | + pip3 install -U pip wheel twine python3 setup.py test - name: Build sdist @@ -25,9 +26,8 @@ jobs: env: TWINE_USERNAME: __token__ TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }} - TWINE_REPOSITORY: https://upload.pypi.org/legacy/ TWINE_NON_INTERACTIVE: 1 run: | - pip3 install -U pip twine + ls -la ~ twine check dist/* twine upload dist/* From 63992250982590a5290c0135fb9845581c5ccd89 Mon Sep 17 00:00:00 2001 From: Christian Swinehart Date: Fri, 15 Jul 2022 15:52:20 -0400 Subject: [PATCH 03/32] remove debugging --- .github/workflows/publish.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index d5450f4..77ac5b3 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -28,6 +28,5 @@ jobs: TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }} TWINE_NON_INTERACTIVE: 1 run: | - ls -la ~ twine check dist/* twine upload dist/* From d056bed57ff806918ca337fc102fab31a7072234 Mon Sep 17 00:00:00 2001 From: Sean Kelley Date: Wed, 12 Feb 2025 21:53:04 +0100 Subject: [PATCH 04/32] fix: prevent findpath from modifying input points list The findpath function was modifying its input points list when converting tuple coordinates to Point objects. This change makes a copy of the points list before processing to avoid this side effect. --- plotdevice/lib/pathmatics.py | 1 + 1 file changed, 1 insertion(+) diff --git a/plotdevice/lib/pathmatics.py b/plotdevice/lib/pathmatics.py index ecf91ba..9e4ea7e 100644 --- a/plotdevice/lib/pathmatics.py +++ b/plotdevice/lib/pathmatics.py @@ -479,6 +479,7 @@ def findpath(points, curvature=1.0): # The list of points consists of Point objects, # but it shouldn't crash on something straightforward # such as someone supplying a list of (x,y)-tuples. + points = points.copy() # Make a copy to avoid modifying the input for i, pt in enumerate(points): if isinstance(pt, (tuple, list)): points[i] = Point(pt[0], pt[1]) From ba5b4d0bc5499e8218a2983b14dae3d1e4682149 Mon Sep 17 00:00:00 2001 From: Sean Kelley Date: Thu, 13 Feb 2025 10:32:26 +0100 Subject: [PATCH 05/32] Prefix build command with PYTHONNOUSERSITE=1 By prefixing the build command with PYTHONNOUSERSITE=1 we ignore user site packages, ensuring modules are properly installed into the relocatable framework. --- deps/frameworks/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/frameworks/Makefile b/deps/frameworks/Makefile index f085083..613289c 100644 --- a/deps/frameworks/Makefile +++ b/deps/frameworks/Makefile @@ -7,7 +7,7 @@ all: Python.framework $(BIN)/pip3 install --upgrade ../.. Python.framework: relocatable-python - python3 ./relocatable-python/make_relocatable_python_framework.py $(BUILD_OPTS) + PYTHONNOUSERSITE=1 python3 ./relocatable-python/make_relocatable_python_framework.py $(BUILD_OPTS) $(BIN)/python3 config.py ../../app/python.xcconfig relocatable-python: From 6b3c7d18f68c9576b9e5ff114f64d73c30466bf5 Mon Sep 17 00:00:00 2001 From: Sean Kelley Date: Thu, 13 Feb 2025 10:55:05 +0100 Subject: [PATCH 06/32] fix: lazy load HTTP dependencies in readers.py The HTTP session was being initialized at module import time, which required all HTTP-related dependencies to be available before plotdevice could be imported. This caused build failures since the dependencies weren't yet installed during the build process. Changes: - Made HTTP session initialization lazy via get_http_session() - Only import HTTP dependencies when actually making requests - Added better error message if dependencies are missing - Updated read() function to use lazy initialization This allows plotdevice to be imported and built without having HTTP dependencies pre-installed, fixing the circular dependency issue during installation. --- plotdevice/util/readers.py | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/plotdevice/util/readers.py b/plotdevice/util/readers.py index 9a3550f..2cdaa6e 100644 --- a/plotdevice/util/readers.py +++ b/plotdevice/util/readers.py @@ -4,7 +4,7 @@ # files & io from io import open, StringIO, BytesIO -from os.path import abspath, dirname, exists, join, splitext +from os.path import abspath, dirname, exists, join, splitext, expanduser from plotdevice import DeviceError, INTERNAL # data formats @@ -190,13 +190,25 @@ def csv_dialect(fd): ### HTTP utils ### -import requests -from cachecontrol import CacheControl, CacheControlAdapter -from cachecontrol.caches import FileCache -from cachecontrol.heuristics import LastModified +HTTP = None -cache_dir = '%s/Library/Caches/PlotDevice'%os.environ['HOME'] -HTTP = CacheControl(requests.Session(), cache=FileCache(cache_dir), heuristic=LastModified()) +def get_http_session(): + """Returns a cached HTTP session (creating it if necessary)""" + global HTTP + if HTTP is None: + try: + from cachecontrol import CacheControl + from cachecontrol.caches import FileCache + from cachecontrol.heuristics import LastModified + import requests + + cache_dir = join(expanduser('~'), 'Library/Caches/PlotDevice') + HTTP = CacheControl(requests.Session(), + cache=FileCache(cache_dir), + heuristic=LastModified()) + except ImportError as e: + raise ImportError("HTTP dependencies not available. Install with: pip install requests cachecontrol[filecache]") from e + return HTTP def binaryish(content, format): bin_types = ('pdf','eps','png','jpg','jpeg','heic','gif','tiff','tif','zip','tar','gz') @@ -244,7 +256,8 @@ def read(pth, format=None, encoding=None, cols=None, **kwargs): """ if re.match(r'https?:', pth): - resp = HTTP.get(pth) + session = get_http_session() # Get the session only when needed + resp = session.get(pth) resp.raise_for_status() extension_type = splitext(urlparse(pth).path)[-1] From 5e2662bad6c4d70d59c6cc04842887623b519def Mon Sep 17 00:00:00 2001 From: Sean Kelley Date: Thu, 13 Feb 2025 11:42:29 +0100 Subject: [PATCH 07/32] fix: add missing dependency to requirements.txt Added missing dependency that was causing build failures: - filelock: Required by cachecontrol for file caching --- deps/frameworks/requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/deps/frameworks/requirements.txt b/deps/frameworks/requirements.txt index 4823c92..3d9ce21 100644 --- a/deps/frameworks/requirements.txt +++ b/deps/frameworks/requirements.txt @@ -1,5 +1,6 @@ # --no-binary :all: xattr +filelock cachecontrol cffi lockfile From a5f6d754daa8393afc56236f752781e3cc38576f Mon Sep 17 00:00:00 2001 From: Sean Kelley Date: Thu, 13 Feb 2025 11:43:29 +0100 Subject: [PATCH 08/32] update: improve clean command to remove all build artifacts Updated the clean command to remove additional build artifacts: - Added .eggs directory - Added *.egg files - Added __pycache__ directories - Added .pyc files - Added local development virtualenv Also modified CleanCommand to: - Added --dist flag to CleanCommand for dist cleaning - Kept DistCleanCommand as separate command for backward compatibility --- setup.py | 72 +++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 51 insertions(+), 21 deletions(-) diff --git a/setup.py b/setup.py index 749ea83..2b18441 100644 --- a/setup.py +++ b/setup.py @@ -182,33 +182,63 @@ def stale(dst, src): ## Build Commands ## class CleanCommand(Command): - description = "wipe out the ./build & ./dist dirs and other setup-generated files" - user_options = [] + description = "wipe out generated files and build artifacts" + user_options = [ + ('dist', None, 'also remove Python.framework and local dependencies'), + ] + def initialize_options(self): - pass + self.dist = None + def finalize_options(self): pass + def run(self): - os.system('rm -rf ./build ./dist') - os.system('rm -rf plotdevice.egg-info MANIFEST.in PKG') - os.system('rm -rf ./tests/_out ./tests/_diff ./details.html') - os.system('rm -f ./_plotdevice.*.so') - os.system('cd deps/extensions/svg && make clean') - os.system('find plotdevice -name .DS_Store -exec rm {} \;') - os.system('find plotdevice -name \*.pyc -exec rm {} \;') - os.system('find plotdevice -name __pycache__ -type d -prune -exec rmdir {} \;') - -class DistCleanCommand(Command): + paths = [ + 'build', + 'dist', + '*.egg', + '*.egg-info', + '.eggs', + 'MANIFEST.in', + 'PKG', + 'tests/_out', + 'tests/_diff', + 'details.html', + '_plotdevice.*.so', + '**/*.pyc', + '**/__pycache__', + '**/.DS_Store', + ] + + # Add framework paths if --dist flag is used + if self.dist: + paths.extend([ + 'deps/local', + 'deps/frameworks/Python.framework', + 'deps/frameworks/relocatable-python', + ]) + + for path_pattern in paths: + for path in glob(path_pattern, recursive=True): + if exists(path): + print('removing %s'%path) + if os.path.isdir(path): + rmtree(path) + else: + os.unlink(path) + + # Run make clean in svg extensions dir + if exists('deps/extensions/svg'): + os.system('cd deps/extensions/svg && make clean') + +class DistCleanCommand(CleanCommand): + """Alias for `clean --dist` for backward compatibility""" description = "delete Python.framework, local pypi dependencies, and all generated files" - user_options = [] + def initialize_options(self): - pass - def finalize_options(self): - pass - def run(self): - self.run_command('clean') - os.system('rm -rf ./deps/local') - os.system('rm -rf ./deps/frameworks/*.framework') + super().initialize_options() + self.dist = True # always do a deep clean class LocalDevCommand(Command): description = "set up environment to allow for running `python -m plotdevice` within the repo" From 6cd89214537384ac55d561b5506f153a120da65f Mon Sep 17 00:00:00 2001 From: Sean Kelley Date: Thu, 13 Feb 2025 12:40:15 +0100 Subject: [PATCH 09/32] enhancement: add --no-cache flag to app build command Added ability to bypass pip's cache when building the app bundle: - Added --no-cache flag to BuildAppCommand in setup.py - Modified Makefile to conditionally set PIP_NO_CACHE_DIR based on environment - Allows clean builds with fresh package downloads via `python setup.py app --no-cache` --- deps/frameworks/Makefile | 7 +++++-- setup.py | 12 +++++++++--- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/deps/frameworks/Makefile b/deps/frameworks/Makefile index 613289c..151b4fb 100644 --- a/deps/frameworks/Makefile +++ b/deps/frameworks/Makefile @@ -3,11 +3,14 @@ FRAMEWORK_REPO = https://github.com/gregneagle/relocatable-python.git BUILD_OPTS = --os-version=11 --python-version=$(PYTHON_VERSION) --upgrade-pip --pip-requirements=requirements.txt BIN = ./Python.framework/Versions/Current/bin +# Use PIP_NO_CACHE_DIR from environment if set, otherwise empty +PIP_ENV = $(if $(PIP_NO_CACHE_DIR),PIP_NO_CACHE_DIR=1,) + all: Python.framework - $(BIN)/pip3 install --upgrade ../.. + $(PIP_ENV) $(BIN)/pip3 install --upgrade ../.. Python.framework: relocatable-python - PYTHONNOUSERSITE=1 python3 ./relocatable-python/make_relocatable_python_framework.py $(BUILD_OPTS) + PYTHONNOUSERSITE=1 $(PIP_ENV) python3 ./relocatable-python/make_relocatable_python_framework.py $(BUILD_OPTS) $(BIN)/python3 config.py ../../app/python.xcconfig relocatable-python: diff --git a/setup.py b/setup.py index 2b18441..f511056 100644 --- a/setup.py +++ b/setup.py @@ -338,14 +338,20 @@ def run(self): class BuildAppCommand(Command): description = "Build PlotDevice.app with xcode" - user_options = [] + user_options = [ + ('no-cache', None, 'do not use pip cache when installing dependencies'), + ] + def initialize_options(self): - pass + self.no_cache = None def finalize_options(self): # make sure the embedded framework exists (and has updated app/python.xcconfig) print("Set up Python.framework for app build") - call('cd deps/frameworks && make', shell=True) + env = os.environ.copy() + if self.no_cache: + env['PIP_NO_CACHE_DIR'] = '1' + call('cd deps/frameworks && make', shell=True, env=env) def run(self): self.spawn(['xcodebuild', '-configuration', 'Release']) From 01b2fb58d69893d085aacb5337a17731a50eeed2 Mon Sep 17 00:00:00 2001 From: Sean Kelley Date: Mon, 17 Feb 2025 09:18:30 +0100 Subject: [PATCH 10/32] Additional check for image() Throw an error if someone calls image() without any arguments, rather than crashing later when trying to access the non-existent _nsImage --- plotdevice/gfx/image.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plotdevice/gfx/image.py b/plotdevice/gfx/image.py index 9e3915c..ec0d82d 100644 --- a/plotdevice/gfx/image.py +++ b/plotdevice/gfx/image.py @@ -63,6 +63,10 @@ def __init__(self, *args, **kwargs): elif args and args[0] is None: args.pop(0) # make image(None, 10,20, image=...) work properly for compat + # Validate that we have either a source or data + if not (src or data): + raise DeviceError("Image requires either a source (path/url/Image) or image data") + # get an NSImage reference (once way or another) if data: self._nsImage = self._lazyload(data=data) From 217daf0c6b16ecbababb8c8f0aba981c293cd0d2 Mon Sep 17 00:00:00 2001 From: Christian Swinehart Date: Sun, 6 Apr 2025 16:45:55 -0400 Subject: [PATCH 11/32] use `cachecontrol`'s `filecache` support - now uses `filelock` rather than the deprecated `lockfile` --- deps/frameworks/requirements.txt | 4 +--- setup.py | 3 +-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/deps/frameworks/requirements.txt b/deps/frameworks/requirements.txt index 3d9ce21..7529ddc 100644 --- a/deps/frameworks/requirements.txt +++ b/deps/frameworks/requirements.txt @@ -1,9 +1,7 @@ # --no-binary :all: xattr -filelock -cachecontrol +cachecontrol[filecache] cffi -lockfile pyobjc requests six \ No newline at end of file diff --git a/setup.py b/setup.py index f511056..9395675 100644 --- a/setup.py +++ b/setup.py @@ -506,8 +506,7 @@ def codesign(root, name=None, exec=False, entitlement=False): )], install_requires = [ 'requests', - 'cachecontrol', - 'lockfile', + 'cachecontrol[filecache]', 'pyobjc-core==8.5', 'pyobjc-framework-Quartz==8.5', 'pyobjc-framework-LaunchServices==8.5', From 39871e3beadbf137a67c3418a5a7d332a2d047ad Mon Sep 17 00:00:00 2001 From: Christian Swinehart Date: Sun, 6 Apr 2025 16:47:28 -0400 Subject: [PATCH 12/32] remove license from classifiers list - satisfies a deprecation warning from setuptools --- setup.py | 1 - 1 file changed, 1 deletion(-) diff --git a/setup.py b/setup.py index 9395675..cb11db4 100644 --- a/setup.py +++ b/setup.py @@ -47,7 +47,6 @@ "Intended Audience :: Developers", "Intended Audience :: Education", "Intended Audience :: End Users/Desktop", - "License :: OSI Approved :: MIT License", "Operating System :: MacOS :: MacOS X", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.6", From e8fc6d9c13a43933d4b9c08f64dee9b0bffdacdb Mon Sep 17 00:00:00 2001 From: Christian Swinehart Date: Sun, 6 Apr 2025 16:48:05 -0400 Subject: [PATCH 13/32] pin same version of pyobjc in framework & module --- deps/frameworks/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/frameworks/requirements.txt b/deps/frameworks/requirements.txt index 7529ddc..d04f012 100644 --- a/deps/frameworks/requirements.txt +++ b/deps/frameworks/requirements.txt @@ -2,6 +2,6 @@ xattr cachecontrol[filecache] cffi -pyobjc +pyobjc==8.5 requests six \ No newline at end of file From 111d22550bc64ffe890dceaef85015283ea0ed32 Mon Sep 17 00:00:00 2001 From: Christian Swinehart Date: Sun, 6 Apr 2025 18:03:06 -0400 Subject: [PATCH 14/32] add missing `setuptools` dependency --- .github/workflows/test.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fde13dc..e051121 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -15,6 +15,8 @@ jobs: id: repo uses: actions/checkout@v3 - - name: Build PyPI Package - run: | - python3 setup.py test + - name: Add missing setuptools + run: brew install python-setuptools + + - name: Run tests + run: python3 setup.py test From f905b9b128ab82846c90934813995f046e4b556f Mon Sep 17 00:00:00 2001 From: Christian Swinehart Date: Sun, 6 Apr 2025 18:36:40 -0400 Subject: [PATCH 15/32] drop trailing whitespace --- setup.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index cb11db4..ebd2f71 100644 --- a/setup.py +++ b/setup.py @@ -226,7 +226,7 @@ def run(self): rmtree(path) else: os.unlink(path) - + # Run make clean in svg extensions dir if exists('deps/extensions/svg'): os.system('cd deps/extensions/svg && make clean') @@ -234,7 +234,7 @@ def run(self): class DistCleanCommand(CleanCommand): """Alias for `clean --dist` for backward compatibility""" description = "delete Python.framework, local pypi dependencies, and all generated files" - + def initialize_options(self): super().initialize_options() self.dist = True # always do a deep clean @@ -340,7 +340,7 @@ class BuildAppCommand(Command): user_options = [ ('no-cache', None, 'do not use pip cache when installing dependencies'), ] - + def initialize_options(self): self.no_cache = None From 07ad3a9a4aae341eb3c2dbfdab1114ee7729ae8c Mon Sep 17 00:00:00 2001 From: Christian Swinehart Date: Sun, 6 Apr 2025 18:40:04 -0400 Subject: [PATCH 16/32] move the src/data validation into the main conditional --- plotdevice/gfx/image.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/plotdevice/gfx/image.py b/plotdevice/gfx/image.py index ec0d82d..c413681 100644 --- a/plotdevice/gfx/image.py +++ b/plotdevice/gfx/image.py @@ -63,10 +63,6 @@ def __init__(self, *args, **kwargs): elif args and args[0] is None: args.pop(0) # make image(None, 10,20, image=...) work properly for compat - # Validate that we have either a source or data - if not (src or data): - raise DeviceError("Image requires either a source (path/url/Image) or image data") - # get an NSImage reference (once way or another) if data: self._nsImage = self._lazyload(data=data) @@ -81,6 +77,9 @@ def __init__(self, *args, **kwargs): else: invalid = "Not a valid image source: %r" % type(src) raise DeviceError(invalid) + else: + undefined = "Image requires either a source (path/url/Image) or image data" + raise DeviceError(undefined) # set the bounds (in phases) if isinstance(src, Image): From b56d834df8587aace61a147a94ab2e1e3e43249d Mon Sep 17 00:00:00 2001 From: flimsyhat Date: Tue, 15 Apr 2025 09:48:17 +0200 Subject: [PATCH 17/32] use list(points) to copy input list --- plotdevice/lib/pathmatics.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plotdevice/lib/pathmatics.py b/plotdevice/lib/pathmatics.py index 9e4ea7e..b0125b7 100644 --- a/plotdevice/lib/pathmatics.py +++ b/plotdevice/lib/pathmatics.py @@ -479,7 +479,7 @@ def findpath(points, curvature=1.0): # The list of points consists of Point objects, # but it shouldn't crash on something straightforward # such as someone supplying a list of (x,y)-tuples. - points = points.copy() # Make a copy to avoid modifying the input + points = list(points) # copy to avoid modifying the input for i, pt in enumerate(points): if isinstance(pt, (tuple, list)): points[i] = Point(pt[0], pt[1]) From e0903620be472a5f2e761c85613283e6db931fbf Mon Sep 17 00:00:00 2001 From: Sean Kelley Date: Fri, 23 May 2025 20:29:54 +0200 Subject: [PATCH 18/32] fix scaling issue with image export (#76) * fix export zoom percentage bug corrects issue where zoom percentages were being stored as a multiplier, meaning the image size was shrinking with each export * remove print debugging * Revert "remove print debugging" This reverts commit cf58a78e84dd16032157e8d14454cbbcf17285f9. * Revert "fix export zoom percentage bug" This reverts commit 2dfb6476c4af26b0b3fa565136c8388aa08d2d6f. * fix zoom unit conversion - the `self.image["zoom"]` state field now uses 1.0 as 100% - the `self.imageZoom` outlet uses "100" as 100% - when exiting the modal, the zoom value is now persisted correctly (rather than accidentally being divided by 100) --------- Co-authored-by: Christian Swinehart --- plotdevice/gui/widgets.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/plotdevice/gui/widgets.py b/plotdevice/gui/widgets.py index 397e3d7..3c93b59 100644 --- a/plotdevice/gui/widgets.py +++ b/plotdevice/gui/widgets.py @@ -365,10 +365,9 @@ class ExportSheet(NSObject): def awakeFromNib(self): self.formats = dict(image=(0, 'pdf', 0,0, 'png', 'jpg', 'heic', 'tiff', 'gif', 0,0, 'pdf', 'eps'), movie=('mov', 'mov', 'gif')) self.movie = dict(format='mov', first=1, last=150, fps=30, bitrate=1, loop=0, codec=0) - self.image = dict(format='pdf', zoom=100, first=1, last=1, cmyk=False, single=True) + self.image = dict(format='pdf', zoom=1.0, first=1, last=1, cmyk=False, single=True) self.last = None - @objc.python_method def beginExport(self, kind): # configure the accessory controls @@ -464,7 +463,7 @@ def imageState(self, key=None): fmts = self.formats['image'] fmt_idx = self.imageFormat.indexOfSelectedItem() state = dict(format=fmts[fmt_idx], - zoom=self.image['zoom'] / 100, + zoom=self.image['zoom'], first=1, cmyk=self.imageCMYK.state()==NSOnState, single=fmt_idx==1, @@ -497,7 +496,7 @@ def imageZoomStepped_(self, sender): sender.setIntValue_(0) self.imageZoomChanged_(None) # reflect any editing in text field - pct = self.image['zoom'] + pct = self.image['zoom'] * 100 if step > 0: pct = 100 * ceil((pct + 1) / 100) @@ -505,16 +504,16 @@ def imageZoomStepped_(self, sender): pct = 100 * floor((pct - 1) / 100) if 0 < pct < 10000: - self.image['zoom'] = pct + self.image['zoom'] = pct / 100 self.imageZoom.setStringValue_("%i%%" % pct) @IBAction def imageZoomChanged_(self, sender): pct = self.imageZoom.intValue() if pct > 0: - self.image['zoom'] = pct + self.image['zoom'] = pct / 100 else: - pct = self.image['zoom'] + pct = self.image['zoom'] * 100 self.imageZoom.setStringValue_("%i%%" % pct) @IBAction From 2f616bf2f66e79a22c6fb80c96e937beed13f514 Mon Sep 17 00:00:00 2001 From: Christian Swinehart Date: Fri, 23 May 2025 14:37:13 -0400 Subject: [PATCH 19/32] scale PDF page dimensions using `zoom` param - previously the content was scaled, but within the original page size, clipping contents if zoom was > 1 - fixes #70 --- plotdevice/context.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plotdevice/context.py b/plotdevice/context.py index 5f6b3d1..799a9fb 100644 --- a/plotdevice/context.py +++ b/plotdevice/context.py @@ -1777,7 +1777,7 @@ def _getImageData(self, format, zoom=1.0, cmyk=False): w, h = self.pagesize cgData = NSMutableData.data() dataConsumer = CGDataConsumerCreateWithCFData(cgData) - pdfContext = CGPDFContextCreate(dataConsumer, CGRectMake(0, 0, w, h), None) + pdfContext = CGPDFContextCreate(dataConsumer, CGRectMake(0, 0, w*zoom, h*zoom), None) CGPDFContextBeginPage(pdfContext, None) self._render_to_context(pdfContext, zoom) CGPDFContextEndPage(pdfContext) From 89c91e465a1a9b74c7e226906b40befb520bde58 Mon Sep 17 00:00:00 2001 From: Christian Swinehart Date: Fri, 23 May 2025 14:49:08 -0400 Subject: [PATCH 20/32] use wildcard to find compiled swift module - newer versions of the swift compiler generate a file named `SwiftDraw_Module.o` rather than `SwiftDraw.o` - fixes #62 --- deps/extensions/svg/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/extensions/svg/Makefile b/deps/extensions/svg/Makefile index 46f3738..df4cbda 100644 --- a/deps/extensions/svg/Makefile +++ b/deps/extensions/svg/Makefile @@ -7,7 +7,7 @@ all: SwiftDraw.o SwiftDraw.o: SwiftDraw cd SwiftDraw && swift build -c release --target SwiftDraw --arch arm64 --arch x86_64 - cp SwiftDraw/.build/apple/Products/Release/SwiftDraw.o . + cp SwiftDraw/.build/apple/Products/Release/SwiftDraw*.o $@ SwiftDraw: git clone --depth 1 --branch $(TAG) $(REPO) From 047422afb77803c4e0bee62c4e7637a9067f8dac Mon Sep 17 00:00:00 2001 From: Christian Swinehart Date: Fri, 23 May 2025 17:46:19 -0400 Subject: [PATCH 21/32] bump PyObjC to 8.5.1 - adds support for python 3.11 --- deps/frameworks/requirements.txt | 2 +- setup.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/deps/frameworks/requirements.txt b/deps/frameworks/requirements.txt index d04f012..8c84793 100644 --- a/deps/frameworks/requirements.txt +++ b/deps/frameworks/requirements.txt @@ -2,6 +2,6 @@ xattr cachecontrol[filecache] cffi -pyobjc==8.5 +pyobjc==8.5.1 requests six \ No newline at end of file diff --git a/setup.py b/setup.py index ebd2f71..22165f7 100644 --- a/setup.py +++ b/setup.py @@ -506,10 +506,10 @@ def codesign(root, name=None, exec=False, entitlement=False): install_requires = [ 'requests', 'cachecontrol[filecache]', - 'pyobjc-core==8.5', - 'pyobjc-framework-Quartz==8.5', - 'pyobjc-framework-LaunchServices==8.5', - 'pyobjc-framework-WebKit==8.5', + 'pyobjc-core==8.5.1', + 'pyobjc-framework-Quartz==8.5.1', + 'pyobjc-framework-LaunchServices==8.5.1', + 'pyobjc-framework-WebKit==8.5.1', ], scripts = ["app/plotdevice"], zip_safe=False, From 86627cb6dfba8905cec4056abac2be924fb7d060 Mon Sep 17 00:00:00 2001 From: Christian Swinehart Date: Fri, 23 May 2025 18:25:14 -0400 Subject: [PATCH 22/32] bump embedded python framework to 3.11.9 --- app/python.xcconfig | 8 ++++---- deps/frameworks/Makefile | 7 +++++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/app/python.xcconfig b/app/python.xcconfig index 3f55206..697f55d 100644 --- a/app/python.xcconfig +++ b/app/python.xcconfig @@ -1,7 +1,7 @@ // Generated by deps/frameworks/config.py PYTHON_FRAMEWORK = $(PROJECT_DIR)/deps/frameworks/Python.framework -PYTHON = $(PYTHON_FRAMEWORK)/Versions/3.10/bin/python3 -LIBRARY_SEARCH_PATHS = $(inherited) $(PYTHON_FRAMEWORK)/Versions/3.10/lib/python3.10/config-3.10-darwin -HEADER_SEARCH_PATHS = $(inherited) $(PYTHON_FRAMEWORK)/Versions/3.10/include/python3.10 -OTHER_LDFLAGS = $(inherited) -lpython3.10 +PYTHON = $(PYTHON_FRAMEWORK)/Versions/3.11/bin/python3 +LIBRARY_SEARCH_PATHS = $(inherited) $(PYTHON_FRAMEWORK)/Versions/3.11/lib/python3.11/config-3.11-darwin +HEADER_SEARCH_PATHS = $(inherited) $(PYTHON_FRAMEWORK)/Versions/3.11/include/python3.11 +OTHER_LDFLAGS = $(inherited) -lpython3.11 GCC_PREPROCESSOR_DEFINITIONS = $(inherited) PYTHON_BIN="$(PYTHON)" PY3K=1 \ No newline at end of file diff --git a/deps/frameworks/Makefile b/deps/frameworks/Makefile index 151b4fb..3a48160 100644 --- a/deps/frameworks/Makefile +++ b/deps/frameworks/Makefile @@ -1,4 +1,4 @@ -PYTHON_VERSION = 3.10.5 +PYTHON_VERSION = 3.11.9 FRAMEWORK_REPO = https://github.com/gregneagle/relocatable-python.git BUILD_OPTS = --os-version=11 --python-version=$(PYTHON_VERSION) --upgrade-pip --pip-requirements=requirements.txt BIN = ./Python.framework/Versions/Current/bin @@ -6,8 +6,11 @@ BIN = ./Python.framework/Versions/Current/bin # Use PIP_NO_CACHE_DIR from environment if set, otherwise empty PIP_ENV = $(if $(PIP_NO_CACHE_DIR),PIP_NO_CACHE_DIR=1,) +# Use the framework's headers (otherwise clang defaults to looking in /Library/Frameworks/Python.framework) +PIP_INCLUDES = $(shell $(BIN)/python3-config --includes) + all: Python.framework - $(PIP_ENV) $(BIN)/pip3 install --upgrade ../.. + $(PIP_ENV) CFLAGS="$(PIP_INCLUDES)" $(BIN)/pip3 install --upgrade ../.. Python.framework: relocatable-python PYTHONNOUSERSITE=1 $(PIP_ENV) python3 ./relocatable-python/make_relocatable_python_framework.py $(BUILD_OPTS) From be7dc22993447ab97ccbf0323d0f8d075009baff Mon Sep 17 00:00:00 2001 From: Christian Swinehart Date: Fri, 23 May 2025 18:25:47 -0400 Subject: [PATCH 23/32] replace deprecated `getargspec` method --- plotdevice/run/sandbox.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plotdevice/run/sandbox.py b/plotdevice/run/sandbox.py index 52e4462..254298f 100644 --- a/plotdevice/run/sandbox.py +++ b/plotdevice/run/sandbox.py @@ -1,7 +1,7 @@ import os, sys, re, ast from os.path import dirname, basename, abspath, relpath, isdir from functools import partial -from inspect import getargspec +from inspect import getfullargspec from collections import namedtuple from PyObjCTools import AppHelper from ..lib.io import MovieExportSession, ImageExportSession @@ -214,7 +214,7 @@ def run(self, method=None, cmyk=False): func = self.namespace.get(routine) # replace each such routine with a partial application passing # the dict. this means we can .call() it without any explicit args - if callable(func) and getargspec(func).args: + if callable(func) and getfullargspec(func).args: self.namespace[routine] = partial(self.namespace[routine], self._anim) elif method=='draw': From 0a1d0fa7e276a2a29cb5a91ce974bbd38476826e Mon Sep 17 00:00:00 2001 From: Christian Swinehart Date: Sun, 25 May 2025 17:37:24 -0400 Subject: [PATCH 24/32] drop unused imports - `cgi` was removed in python 3.13 causing an import error --- plotdevice/gui/editor.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/plotdevice/gui/editor.py b/plotdevice/gui/editor.py index 3f2393c..7d8044b 100644 --- a/plotdevice/gui/editor.py +++ b/plotdevice/gui/editor.py @@ -2,13 +2,10 @@ import os import re import json -import cgi import objc from io import open from objc import super -from pprint import pprint from time import time -from bisect import bisect from ..lib.cocoa import * from plotdevice.gui.preferences import get_default, editor_info from plotdevice.gui import bundle_path, set_timeout From 09e75b814d65b0b6487cb52ad5a918cebe420673 Mon Sep 17 00:00:00 2001 From: Christian Swinehart Date: Sun, 25 May 2025 17:37:51 -0400 Subject: [PATCH 25/32] fix typo in exported symbols --- plotdevice/run/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plotdevice/run/__init__.py b/plotdevice/run/__init__.py index c1e02f3..0e94e4d 100644 --- a/plotdevice/run/__init__.py +++ b/plotdevice/run/__init__.py @@ -28,4 +28,4 @@ # expose the script-runner object from .sandbox import Sandbox -__all__ = ('objc', 'encoding', 'Sandbox') \ No newline at end of file +__all__ = ('objc', 'encoded', 'Sandbox') \ No newline at end of file From 9d4e46adbc9d28469c0764c93a02b13d6a29afac Mon Sep 17 00:00:00 2001 From: Christian Swinehart Date: Sun, 25 May 2025 17:39:20 -0400 Subject: [PATCH 26/32] bump PyObjC to 11.0 - `objc` is no longer reexported by Foundation so pull it in manually --- deps/frameworks/requirements.txt | 3 ++- plotdevice/run/__init__.py | 2 ++ setup.py | 8 ++++---- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/deps/frameworks/requirements.txt b/deps/frameworks/requirements.txt index 8c84793..150f105 100644 --- a/deps/frameworks/requirements.txt +++ b/deps/frameworks/requirements.txt @@ -2,6 +2,7 @@ xattr cachecontrol[filecache] cffi -pyobjc==8.5.1 +pyobjc==11.0 +py2app requests six \ No newline at end of file diff --git a/plotdevice/run/__init__.py b/plotdevice/run/__init__.py index 0e94e4d..5dc8ec2 100644 --- a/plotdevice/run/__init__.py +++ b/plotdevice/run/__init__.py @@ -5,6 +5,7 @@ try: # test the sys.path by attempting to load a PyObjC submodule... from Foundation import * + import objc except ImportError: # detect whether we're being run from the repository and set up a local env if so repo = abspath(join(dirname(__file__), '../..')) @@ -17,6 +18,7 @@ call([sys.executable, setup_py, 'dev']) site.addsitedir(local_libs) from Foundation import * + import objc else: from pprint import pformat missing = "Searched for PyObjC libraries in:\n%s\nto no avail..."%pformat(sys.path) diff --git a/setup.py b/setup.py index 22165f7..61b181a 100644 --- a/setup.py +++ b/setup.py @@ -506,10 +506,10 @@ def codesign(root, name=None, exec=False, entitlement=False): install_requires = [ 'requests', 'cachecontrol[filecache]', - 'pyobjc-core==8.5.1', - 'pyobjc-framework-Quartz==8.5.1', - 'pyobjc-framework-LaunchServices==8.5.1', - 'pyobjc-framework-WebKit==8.5.1', + 'pyobjc-core==11.0', + 'pyobjc-framework-Quartz==11.0', + 'pyobjc-framework-LaunchServices==11.0', + 'pyobjc-framework-WebKit==11.0', ], scripts = ["app/plotdevice"], zip_safe=False, From 52fef48145e5186b5156c146f7ee4f9436fd8cdb Mon Sep 17 00:00:00 2001 From: Christian Swinehart Date: Sun, 25 May 2025 17:39:59 -0400 Subject: [PATCH 27/32] bump embedded python framework to 3.13.3 --- app/python.xcconfig | 8 ++++---- deps/frameworks/Makefile | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/python.xcconfig b/app/python.xcconfig index 697f55d..868ff60 100644 --- a/app/python.xcconfig +++ b/app/python.xcconfig @@ -1,7 +1,7 @@ // Generated by deps/frameworks/config.py PYTHON_FRAMEWORK = $(PROJECT_DIR)/deps/frameworks/Python.framework -PYTHON = $(PYTHON_FRAMEWORK)/Versions/3.11/bin/python3 -LIBRARY_SEARCH_PATHS = $(inherited) $(PYTHON_FRAMEWORK)/Versions/3.11/lib/python3.11/config-3.11-darwin -HEADER_SEARCH_PATHS = $(inherited) $(PYTHON_FRAMEWORK)/Versions/3.11/include/python3.11 -OTHER_LDFLAGS = $(inherited) -lpython3.11 +PYTHON = $(PYTHON_FRAMEWORK)/Versions/3.13/bin/python3 +LIBRARY_SEARCH_PATHS = $(inherited) $(PYTHON_FRAMEWORK)/Versions/3.13/lib/python3.13/config-3.13-darwin +HEADER_SEARCH_PATHS = $(inherited) $(PYTHON_FRAMEWORK)/Versions/3.13/include/python3.13 +OTHER_LDFLAGS = $(inherited) -lpython3.13 GCC_PREPROCESSOR_DEFINITIONS = $(inherited) PYTHON_BIN="$(PYTHON)" PY3K=1 \ No newline at end of file diff --git a/deps/frameworks/Makefile b/deps/frameworks/Makefile index 3a48160..83ca9ed 100644 --- a/deps/frameworks/Makefile +++ b/deps/frameworks/Makefile @@ -1,4 +1,4 @@ -PYTHON_VERSION = 3.11.9 +PYTHON_VERSION = 3.13.3 FRAMEWORK_REPO = https://github.com/gregneagle/relocatable-python.git BUILD_OPTS = --os-version=11 --python-version=$(PYTHON_VERSION) --upgrade-pip --pip-requirements=requirements.txt BIN = ./Python.framework/Versions/Current/bin From 448dbfa93425b067a26cb8bb70f634abe9b3c54e Mon Sep 17 00:00:00 2001 From: Christian Swinehart Date: Sun, 25 May 2025 17:41:08 -0400 Subject: [PATCH 28/32] target macOS 10.13+ --- PlotDevice.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PlotDevice.xcodeproj/project.pbxproj b/PlotDevice.xcodeproj/project.pbxproj index ba4bca4..9b87e2c 100644 --- a/PlotDevice.xcodeproj/project.pbxproj +++ b/PlotDevice.xcodeproj/project.pbxproj @@ -607,7 +607,7 @@ INFOPLIST_FILE = app/info.plist; INSTALL_PATH = /Applications; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @executable_path/../Frameworks/Python.framework"; - MACOSX_DEPLOYMENT_TARGET = 11.0; + MACOSX_DEPLOYMENT_TARGET = 10.13; ONLY_ACTIVE_ARCH = NO; OTHER_LDFLAGS = "$(inherited)"; PRODUCT_BUNDLE_IDENTIFIER = io.plotdevice.PlotDevice; @@ -637,7 +637,7 @@ INFOPLIST_FILE = app/info.plist; INSTALL_PATH = /Applications; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @executable_path/../Frameworks/Python.framework"; - MACOSX_DEPLOYMENT_TARGET = 11.0; + MACOSX_DEPLOYMENT_TARGET = 10.13; OTHER_LDFLAGS = "$(inherited)"; PRODUCT_BUNDLE_IDENTIFIER = io.plotdevice.PlotDevice; PRODUCT_NAME = PlotDevice; From a4fcc8e27935fa454ae0099225c16a9d77463f16 Mon Sep 17 00:00:00 2001 From: Christian Swinehart Date: Sun, 25 May 2025 17:46:49 -0400 Subject: [PATCH 29/32] disable code-stripping to prevent build failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - A number of the .so files installed by PyObjC trip up Xcode's `/usr/bin/strip`, failing with the error: `internal error: reloc_has_pair() called with unknown cputype (18)` if `COPY_STRIP_PHASE` is set to `YES` - it's not clear to me whether this is a (temporary?) bug in Xcode 16.3 or something that should be fixed in the Python.framework build process… --- PlotDevice.xcodeproj/project.pbxproj | 1 + 1 file changed, 1 insertion(+) diff --git a/PlotDevice.xcodeproj/project.pbxproj b/PlotDevice.xcodeproj/project.pbxproj index 9b87e2c..ac55fb0 100644 --- a/PlotDevice.xcodeproj/project.pbxproj +++ b/PlotDevice.xcodeproj/project.pbxproj @@ -625,6 +625,7 @@ CODE_SIGN_IDENTITY = "-"; COMBINE_HIDPI_IMAGES = YES; CONFIGURATION_BUILD_DIR = dist; + COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_HARDENED_RUNTIME = YES; FRAMEWORK_SEARCH_PATHS = ( From 3fdc89c5c0338ff4a89141467a580364209cfe1d Mon Sep 17 00:00:00 2001 From: Christian Swinehart Date: Fri, 30 May 2025 11:02:53 -0400 Subject: [PATCH 30/32] fix tests on python 3.13 --- tests/compositing.py | 2 +- tests/drawing.py | 2 +- tests/geometry.py | 2 +- tests/module.py | 4 ++-- tests/primitives.py | 2 +- tests/typography.py | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/compositing.py b/tests/compositing.py index 6c73e1b..5db3274 100644 --- a/tests/compositing.py +++ b/tests/compositing.py @@ -111,5 +111,5 @@ def test_beginclip(self): def suite(): suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(CompositingTests)) + suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(CompositingTests)) return suite diff --git a/tests/drawing.py b/tests/drawing.py index 8769369..1d0dbe1 100644 --- a/tests/drawing.py +++ b/tests/drawing.py @@ -479,5 +479,5 @@ def test_strokewidth(self): def suite(): suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(DrawingTests)) + suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(DrawingTests)) return suite diff --git a/tests/geometry.py b/tests/geometry.py index cbbcec2..4819798 100644 --- a/tests/geometry.py +++ b/tests/geometry.py @@ -247,5 +247,5 @@ def test_push(self): def suite(): suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(GeometryTests)) + suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(GeometryTests)) return suite diff --git a/tests/module.py b/tests/module.py index 9a13100..77a30bb 100644 --- a/tests/module.py +++ b/tests/module.py @@ -35,9 +35,9 @@ def test_cli(self): def suite(): - from unittest import TestSuite, makeSuite + from unittest import TestSuite, defaultTestLoader suite = TestSuite() - suite.addTest(makeSuite(ModuleTests)) + suite.addTest(defaultTestLoader.loadTestsFromTestCase(ModuleTests)) return suite \ No newline at end of file diff --git a/tests/primitives.py b/tests/primitives.py index 1c31dd3..4fcf41c 100644 --- a/tests/primitives.py +++ b/tests/primitives.py @@ -160,5 +160,5 @@ def test_star(self): def suite(): suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(PrimitivesTests)) + suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(PrimitivesTests)) return suite diff --git a/tests/typography.py b/tests/typography.py index bc30adb..2f777dc 100644 --- a/tests/typography.py +++ b/tests/typography.py @@ -494,5 +494,5 @@ def test_line_fragment(self): def suite(): suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(TypographyTests)) + suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(TypographyTests)) return suite From bdb55df728a86c7b952bb9c460f318c9b70c5244 Mon Sep 17 00:00:00 2001 From: Christian Swinehart Date: Fri, 30 May 2025 11:03:26 -0400 Subject: [PATCH 31/32] use lazy http session when loading images --- plotdevice/gfx/image.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plotdevice/gfx/image.py b/plotdevice/gfx/image.py index c413681..8817cf0 100644 --- a/plotdevice/gfx/image.py +++ b/plotdevice/gfx/image.py @@ -10,7 +10,7 @@ from plotdevice import DeviceError from ..util import _copy_attrs, autorelease -from ..util.readers import HTTP, last_modified +from ..util.readers import get_http_session, last_modified from ..lib.io import MovieExportSession, ImageExportSession from .geometry import Region, Size, Point, Transform, CENTER from .atoms import TransformMixin, EffectsMixin, FrameMixin, Grob @@ -123,7 +123,7 @@ def _lazyload(self, path=None, data=None): if re.match(r'https?:', path): # load from url key = err_info = path - resp = HTTP.get(path) + resp = get_http_session().get(path) mtime = last_modified(resp) # return a cached image if possible... if path in _cache and _cache[path][1] >= mtime: From 23e234f20942d42dd5f4dd7395fe71e37ae50be1 Mon Sep 17 00:00:00 2001 From: Christian Swinehart Date: Fri, 30 May 2025 11:16:44 -0400 Subject: [PATCH 32/32] remove problematic `py2app` binaries - Xcode was objecting to the legacy fat binaries in the prebuilt dirs - now keeping only the `main-universal2` binary and reenabling symbol stripping in the production build process --- PlotDevice.xcodeproj/project.pbxproj | 2 +- deps/frameworks/Makefile | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/PlotDevice.xcodeproj/project.pbxproj b/PlotDevice.xcodeproj/project.pbxproj index ac55fb0..1464ae4 100644 --- a/PlotDevice.xcodeproj/project.pbxproj +++ b/PlotDevice.xcodeproj/project.pbxproj @@ -625,7 +625,7 @@ CODE_SIGN_IDENTITY = "-"; COMBINE_HIDPI_IMAGES = YES; CONFIGURATION_BUILD_DIR = dist; - COPY_PHASE_STRIP = NO; + COPY_PHASE_STRIP = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_HARDENED_RUNTIME = YES; FRAMEWORK_SEARCH_PATHS = ( diff --git a/deps/frameworks/Makefile b/deps/frameworks/Makefile index 83ca9ed..788b538 100644 --- a/deps/frameworks/Makefile +++ b/deps/frameworks/Makefile @@ -11,6 +11,7 @@ PIP_INCLUDES = $(shell $(BIN)/python3-config --includes) all: Python.framework $(PIP_ENV) CFLAGS="$(PIP_INCLUDES)" $(BIN)/pip3 install --upgrade ../.. + find $(shell find ./Python.framework -name py2app -type d) -name main-\* -not -name \*universal2 -delete Python.framework: relocatable-python PYTHONNOUSERSITE=1 $(PIP_ENV) python3 ./relocatable-python/make_relocatable_python_framework.py $(BUILD_OPTS)