zprocess 2.20.4__tar.gz → 2.21.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. zprocess-2.20.4/.github/workflows/build-and-release.yaml → zprocess-2.21.1/.github/workflows/release.yml +48 -65
  2. {zprocess-2.20.4/zprocess.egg-info → zprocess-2.21.1}/PKG-INFO +1 -4
  3. {zprocess-2.20.4 → zprocess-2.21.1}/setup.py +1 -1
  4. {zprocess-2.20.4 → zprocess-2.21.1}/zprocess/process_tree.py +11 -4
  5. {zprocess-2.20.4 → zprocess-2.21.1}/zprocess/remote/server.py +6 -4
  6. {zprocess-2.20.4 → zprocess-2.21.1}/zprocess/security.py +25 -8
  7. {zprocess-2.20.4 → zprocess-2.21.1}/zprocess/utils.py +32 -2
  8. {zprocess-2.20.4 → zprocess-2.21.1}/zprocess/zlock/__init__.py +2 -2
  9. {zprocess-2.20.4 → zprocess-2.21.1}/zprocess/zlog/__init__.py +9 -3
  10. {zprocess-2.20.4 → zprocess-2.21.1}/zprocess/zlog/server.py +1 -0
  11. {zprocess-2.20.4 → zprocess-2.21.1/zprocess.egg-info}/PKG-INFO +1 -4
  12. {zprocess-2.20.4 → zprocess-2.21.1}/zprocess.egg-info/SOURCES.txt +1 -1
  13. {zprocess-2.20.4 → zprocess-2.21.1}/.coveragerc +0 -0
  14. {zprocess-2.20.4 → zprocess-2.21.1}/.gitignore +0 -0
  15. {zprocess-2.20.4 → zprocess-2.21.1}/.travis.yml +0 -0
  16. {zprocess-2.20.4 → zprocess-2.21.1}/LICENSE.txt +0 -0
  17. {zprocess-2.20.4 → zprocess-2.21.1}/README.md +0 -0
  18. {zprocess-2.20.4 → zprocess-2.21.1}/doc/Makefile +0 -0
  19. {zprocess-2.20.4 → zprocess-2.21.1}/doc/conf.py +0 -0
  20. {zprocess-2.20.4 → zprocess-2.21.1}/doc/index.rst +0 -0
  21. {zprocess-2.20.4 → zprocess-2.21.1}/doc/requirements.txt +0 -0
  22. {zprocess-2.20.4 → zprocess-2.21.1}/pyproject.toml +0 -0
  23. {zprocess-2.20.4 → zprocess-2.21.1}/requirements.txt +0 -0
  24. {zprocess-2.20.4 → zprocess-2.21.1}/run_tests.py +0 -0
  25. {zprocess-2.20.4 → zprocess-2.21.1}/setup.cfg +0 -0
  26. {zprocess-2.20.4 → zprocess-2.21.1}/tests/GUI_output_redirection.py +0 -0
  27. {zprocess-2.20.4 → zprocess-2.21.1}/tests/output_redirection.py +0 -0
  28. {zprocess-2.20.4 → zprocess-2.21.1}/tests/test_remote.py +0 -0
  29. {zprocess-2.20.4 → zprocess-2.21.1}/tests/test_zlock_server.py +0 -0
  30. {zprocess-2.20.4 → zprocess-2.21.1}/tests/test_zlog_server.py +0 -0
  31. {zprocess-2.20.4 → zprocess-2.21.1}/tests/tests.py +0 -0
  32. {zprocess-2.20.4 → zprocess-2.21.1}/zprocess/__init__.py +0 -0
  33. {zprocess-2.20.4 → zprocess-2.21.1}/zprocess/__version__.py +0 -0
  34. {zprocess-2.20.4 → zprocess-2.21.1}/zprocess/clientserver.py +0 -0
  35. {zprocess-2.20.4 → zprocess-2.21.1}/zprocess/cryptoproxy.py +0 -0
  36. {zprocess-2.20.4 → zprocess-2.21.1}/zprocess/examples/example_child.py +0 -0
  37. {zprocess-2.20.4 → zprocess-2.21.1}/zprocess/examples/example_parent.py +0 -0
  38. {zprocess-2.20.4 → zprocess-2.21.1}/zprocess/examples/processclass_example.py +0 -0
  39. {zprocess-2.20.4 → zprocess-2.21.1}/zprocess/examples/processclass_remote_example.py +0 -0
  40. {zprocess-2.20.4 → zprocess-2.21.1}/zprocess/locking/__init__.py +0 -0
  41. {zprocess-2.20.4 → zprocess-2.21.1}/zprocess/locking/__main__.py +0 -0
  42. {zprocess-2.20.4 → zprocess-2.21.1}/zprocess/makesecret.py +0 -0
  43. {zprocess-2.20.4 → zprocess-2.21.1}/zprocess/process_class_wrapper.py +0 -0
  44. {zprocess-2.20.4 → zprocess-2.21.1}/zprocess/remote/__init__.py +0 -0
  45. {zprocess-2.20.4 → zprocess-2.21.1}/zprocess/remote/__main__.py +0 -0
  46. {zprocess-2.20.4 → zprocess-2.21.1}/zprocess/remote/curses_server.py +0 -0
  47. {zprocess-2.20.4 → zprocess-2.21.1}/zprocess/socks/__init__.py +0 -0
  48. {zprocess-2.20.4 → zprocess-2.21.1}/zprocess/socks/server.py +0 -0
  49. {zprocess-2.20.4 → zprocess-2.21.1}/zprocess/tasks.py +0 -0
  50. {zprocess-2.20.4 → zprocess-2.21.1}/zprocess/zlock/__main__.py +0 -0
  51. {zprocess-2.20.4 → zprocess-2.21.1}/zprocess/zlock/server.py +0 -0
  52. {zprocess-2.20.4 → zprocess-2.21.1}/zprocess/zlog/__main__.py +0 -0
  53. {zprocess-2.20.4 → zprocess-2.21.1}/zprocess.egg-info/dependency_links.txt +0 -0
  54. {zprocess-2.20.4 → zprocess-2.21.1}/zprocess.egg-info/not-zip-safe +0 -0
  55. {zprocess-2.20.4 → zprocess-2.21.1}/zprocess.egg-info/requires.txt +0 -0
  56. {zprocess-2.20.4 → zprocess-2.21.1}/zprocess.egg-info/top_level.txt +0 -0
