| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent f50b38a commit 79ec55e
6 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -159,6 +159,14 @@ The following exceptions are the exceptions that are usually raised. | |||
| 159 | 159 | Raised when an :keyword:`import` statement fails to find the module definition | |
| 160 | 160 | or when a ``from ... import`` fails to find a name that is to be imported. | |
| 161 | 161 | ||
| 162 | + The :attr:`name` and :attr:`path` attributes can be set using keyword-only | ||
| 163 | + arguments to the constructor. When set they represent the name of the module | ||
| 164 | + that was attempted to be imported and the path to any file which triggered | ||
| 165 | + the exception, respectively. | ||
| 166 | + | ||
| 167 | + .. versionchanged:: 3.3 | ||
| 168 | + Added the :attr:`name` and :attr:`path` attributes. | ||
| 169 | + | ||
| 162 | 170 | ||
| 163 | 171 | .. exception:: IndexError | |
| 164 | 172 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -231,6 +231,13 @@ PyAPI_FUNC(PyObject *) PyErr_Format( | |||
| 231 | 231 | ... | |
| 232 | 232 | ); | |
| 233 | 233 | ||
| 234 | + typedef struct { | ||
| 235 | + PyException_HEAD | ||
| 236 | + PyObject *msg; | ||
| 237 | + PyObject *name; | ||
| 238 | + PyObject *path; | ||
| 239 | + } PyImportErrorObject; | ||
| 240 | + | ||
| 234 | 241 | #ifdef MS_WINDOWS | |
| 235 | 242 | PyAPI_FUNC(PyObject *) PyErr_SetFromWindowsErrWithFilename( | |
| 236 | 243 | int ierr, | |
@@ -256,6 +263,12 @@ PyAPI_FUNC(PyObject *) PyErr_SetExcFromWindowsErrWithUnicodeFilename( | |||
| 256 | 263 | PyAPI_FUNC(PyObject *) PyErr_SetExcFromWindowsErr(PyObject *, int); | |
| 257 | 264 | #endif /* MS_WINDOWS */ | |
| 258 | 265 | ||
| 266 | + PyAPI_FUNC(PyObject *) PyErr_SetExcWithArgsKwargs(PyObject *, PyObject *, | ||
| 267 | + PyObject *); | ||
| 268 | + PyAPI_FUNC(PyObject *) PyErr_SetFromImportErrorWithNameAndPath(PyObject *, | ||
| 269 | + PyObject *, PyObject *); | ||
| 270 | + PyAPI_FUNC(PyObject *) PyErr_SetFromImportErrorWithName(PyObject *, PyObject *); | ||
| 271 | + | ||
| 259 | 272 | /* Export the old function so that the existing API remains available: */ | |
| 260 | 273 | PyAPI_FUNC(void) PyErr_BadInternalCall(void); | |
| 261 | 274 | PyAPI_FUNC(void) _PyErr_BadInternalCall(const char *filename, int lineno); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -902,8 +902,30 @@ def test_errno_ENOTDIR(self): | |||
| 902 | 902 | self.assertEqual(cm.exception.errno, errno.ENOTDIR, cm.exception) | |
| 903 | 903 | ||
| 904 | 904 | ||
| 905 | + class ImportErrorTests(unittest.TestCase): | ||
| 906 | + | ||
| 907 | + def test_attributes(self): | ||
| 908 | + # Setting 'name' and 'path' should not be a problem. | ||
| 909 | + exc = ImportError('test') | ||
| 910 | + self.assertIsNone(exc.name) | ||
| 911 | + self.assertIsNone(exc.path) | ||
| 912 | + | ||
| 913 | + exc = ImportError('test', name='somemodule') | ||
| 914 | + self.assertEqual(exc.name, 'somemodule') | ||
| 915 | + self.assertIsNone(exc.path) | ||
| 916 | + | ||
| 917 | + exc = ImportError('test', path='somepath') | ||
| 918 | + self.assertEqual(exc.path, 'somepath') | ||
| 919 | + self.assertIsNone(exc.name) | ||
| 920 | + | ||
| 921 | + exc = ImportError('test', path='somepath', name='somename') | ||
| 922 | + self.assertEqual(exc.name, 'somename') | ||
| 923 | + self.assertEqual(exc.path, 'somepath') | ||
| 924 | + | ||
| 925 | + | ||
| 926 | + | ||
| 905 | 927 | def test_main(): | |
| 906 | - run_unittest(ExceptionTests) | ||
| 928 | + run_unittest(ExceptionTests, ImportErrorTests) | ||
| 907 | 929 | ||
| 908 | 930 | if __name__ == '__main__': | |
| 909 | 931 | unittest.main() | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -10,6 +10,10 @@ What's New in Python 3.3.0 Alpha 3? | |||
| 10 | 10 | Core and Builtins | |
| 11 | 11 | ----------------- | |
| 12 | 12 | ||
| 13 | + - Issue #1559549: ImportError now has 'name' and 'path' attributes that are set | ||
| 14 | + using keyword arguments to its constructor. They are currently not set by | ||
| 15 | + import as they are meant for use by importlib. | ||
| 16 | + | ||
| 13 | 17 | - Issue #14474: Save and restore exception state in thread.start_new_thread() | |
| 14 | 18 | while writing error message if the thread leaves a unhandled exception. | |
| 15 | 19 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -605,9 +605,104 @@ SimpleExtendsException(PyExc_BaseException, KeyboardInterrupt, | |||
| 605 | 605 | /* | |
| 606 | 606 | * ImportError extends Exception | |
| 607 | 607 | */ | |
| 608 | - SimpleExtendsException(PyExc_Exception, ImportError, | ||
| 609 | - "Import can't find module, or can't find name in module."); | ||
| 610 | 608 | ||
| 609 | + static int | ||
| 610 | + ImportError_init(PyImportErrorObject *self, PyObject *args, PyObject *kwds) | ||
| 611 | + { | ||
| 612 | + PyObject *msg = NULL; | ||
| 613 | + PyObject *name = NULL; | ||
| 614 | + PyObject *path = NULL; | ||
| 615 | + | ||
| 616 | + /* Macro replacement doesn't allow ## to start the first line of a macro, | ||
| 617 | + so we move the assignment and NULL check into the if-statement. */ | ||
| 618 | + #define GET_KWD(kwd) { \ | ||
| 619 | + kwd = PyDict_GetItemString(kwds, #kwd); \ | ||
| 620 | + if (kwd) { \ | ||
| 621 | + Py_CLEAR(self->kwd); \ | ||
| 622 | + self->kwd = kwd; \ | ||
| 623 | + Py_INCREF(self->kwd);\ | ||
| 624 | + if (PyDict_DelItemString(kwds, #kwd)) \ | ||
| 625 | + return -1; \ | ||
| 626 | + } \ | ||
| 627 | + } | ||
| 628 | + | ||
| 629 | + if (kwds) { | ||
| 630 | + GET_KWD(name); | ||
| 631 | + GET_KWD(path); | ||
| 632 | + } | ||
| 633 | + | ||
| 634 | + if (BaseException_init((PyBaseExceptionObject *)self, args, kwds) == -1) | ||
| 635 | + return -1; | ||
| 636 | + if (PyTuple_GET_SIZE(args) != 1) | ||
| 637 | + return 0; | ||
| 638 | + if (!PyArg_UnpackTuple(args, "ImportError", 1, 1, &msg)) | ||
| 639 | + return -1; | ||
| 640 | + | ||
| 641 | + Py_CLEAR(self->msg); /* replacing */ | ||
| 642 | + self->msg = msg; | ||
| 643 | + Py_INCREF(self->msg); | ||
| 644 | + | ||
| 645 | + return 0; | ||
| 646 | + } | ||
| 647 | + | ||
| 648 | + static int | ||
| 649 | + ImportError_clear(PyImportErrorObject *self) | ||
| 650 | + { | ||
| 651 | + Py_CLEAR(self->msg); | ||
| 652 | + Py_CLEAR(self->name); | ||
| 653 | + Py_CLEAR(self->path); | ||
| 654 | + return BaseException_clear((PyBaseExceptionObject *)self); | ||
| 655 | + } | ||
| 656 | + | ||
| 657 | + static void | ||
| 658 | + ImportError_dealloc(PyImportErrorObject *self) | ||
| 659 | + { | ||
| 660 | + _PyObject_GC_UNTRACK(self); | ||
| 661 | + ImportError_clear(self); | ||
| 662 | + Py_TYPE(self)->tp_free((PyObject *)self); | ||
| 663 | + } | ||
| 664 | + | ||
| 665 | + static int | ||
| 666 | + ImportError_traverse(PyImportErrorObject *self, visitproc visit, void *arg) | ||
| 667 | + { | ||
| 668 | + Py_VISIT(self->msg); | ||
| 669 | + Py_VISIT(self->name); | ||
| 670 | + Py_VISIT(self->path); | ||
| 671 | + return BaseException_traverse((PyBaseExceptionObject *)self, visit, arg); | ||
| 672 | + } | ||
| 673 | + | ||
| 674 | + static PyObject * | ||
| 675 | + ImportError_str(PyImportErrorObject *self) | ||
| 676 | + { | ||
| 677 | + if (self->msg) { | ||
| 678 | + Py_INCREF(self->msg); | ||
| 679 | + return self->msg; | ||
| 680 | + } | ||
| 681 | + else { | ||
| 682 | + return BaseException_str((PyBaseExceptionObject *)self); | ||
| 683 | + } | ||
| 684 | + } | ||
| 685 | + | ||
| 686 | + static PyMemberDef ImportError_members[] = { | ||
| 687 | + {"msg", T_OBJECT, offsetof(PyImportErrorObject, msg), 0, | ||
| 688 | + PyDoc_STR("exception message")}, | ||
| 689 | + {"name", T_OBJECT, offsetof(PyImportErrorObject, name), 0, | ||
| 690 | + PyDoc_STR("module name")}, | ||
| 691 | + {"path", T_OBJECT, offsetof(PyImportErrorObject, path), 0, | ||
| 692 | + PyDoc_STR("module path")}, | ||
| 693 | + {NULL} /* Sentinel */ | ||
| 694 | + }; | ||
| 695 | + | ||
| 696 | + static PyMethodDef ImportError_methods[] = { | ||
| 697 | + {NULL} | ||
| 698 | + }; | ||
| 699 | + | ||
| 700 | + ComplexExtendsException(PyExc_Exception, ImportError, | ||
| 701 | + ImportError, 0 /* new */, | ||
| 702 | + ImportError_methods, ImportError_members, | ||
| 703 | + 0 /* getset */, ImportError_str, | ||
| 704 | + "Import can't find module, or can't find name in " | ||
| 705 | + "module."); | ||
| 611 | 706 | ||
| 612 | 707 | /* | |
| 613 | 708 | * OSError extends Exception | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -585,6 +585,53 @@ PyObject *PyErr_SetFromWindowsErrWithUnicodeFilename( | |||
| 585 | 585 | } | |
| 586 | 586 | #endif /* MS_WINDOWS */ | |
| 587 | 587 | ||
| 588 | + PyObject * | ||
| 589 | + PyErr_SetExcWithArgsKwargs(PyObject *exc, PyObject *args, PyObject *kwargs) | ||
| 590 | + { | ||
| 591 | + PyObject *val; | ||
| 592 | + | ||
| 593 | + /* args must at least be an empty tuple */ | ||
| 594 | + if (args == NULL) | ||
| 595 | + args = PyTuple_New(0); | ||
| 596 | + | ||
| 597 | + val = PyObject_Call(exc, args, kwargs); | ||
| 598 | + if (val != NULL) { | ||
| 599 | + PyErr_SetObject((PyObject *) Py_TYPE(val), val); | ||
| 600 | + Py_DECREF(val); | ||
| 601 | + } | ||
| 602 | + | ||
| 603 | + return NULL; | ||
| 604 | + } | ||
| 605 | + | ||
| 606 | + PyObject * | ||
| 607 | + PyErr_SetFromImportErrorWithNameAndPath(PyObject *msg, | ||
| 608 | + PyObject *name, PyObject *path) | ||
| 609 | + { | ||
| 610 | + PyObject *args = PyTuple_New(1); | ||
| 611 | + PyObject *kwargs = PyDict_New(); | ||
| 612 | + PyObject *result; | ||
| 613 | + | ||
| 614 | + if (path == NULL) | ||
| 615 | + path = Py_None; | ||
| 616 | + | ||
| 617 | + PyTuple_SetItem(args, 0, msg); | ||
| 618 | + PyDict_SetItemString(kwargs, "name", name); | ||
| 619 | + PyDict_SetItemString(kwargs, "path", path); | ||
| 620 | + | ||
| 621 | + result = PyErr_SetExcWithArgsKwargs(PyExc_ImportError, args, kwargs); | ||
| 622 | + | ||
| 623 | + Py_DECREF(args); | ||
| 624 | + Py_DECREF(kwargs); | ||
| 625 | + | ||
| 626 | + return result; | ||
| 627 | + } | ||
| 628 | + | ||
| 629 | + PyObject * | ||
| 630 | + PyErr_SetFromImportErrorWithName(PyObject *msg, PyObject *name) | ||
| 631 | + { | ||
| 632 | + return PyErr_SetFromImportErrorWithNameAndPath(msg, name, NULL); | ||
| 633 | + } | ||
| 634 | + | ||
| 588 | 635 | void | |
| 589 | 636 | _PyErr_BadInternalCall(const char *filename, int lineno) | |
| 590 | 637 | { | |
| Back | FazBrowse Home | New Git URL |
0 commit comments