Skip to content

Commit

Permalink
fix: schedule.json sets node_name on error. feat: Improve nonexistent…
Browse files Browse the repository at this point in the history
… project error message on cancel.json.
  • Loading branch information
jpmckinney committed Jul 16, 2024
1 parent ee4e036 commit 9110b5e
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 9 deletions.
2 changes: 2 additions & 0 deletions docs/news.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ API
- Clarify some error messages, for example:

- ``'project' parameter is required`` instead of ``'project'``
- ``project 'myproject' not found`` instead of ``'myproject'``
- ``exception class: message`` instead of ``message``
- ``ValueError: Unknown or corrupt egg`` instead of ``TypeError: 'tuple' object is not an iterator``

Expand All @@ -42,6 +43,7 @@ CLI
Fixed
~~~~~

- The :ref:`schedule.json` webservice sets the ``node_name`` field in error responses.
- The :ref:`cancel.json` webservice now works on Windows.
- The :ref:`jobs_to_keep` setting no longer causes an error if a file to delete can't be deleted (for example, if the file is open on Windows).
- When managing multiple projects, the next pending job for all but one project was unreported by the :ref:`daemonstatus.json` and :ref:`listjobs.json` webservices, and was not cancellable by the :ref:`cancel.json` webservice.
Expand Down
16 changes: 11 additions & 5 deletions integration_tests/test_webservice.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def test_schedule():
{
"status": "error",
"message": (
f'Scrapy {scrapy.__version__} - no active project\n\n'
f'RunnerError: Scrapy {scrapy.__version__} - no active project\n\n'
'Unknown command: list\n\n'
'Use "scrapy" to see available commands\n'
),
Expand All @@ -63,7 +63,7 @@ def test_cancel_nonexistent():
assert_webservice(
"post",
"/cancel.json",
{"status": "error", "message": "'nonexistent'"},
{"status": "error", "message": "project 'nonexistent' not found"},
data={"project": "nonexistent", "job": "nojob"},
)

Expand Down Expand Up @@ -92,7 +92,7 @@ def test_listspiders_nonexistent():
{
"status": "error",
"message": (
f'Scrapy {scrapy.__version__} - no active project\n\n'
f'RunnerError: Scrapy {scrapy.__version__} - no active project\n\n'
'Unknown command: list\n\n'
'Use "scrapy" to see available commands\n'
),
Expand All @@ -113,7 +113,10 @@ def test_delversion_nonexistent():
assert_webservice(
"post",
"/delversion.json",
{"status": "error", "message": "[Errno 2] No such file or directory: 'eggs/nonexistent/noegg.egg'"},
{
"status": "error",
"message": "FileNotFoundError: [Errno 2] No such file or directory: 'eggs/nonexistent/noegg.egg'",
},
data={"project": "nonexistent", "version": "noegg"},
)

Expand All @@ -122,6 +125,9 @@ def test_delproject_nonexistent():
assert_webservice(
"post",
"/delproject.json",
{"status": "error", "message": "[Errno 2] No such file or directory: 'eggs/nonexistent'"},
{
"status": "error",
"message": "FileNotFoundError: [Errno 2] No such file or directory: 'eggs/nonexistent'",
},
data={"project": "nonexistent"},
)
14 changes: 10 additions & 4 deletions scrapyd/webservice.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def render(self, txrequest):
message = f"{e} parameter is required"
else:
message = f"{type(e).__name__}: {str(e)}"
r = {"node_name": self.root.nodename, "status": "error", "message": message}
r = self._error(message)
return self.render_object(r, txrequest).encode('utf-8')

def render_OPTIONS(self, txrequest):
Expand All @@ -57,6 +57,9 @@ def render_OPTIONS(self, txrequest):
txrequest.setResponseCode(http.NO_CONTENT)
return b''

def _error(self, message):
return {"node_name": self.root.nodename, "status": "error", "message": message}


class DaemonStatus(WsResource):

Expand Down Expand Up @@ -87,7 +90,7 @@ def render_POST(self, txrequest):
priority = float(args.pop('priority', 0))
spiders = get_spider_list(project, version=version)
if spider not in spiders:
return {"status": "error", "message": "spider '%s' not found" % spider}
return self._error("spider '%s' not found" % spider)
args['settings'] = settings
jobid = args.pop('jobid', uuid.uuid1().hex)
args['_job'] = jobid
Expand All @@ -103,7 +106,10 @@ def render_POST(self, txrequest):
jobid = _get_required_param(args, 'job')
signal = args.get('signal', 'INT' if sys.platform != 'win32' else 'BREAK')
prevstate = None
queue = self.root.poller.queues[project]
try:
queue = self.root.poller.queues[project]
except KeyError as e:
return self._error(f"project {e} not found")
c = queue.remove(lambda x: x["_job"] == jobid)
if c:
prevstate = "pending"
Expand All @@ -120,7 +126,7 @@ class AddVersion(WsResource):
def render_POST(self, txrequest):
egg = _pop_required_param(txrequest.args, b'egg')[0]
if not zipfile.is_zipfile(BytesIO(egg)):
return {"status": "error", "message": "egg is not a ZIP file (if using curl, use egg=@path not egg=path)"}
return self._error("egg is not a ZIP file (if using curl, use egg=@path not egg=path)")
eggf = BytesIO(egg)
args = native_stringify_dict(copy(txrequest.args), keys_only=False)
project = _get_required_param(args, 'project')[0]
Expand Down

0 comments on commit 9110b5e

Please sign in to comment.