@@ -9,10 +9,6 @@ on:
9
9
  tags:
10
10
  - 'v[0-9]+.[0-9]+.[0-9]+*'
11
11
 
12
- defaults:
13
- run:
14
- shell: bash -l {0}
15
-
16
12
  env:
17
13
  PACKAGE_NAME: zprocess
18
14
  SCM_LOCAL_SCHEME: no-local-version
@@ -41,30 +37,30 @@ jobs:
41
37
  strategy:
42
38
  matrix:
43
39
  include:
44
- - { os: ubuntu-latest, python: 3.9, arch: x64 }
45
- - { os: ubuntu-latest, python: 3.8, arch: x64 }
46
- - { os: ubuntu-latest, python: 3.7, arch: x64 }
47
- - { os: ubuntu-latest, python: 3.6, arch: x64 }
48
-
49
- - { os: macos-latest, python: 3.9, arch: x64 }
50
- - { os: macos-latest, python: 3.8, arch: x64 }
51
- - { os: macos-latest, python: 3.7, arch: x64 }
52
- - { os: macos-latest, python: 3.6, arch: x64 }
53
-
54
- - { os: windows-latest, python: 3.9, arch: x64 }
55
- - { os: windows-latest, python: 3.8, arch: x64 }
56
- - { os: windows-latest, python: 3.7, arch: x64 }
57
- - { os: windows-latest, python: 3.6, arch: x64 }
58
-
59
- - { os: windows-latest, python: 3.9, arch: x86 }
60
- - { os: windows-latest, python: 3.8, arch: x86 }
61
- - { os: windows-latest, python: 3.7, arch: x86 }
62
- - { os: windows-latest, python: 3.6, arch: x86 }
40
+ - { os: ubuntu-latest, python: '3.10', arch: x64 }
41
+ - { os: ubuntu-latest, python: '3.9', arch: x64 }
42
+ - { os: ubuntu-latest, python: '3.8', arch: x64 }
43
+ - { os: ubuntu-latest, python: '3.7', arch: x64 }
44
+
45
+ - { os: macos-10.15, python: '3.10', arch: x64 }
46
+ - { os: macos-10.15, python: '3.9', arch: x64 }
47
+ - { os: macos-10.15, python: '3.8', arch: x64 }
48
+ - { os: macos-10.15, python: '3.7', arch: x64 }
49
+
50
+ - { os: windows-latest, python: '3.10', arch: x64 }
51
+ - { os: windows-latest, python: '3.9', arch: x64 }
52
+ - { os: windows-latest, python: '3.8', arch: x64 }
53
+ - { os: windows-latest, python: '3.7', arch: x64 }
54
+
55
+ - { os: windows-latest, python: '3.10', arch: x86 }
56
+ - { os: windows-latest, python: '3.9', arch: x86 }
57
+ - { os: windows-latest, python: '3.8', arch: x86 }
58
+ - { os: windows-latest, python: '3.7', arch: x86 }
63
59
 
