1# We don't need to import 'exceptions' 2import os.path 3 4from unyt.exceptions import UnitOperationError 5 6 7class YTException(Exception): 8 def __init__(self, message=None, ds=None): 9 Exception.__init__(self, message) 10 self.ds = ds 11 12 13# Data access exceptions: 14 15 16class YTUnidentifiedDataType(YTException): 17 def __init__(self, filename, *args, **kwargs): 18 self.filename = filename 19 self.args = args 20 self.kwargs = kwargs 21 22 def __str__(self): 23 msg = [f"Could not determine input format from `'{self.filename}'"] 24 if self.args: 25 msg.append(", ".join(str(a) for a in self.args)) 26 if self.kwargs: 27 msg.append(", ".join(f"{k}={v}" for k, v in self.kwargs.items())) 28 msg = ", ".join(msg) + "`." 29 return msg 30 31 32class YTOutputNotIdentified(YTUnidentifiedDataType): 33 def __init__(self, filename, args=None, kwargs=None): 34 super(YTUnidentifiedDataType, self).__init__(filename, args, kwargs) 35 # this cannot be imported at the module level (creates circular imports) 36 from yt._maintenance.deprecation import issue_deprecation_warning 37 38 issue_deprecation_warning( 39 "YTOutputNotIdentified is a deprecated alias for YTUnidentifiedDataType", 40 since="4.0.0", 41 removal="4.1.0", 42 ) 43 44 45class YTAmbiguousDataType(YTUnidentifiedDataType): 46 def __init__(self, filename, candidates): 47 self.filename = filename 48 self.candidates = candidates 49 50 def __str__(self): 51 msg = f"Multiple data type candidates for {self.filename}\n" 52 msg += "The following independent classes were detected as valid :\n" 53 for c in self.candidates: 54 msg += f"{c}\n" 55 msg += "A possible workaround is to directly instantiate one of the above.\n" 56 msg += "Please report this to https://github.com/yt-project/yt/issues/new" 57 return msg 58 59 60class YTSphereTooSmall(YTException): 61 def __init__(self, ds, radius, smallest_cell): 62 YTException.__init__(self, ds=ds) 63 self.radius = radius 64 self.smallest_cell = smallest_cell 65 66 def __str__(self): 67 return f"{self.radius:0.5e} < {self.smallest_cell:0.5e}" 68 69 70class YTAxesNotOrthogonalError(YTException): 71 def __init__(self, axes): 72 self.axes = axes 73 74 def __str__(self): 75 return f"The supplied axes are not orthogonal. {self.axes}" 76 77 78class YTNoDataInObjectError(YTException): 79 def __init__(self, obj): 80 self.obj_type = getattr(obj, "_type_name", "") 81 82 def __str__(self): 83 s = "The object requested has no data included in it." 84 if self.obj_type == "slice": 85 s += " It may lie on a grid face. Try offsetting slightly." 86 return s 87 88 89class YTFieldNotFound(YTException): 90 def __init__(self, field, ds): 91 self.field = field 92 self.ds = ds 93 self.suggestions = [] 94 try: 95 self._find_suggestions() 96 except AttributeError: 97 # This may happen if passing a field that is e.g. an Ellipsis 98 # e.g. when using ds.r[...] 99 pass 100 101 def _find_suggestions(self): 102 from yt.funcs import levenshtein_distance 103 104 field = self.field 105 ds = self.ds 106 107 suggestions = {} 108 if not isinstance(field, tuple): 109 ftype, fname = None, field 110 elif field[1] is None: 111 ftype, fname = None, field[0] 112 else: 113 ftype, fname = field 114 115 # Limit the suggestions to a distance of 3 (at most 3 edits) 116 # This is very arbitrary, but is picked so that... 117 # - small typos lead to meaningful suggestions (e.g. `densty` -> `density`) 118 # - we don't suggest unrelated things (e.g. `pressure` -> `density` has a distance 119 # of 6, we definitely do not want it) 120 # A threshold of 3 seems like a good middle point. 121 max_distance = 3 122 123 # Suggest (ftype, fname), with alternative ftype 124 for ft, fn in ds.derived_field_list: 125 if fn.lower() == fname.lower() and ( 126 ftype is None or ft.lower() != ftype.lower() 127 ): 128 suggestions[ft, fn] = 0 129 130 if ftype is not None: 131 # Suggest close matches using levenshtein distance 132 fields_str = {_: str(_).lower() for _ in ds.derived_field_list} 133 field_str = str(field).lower() 134 135 for (ft, fn), fs in fields_str.items(): 136 distance = levenshtein_distance(field_str, fs, max_dist=max_distance) 137 if distance < max_distance: 138 if (ft, fn) in suggestions: 139 continue 140 suggestions[ft, fn] = distance 141 142 # Return suggestions sorted by increasing distance (first are most likely) 143 self.suggestions = [ 144 (ft, fn) 145 for (ft, fn), distance in sorted(suggestions.items(), key=lambda v: v[1]) 146 ] 147 148 def __str__(self): 149 msg = f"Could not find field {self.field} in {self.ds}." 150 if self.suggestions: 151 msg += "\nDid you mean:\n\t" 152 msg += "\n\t".join(str(_) for _ in self.suggestions) 153 return msg 154 155 156class YTParticleTypeNotFound(YTException): 157 def __init__(self, fname, ds): 158 self.fname = fname 159 self.ds = ds 160 161 def __str__(self): 162 return f"Could not find particle_type '{self.fname}' in {self.ds}." 163 164 165class YTSceneFieldNotFound(YTException): 166 pass 167 168 169class YTCouldNotGenerateField(YTFieldNotFound): 170 def __str__(self): 171 return f"Could field '{self.fname}' in {self.ds} could not be generated." 172 173 174class YTFieldTypeNotFound(YTException): 175 def __init__(self, ftype, ds=None): 176 self.ftype = ftype 177 self.ds = ds 178 179 def __str__(self): 180 if self.ds is not None and self.ftype in self.ds.particle_types: 181 return ( 182 "Could not find field type '%s'. " 183 + "This field type is a known particle type for this dataset. " 184 + "Try adding this field with particle_type=True." 185 ) % self.ftype 186 else: 187 return f"Could not find field type '{self.ftype}'." 188 189 190class YTSimulationNotIdentified(YTException): 191 def __init__(self, sim_type): 192 YTException.__init__(self) 193 self.sim_type = sim_type 194 195 def __str__(self): 196 return f"Simulation time-series type {self.sim_type} not defined." 197 198 199class YTCannotParseFieldDisplayName(YTException): 200 def __init__(self, field_name, display_name, mathtext_error): 201 self.field_name = field_name 202 self.display_name = display_name 203 self.mathtext_error = mathtext_error 204 205 def __str__(self): 206 return ( 207 'The display name "%s" ' 208 "of the derived field %s " 209 "contains the following LaTeX parser errors:\n" 210 ) % (self.display_name, self.field_name) + self.mathtext_error 211 212 213class YTCannotParseUnitDisplayName(YTException): 214 def __init__(self, field_name, unit_name, mathtext_error): 215 self.field_name = field_name 216 self.unit_name = unit_name 217 self.mathtext_error = mathtext_error 218 219 def __str__(self): 220 return ( 221 'The unit display name "%s" ' 222 "of the derived field %s " 223 "contains the following LaTeX parser errors:\n" 224 ) % (self.unit_name, self.field_name) + self.mathtext_error 225 226 227class InvalidSimulationTimeSeries(YTException): 228 def __init__(self, message): 229 self.message = message 230 231 def __str__(self): 232 return self.message 233 234 235class MissingParameter(YTException): 236 def __init__(self, ds, parameter): 237 YTException.__init__(self, ds=ds) 238 self.parameter = parameter 239 240 def __str__(self): 241 return f"dataset {self.ds} is missing {self.parameter} parameter." 242 243 244class NoStoppingCondition(YTException): 245 def __init__(self, ds): 246 YTException.__init__(self, ds=ds) 247 248 def __str__(self): 249 return ( 250 "Simulation %s has no stopping condition. " 251 "StopTime or StopCycle should be set." % self.ds 252 ) 253 254 255class YTNotInsideNotebook(YTException): 256 def __str__(self): 257 return "This function only works from within an IPython Notebook." 258 259 260class YTGeometryNotSupported(YTException): 261 def __init__(self, geom): 262 self.geom = geom 263 264 def __str__(self): 265 return f"We don't currently support {self.geom} geometry" 266 267 268class YTCoordinateNotImplemented(YTException): 269 def __str__(self): 270 return "This coordinate is not implemented for this geometry type." 271 272 273# define for back compat reasons for code written before yt 4.0 274YTUnitOperationError = UnitOperationError 275 276 277class YTUnitNotRecognized(YTException): 278 def __init__(self, unit): 279 self.unit = unit 280 281 def __str__(self): 282 return f"This dataset doesn't recognize {self.unit}" 283 284 285class YTFieldUnitError(YTException): 286 def __init__(self, field_info, returned_units): 287 self.msg = ( 288 "The field function associated with the field '%s' returned " 289 "data with units '%s' but was defined with units '%s'." 290 ) 291 self.msg = self.msg % (field_info.name, returned_units, field_info.units) 292 293 def __str__(self): 294 return self.msg 295 296 297class YTFieldUnitParseError(YTException): 298 def __init__(self, field_info): 299 self.msg = "The field '%s' has unparseable units '%s'." 300 self.msg = self.msg % (field_info.name, field_info.units) 301 302 def __str__(self): 303 return self.msg 304 305 306class YTSpatialFieldUnitError(YTException): 307 def __init__(self, field): 308 msg = ( 309 "Field '%s' is a spatial field but has unknown units but " 310 "spatial fields must have explicitly defined units. Add the " 311 "field with explicit 'units' to clear this error." 312 ) 313 self.msg = msg % (field,) 314 315 def __str__(self): 316 return self.msg 317 318 319class YTHubRegisterError(YTException): 320 def __str__(self): 321 return ( 322 "You must create an API key before uploading. See " 323 + "https://data.yt-project.org/getting_started.html" 324 ) 325 326 327class YTNoFilenamesMatchPattern(YTException): 328 def __init__(self, pattern): 329 self.pattern = pattern 330 331 def __str__(self): 332 return f"No filenames were found to match the pattern: '{self.pattern}'" 333 334 335class YTNoOldAnswer(YTException): 336 def __init__(self, path): 337 self.path = path 338 339 def __str__(self): 340 return f"There is no old answer available.\n{self.path}" 341 342 343class YTNoAnswerNameSpecified(YTException): 344 def __init__(self, message=None): 345 if message is None or message == "": 346 message = ( 347 "Answer name not provided for the answer testing test." 348 "\n Please specify --answer-name=<answer_name> in" 349 " command line mode or in AnswerTestingTest.answer_name" 350 " variable." 351 ) 352 self.message = message 353 354 def __str__(self): 355 return str(self.message) 356 357 358class YTCloudError(YTException): 359 def __init__(self, path): 360 self.path = path 361 362 def __str__(self): 363 return "Failed to retrieve cloud data. Connection may be broken.\n" + str( 364 self.path 365 ) 366 367 368class YTEllipsoidOrdering(YTException): 369 def __init__(self, ds, A, B, C): 370 YTException.__init__(self, ds=ds) 371 self._A = A 372 self._B = B 373 self._C = C 374 375 def __str__(self): 376 return "Must have A>=B>=C" 377 378 379class EnzoTestOutputFileNonExistent(YTException): 380 def __init__(self, filename): 381 self.filename = filename 382 self.testname = os.path.basename(os.path.dirname(filename)) 383 384 def __str__(self): 385 return ( 386 "Enzo test output file (OutputLog) not generated for: " 387 + f"'{self.testname}'" 388 + ".\nTest did not complete." 389 ) 390 391 392class YTNoAPIKey(YTException): 393 def __init__(self, service, config_name): 394 self.service = service 395 self.config_name = config_name 396 397 def __str__(self): 398 return "You need to set an API key for {} in ~/.config/yt/ytrc as {}".format( 399 self.service, 400 self.config_name, 401 ) 402 403 404class YTTooManyVertices(YTException): 405 def __init__(self, nv, fn): 406 self.nv = nv 407 self.fn = fn 408 409 def __str__(self): 410 s = f"There are too many vertices ({self.nv}) to upload to Sketchfab. " 411 s += f"Your model has been saved as {self.fn} . You should upload manually." 412 return s 413 414 415class YTInvalidWidthError(YTException): 416 def __init__(self, width): 417 self.error = f"width ({str(width)}) is invalid" 418 419 def __str__(self): 420 return str(self.error) 421 422 423class YTFieldNotParseable(YTException): 424 def __init__(self, field): 425 self.field = field 426 427 def __str__(self): 428 return f"Cannot identify field {self.field}" 429 430 431class YTDataSelectorNotImplemented(YTException): 432 def __init__(self, class_name): 433 self.class_name = class_name 434 435 def __str__(self): 436 return f"Data selector '{self.class_name}' not implemented." 437 438 439class YTParticleDepositionNotImplemented(YTException): 440 def __init__(self, class_name): 441 self.class_name = class_name 442 443 def __str__(self): 444 return f"Particle deposition method '{self.class_name}' not implemented." 445 446 447class YTDomainOverflow(YTException): 448 def __init__(self, mi, ma, dle, dre): 449 self.mi = mi 450 self.ma = ma 451 self.dle = dle 452 self.dre = dre 453 454 def __str__(self): 455 return "Particle bounds {} and {} exceed domain bounds {} and {}".format( 456 self.mi, 457 self.ma, 458 self.dle, 459 self.dre, 460 ) 461 462 463class YTIntDomainOverflow(YTException): 464 def __init__(self, dims, dd): 465 self.dims = dims 466 self.dd = dd 467 468 def __str__(self): 469 return f"Integer domain overflow: {self.dims} in {self.dd}" 470 471 472class YTIllDefinedFilter(YTException): 473 def __init__(self, filter, s1, s2): 474 self.filter = filter 475 self.s1 = s1 476 self.s2 = s2 477 478 def __str__(self): 479 return "Filter '{}' ill-defined. Applied to shape {} but is shape {}.".format( 480 self.filter, 481 self.s1, 482 self.s2, 483 ) 484 485 486class YTIllDefinedParticleFilter(YTException): 487 def __init__(self, filter, missing): 488 self.filter = filter 489 self.missing = missing 490 491 def __str__(self): 492 msg = ( 493 '\nThe fields\n\t{},\nrequired by the "{}" particle filter, ' 494 "are not defined for this dataset." 495 ) 496 f = self.filter 497 return msg.format("\n".join(str(m) for m in self.missing), f.name) 498 499 500class YTIllDefinedBounds(YTException): 501 def __init__(self, lb, ub): 502 self.lb = lb 503 self.ub = ub 504 505 def __str__(self): 506 v = f"The bounds {self.lb:0.3e} and {self.ub:0.3e} are ill-defined. " 507 v += "Typically this happens when a log binning is specified " 508 v += "and zero or negative values are given for the bounds." 509 return v 510 511 512class YTObjectNotImplemented(YTException): 513 def __init__(self, ds, obj_name): 514 self.ds = ds 515 self.obj_name = obj_name 516 517 def __str__(self): 518 v = r"The object type '%s' is not implemented for the dataset " 519 v += r"'%s'." 520 return v % (self.obj_name, self.ds) 521 522 523class YTParticleOutputFormatNotImplemented(YTException): 524 def __str__(self): 525 return "The particle output format is not supported." 526 527 528class YTFileNotParseable(YTException): 529 def __init__(self, fname, line): 530 self.fname = fname 531 self.line = line 532 533 def __str__(self): 534 v = r"Error while parsing file %s at line %s" 535 return v % (self.fname, self.line) 536 537 538class YTRockstarMultiMassNotSupported(YTException): 539 def __init__(self, mi, ma, ptype): 540 self.mi = mi 541 self.ma = ma 542 self.ptype = ptype 543 544 def __str__(self): 545 v = f"Particle type '{self.ptype}' has minimum mass {self.mi:0.3e} and maximum " 546 v += f"mass {self.ma:0.3e}. Multi-mass particles are not currently supported." 547 return v 548 549 550class YTTooParallel(YTException): 551 def __str__(self): 552 return "You've used too many processors for this dataset." 553 554 555class YTElementTypeNotRecognized(YTException): 556 def __init__(self, dim, num_nodes): 557 self.dim = dim 558 self.num_nodes = num_nodes 559 560 def __str__(self): 561 return "Element type not recognized - dim = {}, num_nodes = {}".format( 562 self.dim, 563 self.num_nodes, 564 ) 565 566 567class YTDuplicateFieldInProfile(Exception): 568 def __init__(self, field, new_spec, old_spec): 569 self.field = field 570 self.new_spec = new_spec 571 self.old_spec = old_spec 572 573 def __str__(self): 574 r = f"""Field {self.field} already exists with field spec: 575 {self.old_spec} 576 But being asked to add it with: 577 {self.new_spec}""" 578 return r 579 580 581class YTInvalidPositionArray(Exception): 582 def __init__(self, shape, dimensions): 583 self.shape = shape 584 self.dimensions = dimensions 585 586 def __str__(self): 587 r = f"""Position arrays must be length and shape (N,3). 588 But this one has {self.dimensions} and {self.shape}.""" 589 return r 590 591 592class YTIllDefinedCutRegion(Exception): 593 def __init__(self, conditions): 594 self.conditions = conditions 595 596 def __str__(self): 597 r = """Can't mix particle/discrete and fluid/mesh conditions or 598 quantities. Conditions specified: 599 """ 600 r += "\n".join(c for c in self.conditions) 601 return r 602 603 604class YTMixedCutRegion(Exception): 605 def __init__(self, conditions, field): 606 self.conditions = conditions 607 self.field = field 608 609 def __str__(self): 610 r = f"""Can't mix particle/discrete and fluid/mesh conditions or 611 quantities. Field: {self.field} and Conditions specified: 612 """ 613 r += "\n".join(c for c in self.conditions) 614 return r 615 616 617class YTGDFAlreadyExists(Exception): 618 def __init__(self, filename): 619 self.filename = filename 620 621 def __str__(self): 622 return f"A file already exists at {self.filename} and overwrite=False." 623 624 625class YTNonIndexedDataContainer(YTException): 626 def __init__(self, cont): 627 self.cont = cont 628 629 def __str__(self): 630 return ( 631 "The data container (%s) is an unindexed type. " 632 "Operations such as ires, icoords, fcoords and fwidth " 633 "will not work on it." % type(self.cont) 634 ) 635 636 637class YTGDFUnknownGeometry(Exception): 638 def __init__(self, geometry): 639 self.geometry = geometry 640 641 def __str__(self): 642 return ( 643 """Unknown geometry %i. Please refer to GDF standard 644 for more information""" 645 % self.geometry 646 ) 647 648 649class YTInvalidUnitEquivalence(Exception): 650 def __init__(self, equiv, unit1, unit2): 651 self.equiv = equiv 652 self.unit1 = unit1 653 self.unit2 = unit2 654 655 def __str__(self): 656 return ( 657 "The unit equivalence '%s' does not exist for the units '%s' and '%s'." 658 % (self.equiv, self.unit1, self.unit2) 659 ) 660 661 662class YTPlotCallbackError(Exception): 663 def __init__(self, callback): 664 self.callback = "annotate_" + callback 665 666 def __str__(self): 667 return f"{self.callback} callback failed" 668 669 670class YTPixelizeError(YTException): 671 def __init__(self, message): 672 self.message = message 673 674 def __str__(self): 675 return self.message 676 677 678class YTDimensionalityError(YTException): 679 def __init__(self, wrong, right): 680 self.wrong = wrong 681 self.right = right 682 683 def __str__(self): 684 return f"Dimensionality specified was {self.wrong} but we need {self.right}" 685 686 687class YTInvalidShaderType(YTException): 688 def __init__(self, source): 689 self.source = source 690 691 def __str__(self): 692 return f"Can't identify shader_type for file '{self.source}.'" 693 694 695class YTInvalidFieldType(YTException): 696 def __init__(self, fields): 697 self.fields = fields 698 699 def __str__(self): 700 msg = ( 701 "\nSlicePlot, ProjectionPlot, and OffAxisProjectionPlot can " 702 "only plot fields that\n" 703 "are defined on a mesh or for SPH particles, but received the " 704 "following N-body\n" 705 "particle fields:\n\n" 706 " %s\n\n" 707 "Did you mean to use ParticlePlot or plot a deposited particle " 708 "field instead?" % self.fields 709 ) 710 return msg 711 712 713class YTUnknownUniformKind(YTException): 714 def __init__(self, kind): 715 self.kind = kind 716 717 def __str__(self): 718 return f"Can't determine kind specification for {self.kind}" 719 720 721class YTUnknownUniformSize(YTException): 722 def __init__(self, size_spec): 723 self.size_spec = size_spec 724 725 def __str__(self): 726 return f"Can't determine size specification for {self.size_spec}" 727 728 729class YTDataTypeUnsupported(YTException): 730 def __init__(self, this, supported): 731 self.supported = supported 732 self.this = this 733 734 def __str__(self): 735 v = f"This operation is not supported for data of geometry {self.this}; " 736 v += f"It supports data of geometries {self.supported}" 737 return v 738 739 740class YTBoundsDefinitionError(YTException): 741 def __init__(self, message, bounds): 742 self.bounds = bounds 743 self.message = message 744 745 def __str__(self): 746 v = "This operation has encountered a bounds error: " 747 v += self.message 748 v += f" Specified bounds are '{self.bounds}'." 749 return v 750 751 752def screen_one_element_list(lis): 753 if len(lis) == 1: 754 return lis[0] 755 return lis 756 757 758class YTIllDefinedProfile(YTException): 759 def __init__(self, bin_fields, fields, weight_field, is_pfield): 760 nbin = len(bin_fields) 761 nfields = len(fields) 762 self.bin_fields = screen_one_element_list(bin_fields) 763 self.bin_fields_ptype = screen_one_element_list(is_pfield[:nbin]) 764 self.fields = screen_one_element_list(fields) 765 self.fields_ptype = screen_one_element_list(is_pfield[nbin : nbin + nfields]) 766 self.weight_field = weight_field 767 if self.weight_field is not None: 768 self.weight_field_ptype = is_pfield[-1] 769 770 def __str__(self): 771 msg = ( 772 "\nCannot create a profile object that mixes particle and mesh " 773 "fields.\n\n" 774 "Received the following bin_fields:\n\n" 775 " %s, particle_type = %s\n\n" 776 "Profile fields:\n\n" 777 " %s, particle_type = %s\n" 778 ) 779 msg = msg % ( 780 self.bin_fields, 781 self.bin_fields_ptype, 782 self.fields, 783 self.fields_ptype, 784 ) 785 786 if self.weight_field is not None: 787 weight_msg = "\nAnd weight field:\n\n %s, particle_type = %s\n" 788 weight_msg = weight_msg % (self.weight_field, self.weight_field_ptype) 789 else: 790 weight_msg = "" 791 792 return msg + weight_msg 793 794 795class YTProfileDataShape(YTException): 796 def __init__(self, field1, shape1, field2, shape2): 797 self.field1 = field1 798 self.shape1 = shape1 799 self.field2 = field2 800 self.shape2 = shape2 801 802 def __str__(self): 803 return ( 804 "Profile fields must have same shape: %s has " 805 + "shape %s and %s has shape %s." 806 ) % (self.field1, self.shape1, self.field2, self.shape2) 807 808 809class YTBooleanObjectError(YTException): 810 def __init__(self, bad_object): 811 self.bad_object = bad_object 812 813 def __str__(self): 814 v = f"Supplied:\n{self.bad_object}\nto a boolean operation" 815 v += " but it is not a YTSelectionContainer3D object." 816 return v 817 818 819class YTBooleanObjectsWrongDataset(YTException): 820 def __init__(self): 821 pass 822 823 def __str__(self): 824 return "Boolean data objects must share a common dataset object." 825 826 827class YTIllDefinedAMR(YTException): 828 def __init__(self, level, axis): 829 self.level = level 830 self.axis = axis 831 832 def __str__(self): 833 msg = ( 834 "Grids on the level {} are not properly aligned with cell edges " 835 "on the parent level ({} axis)" 836 ).format(self.level, self.axis) 837 return msg 838 839 840class YTIllDefinedParticleData(YTException): 841 pass 842 843 844class YTIllDefinedAMRData(YTException): 845 pass 846 847 848class YTInconsistentGridFieldShape(YTException): 849 def __init__(self, shapes): 850 self.shapes = shapes 851 852 def __str__(self): 853 msg = "Not all grid-based fields have the same shape!\n" 854 for name, shape in self.shapes: 855 msg += f" Field {name} has shape {shape}.\n" 856 return msg 857 858 859class YTInconsistentParticleFieldShape(YTException): 860 def __init__(self, ptype, shapes): 861 self.ptype = ptype 862 self.shapes = shapes 863 864 def __str__(self): 865 msg = ("Not all fields with field type '{}' have the same shape!\n").format( 866 self.ptype 867 ) 868 for name, shape in self.shapes: 869 field = (self.ptype, name) 870 msg += f" Field {field} has shape {shape}.\n" 871 return msg 872 873 874class YTInconsistentGridFieldShapeGridDims(YTException): 875 def __init__(self, shapes, grid_dims): 876 self.shapes = shapes 877 self.grid_dims = grid_dims 878 879 def __str__(self): 880 msg = "Not all grid-based fields match the grid dimensions! " 881 msg += f"Grid dims are {self.grid_dims}, " 882 msg += "and the following fields have shapes that do not match them:\n" 883 for name, shape in self.shapes: 884 if shape != self.grid_dims: 885 msg += f" Field {name} has shape {shape}.\n" 886 return msg 887 888 889class YTCommandRequiresModule(YTException): 890 def __init__(self, module): 891 self.module = module 892 893 def __str__(self): 894 msg = f'This command requires "{self.module}" to be installed.\n\n' 895 msg += f'Please install "{self.module}" with the package manager ' 896 msg += "appropriate for your python environment, e.g.:\n" 897 msg += f" conda install {self.module}\n" 898 msg += "or:\n" 899 msg += f" python -m pip install {self.module}\n" 900 return msg 901 902 903class YTModuleRemoved(Exception): 904 def __init__(self, name, new_home=None, info=None): 905 message = f"The {name} module has been removed from yt." 906 if new_home is not None: 907 message += f"\nIt has been moved to {new_home}." 908 if info is not None: 909 message += f"\nFor more information, see {info}." 910 Exception.__init__(self, message) 911 912 913class YTArrayTooLargeToDisplay(YTException): 914 def __init__(self, size, max_size): 915 self.size = size 916 self.max_size = max_size 917 918 def __str__(self): 919 msg = f"The requested array is of size {self.size}.\n" 920 msg += "We do not support displaying arrays larger\n" 921 msg += f"than size {self.max_size}." 922 return msg 923 924 925class GenerationInProgress(Exception): 926 def __init__(self, fields): 927 self.fields = fields 928 super().__init__() 929