64
60
  if: github.repository == 'chrisjbillington/zprocess' && (github.event_name != 'create' || github.event.ref_type != 'branch')
65
61
  steps:
66
62
  - name: Checkout
67
- uses: actions/checkout@v2
63
+ uses: actions/checkout@v3
68
64
  with:
69
65
  fetch-depth: 0
70
66
 
@@ -73,7 +69,7 @@ jobs:
73
69
  run: git tag -d $(git tag --points-at HEAD)
74
70
 
75
71
  - name: Install Python
76
- uses: actions/setup-python@v2
72
+ uses: actions/setup-python@v4
77
73
  with:
78
74
  python-version: ${{ matrix.python }}
79
75
  architecture: ${{ matrix.arch }}
@@ -93,12 +89,13 @@ jobs:
93
89
 
94
90
  - name: Upload Artifact
95
91
  if: strategy.job-index == 0 || (env.PURE == 'false' && runner.os != 'Linux')
96
- uses: actions/upload-artifact@v2
92
+ uses: actions/upload-artifact@v3
97
93
  with:
98
94
  name: dist
99
95
  path: ./dist
100
96
 
101
97
  - name: Set Variables for Conda Build
98
+ shell: bash
102
99
  run: |
103
100
  if [ $NOARCH == true ]; then
104
101
  CONDA_BUILD_ARGS="--noarch"
@@ -108,10 +105,7 @@ jobs:
108
105
  echo "CONDA_BUILD_ARGS=$CONDA_BUILD_ARGS" >> $GITHUB_ENV
109
106
 
110
107
  - name: Install Miniconda
111
- # We need https://github.com/conda-incubator/setup-miniconda/pull/189 in order
112
- # to be able to install 32-bit miniconda on Windows. Once setup-miniconda 2.1.2
113
- # is released with this fix, can change to @v2.
114
- uses: conda-incubator/setup-miniconda@1a875d105ac03256664b54c882c8c374ce617ef6
108
+ uses: conda-incubator/setup-miniconda@v2
115
109
  with:
116
110
  auto-update-conda: true
117
111
  python-version: ${{ matrix.python }}
@@ -123,9 +117,10 @@ jobs:
123
117
  uses: maxim-lobanov/setup-xcode@v1
124
118
  with:
125
119
  xcode-version: 11.7
126
-
120
+
127
121
  - name: Conda package (Unix)
128
122
  if: runner.os != 'Windows'
123
+ shell: bash -l {0}
129
124
  run: |
130
125
  conda install -c labscript-suite setuptools-conda
131
126
  setuptools-conda build $CONDA_BUILD_ARGS .
@@ -138,7 +133,7 @@ jobs:
138
133
  setuptools-conda build %CONDA_BUILD_ARGS% --croot ${{ runner.temp }}\cb .
139
134
 
140
135
  - name: Upload Artifact
141
- uses: actions/upload-artifact@v2
136
+ uses: actions/upload-artifact@v3
142
137
  with:
143
138
  name: conda_packages
144
139
  path: ./conda_packages
@@ -147,16 +142,11 @@ jobs:
147
142
  manylinux:
148
143
  name: Build Manylinux
149
144
  runs-on: ubuntu-latest
150
- strategy:
151
- matrix:
152
- include:
153
- - { python: 'cp36-cp36m cp37-cp37m cp38-cp38 cp39-cp39' }
154
-
155
145
  if: github.repository == 'chrisjbillington/zprocess' && (github.event_name != 'create' || github.event.ref_type != 'branch')
156
146
  steps:
157
147
  - name: Checkout
158
148
  if: env.PURE == 'false'
159
- uses: actions/checkout@v2
149
+ uses: actions/checkout@v3
160
150
  with:
161
151
  fetch-depth: 0
162
152
 
@@ -166,16 +156,17 @@ jobs:
166
156
 
167
157
  - name: Build Manylinux Wheels
168
158
  if: env.PURE == 'false'
169
- uses: RalfG/python-wheels-manylinux-build@v0.4.0
159
+ uses: RalfG/python-wheels-manylinux-build@v0.4.2
170
160
  with:
171
- python-versions: ${{ matrix.python }}
161
+ python-versions: 'cp37-cp37m cp38-cp38 cp39-cp39 cp310-cp310'
162
+ pre-build-command: 'git config --global --add safe.directory "*"'
172
163
 
173
164
  - name: Upload Artifact
174
165
  if: env.PURE == 'false'
175
- uses: actions/upload-artifact@v2
166
+ uses: actions/upload-artifact@v3
176
167
  with:
177
168
  name: dist
178
- path: wheelhouse/*manylinux*.whl
169
+ path: dist/*manylinux*.whl
179
170
 
180
171
  release:
181
172
  name: Release
@@ -184,56 +175,45 @@ jobs:
184
175
  steps:
185
176
 
186
177
  - name: Download Artifact
187
- uses: actions/download-artifact@v2
178
+ uses: actions/download-artifact@v3
188
179
  with:
189
180
  name: dist
190
181
  path: ./dist
191
182
 
192
183
  - name: Download Artifact
193
- uses: actions/download-artifact@v2
184
+ uses: actions/download-artifact@v3
194
185
  with:
195
186
  name: conda_packages
196
187
  path: ./conda_packages
197
188
 
198
- - name: Publish on TestPyPI
199
- uses: pypa/gh-action-pypi-publish@release/v1
200
- with:
201
- user: __token__
202
- password: ${{ secrets.testpypi }}
203
- repository_url: https://test.pypi.org/legacy/
204
-
205
189
  - name: Get Version Number
206
190
  if: github.event.ref_type == 'tag'
207
191
  run: |
208
192
  VERSION="${GITHUB_REF/refs\/tags\/v/}"
209
193
  echo "VERSION=$VERSION" >> $GITHUB_ENV
210
194
 
211
- - name: Create GitHub Release
195
+ - name: Create GitHub Release and Upload Release Asset
212
196
  if: github.event.ref_type == 'tag'
213
- id: create_release
214
- uses: actions/create-release@latest
197
+ uses: softprops/action-gh-release@v1
215
198
  env:
216
199
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
217
200
  with:
218
201
  tag_name: ${{ github.event.ref }}
219
- release_name: ${{ env.PACKAGE_NAME }} ${{ env.VERSION }}
202
+ name: ${{ env.PACKAGE_NAME }} ${{ env.VERSION }}
220
203
  draft: true
221
204
  prerelease: ${{ contains(github.event.ref, 'rc') }}
205
+ files: ./dist/${{ env.PACKAGE_NAME }}-${{ env.VERSION }}.tar.gz
222
206
 
223
- - name: Upload Release Asset
224
- if: github.event.ref_type == 'tag'
225
- uses: actions/upload-release-asset@v1
226
- env:
227
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
207
+ - name: Publish on TestPyPI
208
+ uses: pypa/gh-action-pypi-publish@release/v1
228
209
  with:
229
- upload_url: ${{ steps.create_release.outputs.upload_url }}
230
- asset_path: ./dist/${{ env.PACKAGE_NAME }}-${{ env.VERSION }}.tar.gz
231
- asset_name: ${{ env.PACKAGE_NAME }}-${{ env.VERSION }}.tar.gz
232
- asset_content_type: application/gzip
210
+ user: __token__
211
+ password: ${{ secrets.testpypi }}
212
+ repository-url: https://test.pypi.org/legacy/
233
213
 
234
214
  - name: Publish on PyPI
235
215
  if: github.event.ref_type == 'tag'
236
- uses: pypa/gh-action-pypi-publish@master
216
+ uses: pypa/gh-action-pypi-publish@release/v1
237
217
  with:
238
218
  user: __token__
239
219
  password: ${{ secrets.pypi }}
@@ -244,10 +224,12 @@ jobs:
244
224
  auto-update-conda: true
245
225
 
246
226
  - name: Install Anaconda cloud client
227
+ shell: bash -l {0}
247
228
  run: conda install anaconda-client
248
229
 
249
230
  - name: Publish to Anaconda test label
250
231
  if: github.event.ref_type != 'tag'
232
+ shell: bash -l {0}
251
233
  run: |
252
234
  anaconda \
253
235
  --token ${{ secrets.ANACONDA_API_TOKEN }} \
@@ -257,6 +239,7 @@ jobs:
257
239
  conda_packages/*/*
258
240
 
259
241
  - name: Publish to Anaconda main label
242
+ shell: bash -l {0}
260
243
  if: github.event.ref_type == 'tag'
261
244
  run: |
262
245
  anaconda \
@@ -1,12 +1,11 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: zprocess
3
- Version: 2.20.4
3
+ Version: 2.21.1
4
4
  Summary: A set of utilities for multiprocessing using zeromq.
5
5
  Home-page: http://github.com/chrisjbillington/zprocess
6
6
  Author: Chris Billington
7
7
  Author-email: chrisjbillington@gmail.com
8
8
  License: BSD
9
- Platform: UNKNOWN
10
9
  Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5
11
10
  Description-Content-Type: text/markdown
12
11
  License-File: LICENSE.txt
@@ -29,5 +28,3 @@ and a process-tree-wide event system.
29
28
 
30
29
  * Install `python setup.py install`.
31
30
 
32
-
33
-
@@ -14,7 +14,7 @@ INSTALL_REQUIRES = [
14
14
  ]
15
15
 
16
16
  VERSION_SCHEME = {
17
- "version_scheme": "release-branch-semver",
17
+ "version_scheme": "guess-next-dev",
18
18
  "local_scheme": os.getenv("SCM_LOCAL_SCHEME", "node-and-date"),
19
19
  }
20
20
 
@@ -24,7 +24,14 @@ if _cwd == 'zprocess' and _path not in sys.path:
24
24
  import ipaddress
25
25
  import zprocess
26
26
  from zprocess.security import SecureContext
27
- from zprocess.utils import gethostbyname, Interruptor, Interrupted, TimeoutError
27
+ from zprocess.utils import (
28
+ gethostbyname,
29
+ Interruptor,
30
+ Interrupted,
31
+ TimeoutError,
32
+ get_venv_executable_and_env,
33
+ _get_fileno
34
+ )
28
35
  from zprocess.remote import (
29
36
  RemoteProcessClient,
30
37
  RemoteOutputReceiver,
@@ -785,7 +792,7 @@ class OutputInterceptor(object):
785
792
  raise RuntimeError(msg)
786
793
  self.streams_connected[self.streamname] = self
787
794
  stream = getattr(sys, self.streamname)
788
- if stream is not None and stream.fileno() > 0:
795
+ if stream is not None and _get_fileno(stream) > 0:
789
796
  self.stream_fd = stream.fileno()
790
797
  else:
791
798
  # On Windows with pythonw, sys.stdout and sys.stderr are None or
@@ -1386,9 +1393,9 @@ class ProcessTree(object):
1386
1393
  extra_env = {k.encode(): v.encode() for k, v in extra_env.items()}
1387
1394
 
1388
1395
  if remote_process_client is None:
1389
- env = os.environ.copy()
1396
+ executable, env = get_venv_executable_and_env(os.environ.copy())
1390
1397
  env.update(extra_env)
1391
- child = subprocess.Popen([sys.executable] + cmd, env=env)
1398
+ child = subprocess.Popen([executable] + cmd, env=env)
1392
1399
  else:
1393
1400
  # The remote server will prefix the path to its own Python interpreter.
1394
1401
  # Also, it will pass to Popen an env consisting of its own env updated with
@@ -14,7 +14,7 @@ else:
14
14
  from weakref import WeakSet
15
15
  import atexit
16
16
  from zprocess import ZMQServer
17
- from zprocess.utils import setup_logging
17
+ from zprocess.utils import setup_logging, get_venv_executable_and_env
18
18
  from zprocess.remote import PROTOCOL_VERSION
19
19
 
20
20
  ERR_INVALID_COMMAND = 'error: invalid command'
@@ -163,9 +163,11 @@ class RemoteProcessServer(ZMQServer):
163
163
 
164
164
  def proxy_Popen(self, cmd, *args, **kwargs):
165
165
  if kwargs.pop('prepend_sys_executable', False):
166
- cmd = [sys.executable] + cmd
166
+ executable, kwargs['env'] = get_venv_executable_and_env(os.environ.copy())
167
+ cmd = [executable] + cmd
168
+ else:
169
+ kwargs['env'] = os.environ.copy()
167
170
  # Update current environment with the contents of 'extra_env', if given:
168
- kwargs['env'] = os.environ.copy()
169
171
  kwargs['env'].update(kwargs.pop('extra_env', {}))
170
172
  if any(kwarg in kwargs for kwarg in ['stdout', 'stdin', 'stderr']):
171
173
  msg = "Cannot specify stdout, stdin or stderr for remote process."
@@ -207,4 +209,4 @@ class RemoteProcessServer(ZMQServer):
207
209
  return PROTOCOL_VERSION
208
210
  else:
209
211
  logger.info('%s: invalid command', self.sock.peer_ip)
210
- return ERR_INVALID_COMMAND
212
+ return ERR_INVALID_COMMAND
@@ -8,6 +8,8 @@ import zmq
8
8
  import zmq.auth.thread
9
9
  from zmq.utils.monitor import recv_monitor_message
10
10
 
11
+ from zprocess.utils import _get_fileno
12
+
11
13
  _path, _cwd = os.path.split(os.getcwd())
12
14
  if _cwd == 'zprocess' and _path not in sys.path:
13
15
  # Running from within zprocess dir? Add to sys.path for testing during
@@ -37,7 +39,7 @@ def _check_versions():
37
39
  except ImportError:
38
40
  # No bundled zmq.
39
41
  return
40
- if sys.stderr is not None and sys.stderr.fileno() >= 0:
42
+ if sys.stderr is not None and _get_fileno(sys.stderr) >= 0:
41
43
  sys.stderr.write(_bundle_warning)
42
44
 
43
45
  # Events to tell when a conneciton has succeeded, including authentication:
@@ -139,7 +141,7 @@ class SecureSocket(zmq.Socket):
139
141
  # remote process server on localhost with no encryption:
140
142
 
141
143
  # Enable IPv6 by default:
142
- # self.ipv6 = True
144
+ self.ipv6 = True
143
145
 
144
146
  def _is_internal(self, endpoint):
145
147
  """Return whether a bind or connect endpoint is on an internal
@@ -147,7 +149,7 @@ class SecureSocket(zmq.Socket):
147
149
  if endpoint.startswith('inproc://'):
148
150
  return True
149
151
  if endpoint.startswith('tcp://'):
150
- host = ''.join(''.join(endpoint.split('//')[1:]).split(':')[0])
152
+ host = endpoint.split('//', 1)[1].rsplit(':', 1)[0]
151
153
  if host.startswith('[') and host.endswith(']'):
152
154
  host = host[1:-1]
153
155
  if host == '*':
@@ -276,7 +278,11 @@ class SecureSocket(zmq.Socket):
276
278
  msg = zmq.Socket.recv(self, flags=flags, copy=False, track=track)
277
279
  if self.tcp:
278
280
  try:
279
- self.peer_ip = msg.get('Peer-Address')
281
+ peer_ip = msg.get('Peer-Address')
282
+ peer_ip = ipaddress.ip_address(peer_ip)
283
+ if peer_ip.version == 6 and peer_ip.ipv4_mapped is not None:
284
+ peer_ip = peer_ip.ipv4_mapped
285
+ self.peer_ip = str(peer_ip)
280
286
  except zmq.error.ZMQError:
281
287
  # Sent by a non-TCP client, even though we are a TCP socket. This is
282
288
  # possible sometimes. For example, XPUB seems to receive unsubscribe
@@ -290,7 +296,7 @@ class SecureSocket(zmq.Socket):
290
296
  msg = INSECURE_RECV_WARNING % self.peer_ip
291
297
  if self.logger is not None:
292
298
  self.logger.warning(msg)
293
- elif sys.stderr is not None and sys.stderr.fileno() >= 0:
299
+ elif sys.stderr is not None and _get_fileno(sys.stderr) >= 0:
294
300
  sys.stderr.write(msg + '\n')
295
301
  # Disregard the insecure message and call recv() again
296
302
  continue
@@ -324,12 +330,23 @@ class SecureContext(zmq.Context):
324
330
  self.client_secretkey, self.server_secretkey = keys
325
331
  self.client_publickey = zmq.curve_public(self.client_secretkey)
326
332
  self.server_publickey = zmq.curve_public(self.server_secretkey)
327
- # Don't hold ref to auth: needed for auto cleanup at shutdown:
333
+
334
+ # There are potential reference cycles causing the authentication thread to
335
+ # prevent the interpreter from shutting down. In pyzmq <25, the
336
+ # authentication thread holds a reference to the context. So we must avoid
337
+ # holding a reference to it. In pyzmq 25+, the authentication thread and
338
+ # threadauthenticator objects both hold references to each other. So we
339
+ # replace one with a weakref to break the cycle.
340
+
328
341
  auth = zmq.auth.thread.ThreadAuthenticator(self)
329
342
  auth.start()
343
+
344
+ if auth.thread.authenticator is auth:
345
+ auth.thread.authenticator = weakref.proxy(auth)
346
+
330
347
  # Allow only clients who have the client public key:
331
- auth.thread.authenticator.allow_any = False
332
- auth.thread.authenticator.certs['*'] = {self.client_publickey: True}
348
+ auth.allow_any = False
349
+ auth.certs['*'] = {self.client_publickey: True}
333
350
  self.secure = True
334
351
 
335
352
  @classmethod
@@ -6,6 +6,8 @@ import logging, logging.handlers
6
6
  from binascii import hexlify
7
7
  import socket
8
8
  import tempfile
9
+ from pathlib import Path
10
+ import io
9
11
 
10
12
  import zmq
11
13
 
@@ -157,6 +159,15 @@ def start_daemon(cmd_args):
157
159
  os._exit(0)
158
160
 
159
161
 
162
+ def _get_fileno(stream):
163
+ """Return stream.get_fileno(), or -1 if the call raises io.UnsupportedOperation"""
164
+ try:
165
+ return stream.fileno()
166
+ except io.UnsupportedOperation:
167
+ # IDLE or Jupyter. Return an invalid fileno
168
+ return -1
169
+
170
+
160
171
  def disable_quick_edit():
161
172
  """Disable the 'quick-edit' misfeature of Windows' cmd.exe, in which a single click
162
173
  on the console puts it in 'select' mode indefinitely, causing writes to stdout from
@@ -168,7 +179,7 @@ def disable_quick_edit():
168
179
  """
169
180
  if os.name == 'nt' and all(
170
181
  [
171
- a is not None and a.isatty() and a.fileno() >= 0
182
+ a is not None and a.isatty() and _get_fileno(a) >= 0
172
183
  for a in (sys.stdin, sys.stdout, sys.stderr)
173
184
  ]
174
185
  ):
@@ -261,4 +272,23 @@ def gethostbyname(host, prefer_ipv4=True, require_ipv4=False):
261
272
  if family == socket.AF_INET:
262
273
  return sockaddr[0]
263
274
  family, _, _, _, sockaddr = results[0]
264
- return sockaddr[0]
275
+ return sockaddr[0]
276
+
277
+
278
+ def get_venv_executable_and_env(env=None):
279
+ """If we are running in a venv on Windows or MacOS such that sys.executable is a
280
+ shim to sys._base_executable, then return sys._base_executable, as well as the
281
+ environment that should be passed to sys._base_executable in order for it to know to
282
+ configure itself for the virtual environment instead of the base environment. This
283
+ allows us to skip the shim and thus have fewer layers in our process hierarchy. If
284
+ we are not in a venv, return sys.executable and the env as passed in. If env passed
285
+ in is None, and needs to be modified for the subprocess, a copy of os.environ(),
286
+ appropriately modified, will be returned."""
287
+ base_executable = getattr(sys, '_base_executable', sys.executable)
288
+ if Path(base_executable) != Path(sys.executable):
289
+ if env is None:
290
+ env = os.environ.copy()
291
+ env["__PYVENV_LAUNCHER__"] = str(sys.executable)
292
+ return base_executable, env
293
+ return sys.executable, env
294
+
@@ -48,8 +48,8 @@ class ZLockClient(object):
48
48
 
49
49
  def __init__(
50
50
  self,
51
- host,
52
- port,
51
+ host='localhost',
52
+ port=DEFAULT_PORT,
53
53
  shared_secret=None,
54
54
  allow_insecure=True,
55
55
  default_timeout=DEFAULT_TIMEOUT,
@@ -47,7 +47,13 @@ class ZLogClient(object):
47
47
 
48
48
  RESPONSE_TIMEOUT = 5000
49
49
 
50
- def __init__(self, host, port, shared_secret=None, allow_insecure=True):
50
+ def __init__(
51
+ self,
52
+ host='localhost',
53
+ port=DEFAULT_PORT,
54
+ shared_secret=None,
55
+ allow_insecure=True,
56
+ ):
51
57
  self.host = socket.gethostbyname(host)
52
58
  self.port = port
53
59
  self.shared_secret = shared_secret
@@ -194,12 +200,12 @@ class ZMQLoggingHandler(Handler):
194
200
 
195
201
 
196
202
 
197
- # Backwards compatibility follots
203
+ # Backwards compatibility follows
198
204
 
199
205
  _default_zlog_client = None
200
206
 
201
207
  _ZMQLoggingHandler = ZMQLoggingHandler
202
- """Backward compatibility to allow instantiating a lock without a ZLockClient as the
208
+ """Backward compatibility to allow instantiating a lock without a ZLogClient as the
203
209
  first argument"""
204
210
  class ZMQLoggingHandler(_ZMQLoggingHandler):
205
211
  def __init__(self, *args, **kwargs):
@@ -77,6 +77,7 @@ class FileHandler(logging.FileHandler):
77
77
  return
78
78
  try:
79
79
  self.stream.write(message + '\n')
80
+ self.flush()
80
81
  except (OSError, IOError):
81
82
  # Nothing to be done.
82
83
  return
@@ -1,12 +1,11 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: zprocess
3
- Version: 2.20.4
3
+ Version: 2.21.1
4
4
  Summary: A set of utilities for multiprocessing using zeromq.
5
5
  Home-page: http://github.com/chrisjbillington/zprocess
6
6
  Author: Chris Billington
7
7
  Author-email: chrisjbillington@gmail.com
8
8
  License: BSD
9
- Platform: UNKNOWN
10
9
  Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5
11
10
  Description-Content-Type: text/markdown
12
11
  License-File: LICENSE.txt
@@ -29,5 +28,3 @@ and a process-tree-wide event system.
29
28
 
30
29
  * Install `python setup.py install`.
31
30
 
32
-
33
-
@@ -7,7 +7,7 @@ pyproject.toml
7
7
  requirements.txt
8
8
  run_tests.py
9
9
  setup.py
10
- .github/workflows/build-and-release.yaml
10
+ .github/workflows/release.yml
11
11
  doc/Makefile
12
12
  doc/conf.py
13
13
  doc/index.rst
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes