├── src ├── compiler │ └── readme.md ├── typespecs │ ├── readme.md │ └── cpython │ │ └── builtins.lumispec ├── language_server │ └── readme.md ├── lumi_runtime │ ├── __init__.py │ ├── type_forms.py │ ├── exceptions.py │ ├── types.py │ └── builtins.py └── readme.md ├── datamodel.md ├── overloads.md ├── definitions.md ├── why_not_x.md ├── theory_outline.md ├── additional_syntax.md ├── numerics.md ├── operator_overloading.md ├── .gitignore ├── theory_overview.md ├── README.md ├── code_generation.md ├── inference.md ├── differences_from_python.md └── LICENSE /src/compiler/readme.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/typespecs/readme.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/language_server/readme.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /datamodel.md: -------------------------------------------------------------------------------- 1 | ### [HEAVY WIP] dascribing the data and object model of python's runtime goes here. 2 | 3 | -------------------------------------------------------------------------------- /src/lumi_runtime/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | This Source Code Form is subject to the terms of the Mozilla Public 3 | License, v. 2.0. If a copy of the MPL was not distributed with this 4 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 5 | 6 | Copyright (C) 2024 Michael Hall 7 | """ -------------------------------------------------------------------------------- /src/lumi_runtime/type_forms.py: -------------------------------------------------------------------------------- 1 | """ 2 | This Source Code Form is subject to the terms of the Mozilla Public 3 | License, v. 2.0. If a copy of the MPL was not distributed with this 4 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 5 | 6 | Copyright (C) 2024 Michael Hall 7 | """ 8 | 9 | # TODO 10 | 11 | 12 | -------------------------------------------------------------------------------- /overloads.md: -------------------------------------------------------------------------------- 1 | ### overloads 2 | 3 | - Lumi does not allow overloads to share an implementation, and requires each type specification to have it's own implementation. 4 | - Lumi will statically skip calling an overload-dispatch system when the types are statically known, generating a direct call to the implementation. 5 | - This results in all overload branches being type safe, while minimizing performance concerns. 6 | - Lumi will generate an efficient underlying dispatch mechanism. -------------------------------------------------------------------------------- /src/lumi_runtime/exceptions.py: -------------------------------------------------------------------------------- 1 | """ 2 | This Source Code Form is subject to the terms of the Mozilla Public 3 | License, v. 2.0. If a copy of the MPL was not distributed with this 4 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 5 | 6 | Copyright (C) 2024 Michael Hall 7 | """ 8 | 9 | from __future__ import annotations 10 | 11 | 12 | class FrozenRecordError(AttributeError): 13 | """Raised when attempting to modify a Lumi record type that was frozen""" 14 | pass -------------------------------------------------------------------------------- /src/typespecs/cpython/builtins.lumispec: -------------------------------------------------------------------------------- 1 | 2 | class type: 3 | ... 4 | 5 | class object: 6 | ... 7 | 8 | class tuple: 9 | ... 10 | 11 | class list: 12 | ... 13 | 14 | class str: 15 | ... 16 | 17 | class memoryview: 18 | ... 19 | 20 | class bool: 21 | ... 22 | 23 | class bytes: 24 | ... 25 | 26 | class int: 27 | ... 28 | 29 | class float: 30 | ... 31 | 32 | class complex: 33 | ... 34 | 35 | class dict: 36 | ... 37 | 38 | class set: 39 | ... 40 | 41 | class frozenset: 42 | ... -------------------------------------------------------------------------------- /definitions.md: -------------------------------------------------------------------------------- 1 | ## Base definitions 2 | 3 | TODO: figure out which definitions can be lifted directly from academic work, 4 | and which ones require additional wording and reasoning for. 5 | 6 | specific TODO after discussion with carljm: 7 | concept of "suitable replacement" needs to be well defined, 8 | otherwise differentiating `Never` and subtyping behavior of `Never` will 9 | end up inconsistent. Also good for this to be well-defined in general. 10 | See also, discussion with DiscordLiz re: Removal of `Never[InfiniteLoop]` 11 | and keeping kinds of `Never` disjoint unless generalized algebraic effects. -------------------------------------------------------------------------------- /why_not_x.md: -------------------------------------------------------------------------------- 1 | # Why not x? 2 | 3 | 4 | ### Why not just use other languages? 5 | 6 | - the existing wealth of python libraries 7 | - the familiarity with python is a huge plus for those working with others 8 | who do not pick up other languages quickly 9 | 10 | ### What about transpiling? 11 | 12 | The closest language I've seen do something "good" here is F#, with Fable 13 | At the point where Fable looks like a good option, I'd rather write F# 14 | 15 | ### what about other supersets of python? 16 | 17 | Mojo looks promising here, but for now, it isn't open source or 18 | production ready. Mojo *could* make this obsolete before it gets off the ground. -------------------------------------------------------------------------------- /src/lumi_runtime/types.py: -------------------------------------------------------------------------------- 1 | """ 2 | This Source Code Form is subject to the terms of the Mozilla Public 3 | License, v. 2.0. If a copy of the MPL was not distributed with this 4 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 5 | 6 | Copyright (C) 2024 Michael Hall 7 | """ 8 | 9 | from __future__ import annotations 10 | from typing import Any 11 | # piggybacking on mumpy's implementation, for now. These are compatible with Lumi's numeric principles 12 | from numpy import uint8, uint16, uint32, uint64, uint128, int8, int16, int32, int64, int128 13 | 14 | 15 | #: This should never be manually used. It's used by Lumi for generating latebound function defaults. 16 | MISSING: Any = object() 17 | -------------------------------------------------------------------------------- /src/readme.md: -------------------------------------------------------------------------------- 1 | ## lumi_runtime 2 | 3 | These are used by lumi when generating python code 4 | 5 | ### builtins.py 6 | 7 | This contains all of the type-safe replaced builtin behavior. 8 | 9 | ### type_forms.py 10 | 11 | This contains type forms that do not exist in python's type system. 12 | These are available for tools which wish to introspect Lumi generated code 13 | Where possible, they are defined in such a way that the existing 14 | *specification compliant* type system will understand them, 15 | but this is done on a "best effort" basis. Use of `Any` is prefered 16 | for cases where python's type system cannot understand. 17 | 18 | ### types.py 19 | 20 | python implementation of Lumi provided additional types 21 | 22 | ### exceptions.py 23 | 24 | exceptions raised by lumi generated code -------------------------------------------------------------------------------- /theory_outline.md: -------------------------------------------------------------------------------- 1 | ### This is just here for me temporarily, so I don't lose track of anything I need to account for 2 | 3 | 4 | - Unions and Intersections 5 | - Filtering by constraint 6 | - subtyping (`<:`) 7 | - refinement types (via guard clauses, Literals) 8 | - Negation, limited to negation of sets of runtime types 9 | - Rules defining a relation between sized numeric types in the type system 10 | - Multiply Expressible lower and upper type bounds, constraints 11 | - Variance interaction with type bounds 12 | - Generics 13 | 14 | To further explore: 15 | 16 | - Higher ranked types (vs fully decidable Unification) 17 | - Dependent types 18 | - TypeConstructors as an explicit concept (ie. type[T] vs Callable[Paramspec.fromcallable[T], T]) 19 | to deal with python's issue with ignoring LSP for construction, and covariant type 20 | - There's probbaly some issues interacting with CPython apis that expect sequences due to variance mismatches... 21 | need to find a way to mark these in a lumi stub based on how lumi code can safely interact with these 22 | functions -------------------------------------------------------------------------------- /additional_syntax.md: -------------------------------------------------------------------------------- 1 | ### Additional syntax 2 | 3 | Lumi provides additional syntax for certain things which will result in generating appropriate code, 4 | while retaining the type checking benefits of that code. In cases where CPython's type system cannot 5 | appropriately handle this, they will be typed in the generated module as `Any` rather than lie about this. 6 | Attempts will be made to generate at minimum sensible structural types for python consumers of your module. 7 | 8 | 9 | Currently planned: 10 | 11 | - Efficient Data only structs (initially to be implemented in python, may change in future) 12 | - Derived numerical types and refinement types (see numerics.md) 13 | - Differing overload behavior (see overloads.md) 14 | - None aware operations (will expand to python code that short circuits on None) 15 | - Late bound function defaults (will still generate a sentinel, but allows ensuring the 16 | type system checks that you removed the generated sentinel by not having this exist in your code) 17 | - Guard clauses 18 | - ADTs (While planned, this one is more tentatively so) -------------------------------------------------------------------------------- /numerics.md: -------------------------------------------------------------------------------- 1 | ### Lumi's numeric system 2 | 3 | TODO: further details, links to theory 4 | 5 | - Lumi comes with support for arbitrary sized and machine sized numerics out of the box 6 | - Lumi's numeric types do not automatically convert between domains, but allow resizing. Resizing behavior is based on the defined behavior of the numeric for overflow and underflow. Converting between types with differing precisions rather than differing bounds requires an explicit conversion. 7 | - Long term: Unit aware numerics 8 | - Operator overloading on numerics is limited, but expressive. 9 | - Types define the behavior for saturation, error, or wrapping 10 | 11 | User defined types may register which operations are defined 12 | 13 | User derived numerics using the default implementation is possible (pseudo syntax, syntax still under development) 14 | This is the encouraged manner to interact with numerics in lumi as safe code will be generated 15 | 16 | ``` 17 | lumi Derived Numeric: 18 | name: Int64 19 | derives: SizedInt 20 | maxsize: 9,223,372,036,854,775,807 21 | minsize: -9,223,372,036,854,775,808 22 | overflow: error 23 | underflow: error 24 | division: truncate 25 | ``` 26 | (Note: several common machine sized types come pre-defined) 27 | -------------------------------------------------------------------------------- /operator_overloading.md: -------------------------------------------------------------------------------- 1 | 2 | - Lumi allows operator overloading. 3 | - Operator overloading is only allowed for types where the relationship has been declared 4 | implementations of operators will be checked against such declarations. 5 | - Lumi has seperate rules for application code and library code. 6 | - Lumi allows some amount of ["Type piracy"](https://docs.julialang.org/en/v1/manual/style-guide/#avoid-type-piracy) 7 | in application code, but not in library code. 8 | - Lumi allows for operator implementations that would be unsafe if further extended in application code, but not in library code. 9 | 10 | ie. (syntax not final) 11 | 12 | ``` 13 | lumi binop-relation: datetime + timedelta = datetime 14 | ``` 15 | 16 | This avoids a few issues that exist in python. 17 | 18 | In python, given an expression, knowing the types of {z,x} or {z, y} does not 19 | give you knowledgeof the unknown of x or y 20 | 21 | x + y = z 22 | 23 | The reasons for this are a combination of both LHS and RHS being able to implement 24 | most binops (some exceptions like `__matmul__`, don't have a corresponding RHS version `__rmatmul__`) 25 | for the other operand noncooperatively, and that the [RHS steals priority from the LHS 26 | when the RHS is a subclass of the LHS](). 27 | 28 | Given the priority placed on inference doing most of the work, asking people who are participating in 29 | operator overloading to just list out the participating overloads their types define 30 | prevents that lack of knowledge. In the future, this may result in special syntax for implementing this 31 | instead, with Lumi generating the correct dunder methods for the generated python code. -------------------------------------------------------------------------------- /src/lumi_runtime/builtins.py: -------------------------------------------------------------------------------- 1 | """ 2 | This Source Code Form is subject to the terms of the Mozilla Public 3 | License, v. 2.0. If a copy of the MPL was not distributed with this 4 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 5 | 6 | Copyright (C) 2024 Michael Hall 7 | """ 8 | 9 | from __future__ import annotations 10 | import numpy as np 11 | from typing import TypeVar, TypeAlias, Mapping, Sequence 12 | import builtins 13 | from functools import lru_cache 14 | 15 | __all__ = ["float", "isinstance", "issubclass", "type"] 16 | 17 | float = np.float64 18 | T = TypeVar("T") 19 | 20 | def type(object: T, /) -> builtins.type[T]: 21 | return builtins.type(object) 22 | 23 | 24 | _clstype: TypeAlias = builtins.type | tuple["_clstype", ...] 25 | 26 | 27 | excluded_type_map: Mapping[builtins.type, Sequence[builtins.type]] = {} 28 | 29 | def isinstance(obj: object, typeinfo: _clstype) -> bool: 30 | return issubclass(type(obj), typeinfo) 31 | 32 | # We don't allow abc.ABC.register use and bypass `__instancecheck__` and `__subclasscheck__` 33 | @lru_cache(512) 34 | def issubclass(cls: builtins.type, typeinfo: _clstype, /) -> bool: 35 | 36 | 37 | if not builtins.isinstance(typeinfo, tuple): 38 | excluded = excluded_type_map.get(typeinfo, ()) 39 | if cls in excluded: 40 | return False 41 | if cls is typeinfo: 42 | return True 43 | for base_type in cls.__bases__: 44 | if base_type not in excluded: 45 | if issubclass(base_type, typeinfo): 46 | return True 47 | 48 | else: 49 | for possible_parent in typeinfo: 50 | if issubclass(cls, possible_parent): 51 | return True 52 | 53 | return False -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | 49 | # Translations 50 | *.mo 51 | *.pot 52 | 53 | # Django stuff: 54 | *.log 55 | local_settings.py 56 | 57 | # Flask stuff: 58 | instance/ 59 | .webassets-cache 60 | 61 | # Scrapy stuff: 62 | .scrapy 63 | 64 | # Sphinx documentation 65 | docs/_build/ 66 | 67 | # PyBuilder 68 | target/ 69 | 70 | # Jupyter Notebook 71 | .ipynb_checkpoints 72 | 73 | # pyenv 74 | .python-version 75 | 76 | # celery beat schedule file 77 | celerybeat-schedule 78 | 79 | # SageMath parsed files 80 | *.sage.py 81 | 82 | # dotenv 83 | .env 84 | 85 | # virtualenv 86 | .venv 87 | venv/ 88 | ENV/ 89 | 90 | # Spyder project settings 91 | .spyderproject 92 | .spyproject 93 | 94 | # Rope project settings 95 | .ropeproject 96 | 97 | # mkdocs documentation 98 | /site 99 | 100 | # mypy 101 | .mypy_cache/ 102 | 103 | # vscode 104 | .vscode/ -------------------------------------------------------------------------------- /theory_overview.md: -------------------------------------------------------------------------------- 1 | TODO: More details 2 | 3 | ## Lumi's typesystem, an overview 4 | 5 | Lumi is designed around a combination of gradual set-theoretic typing, 6 | based on [prior academic work](https://www.irif.fr/~gc/papers/icfp17.pdf) 7 | and a partial inclusion of support for algebraic effects. 8 | Lumi *may* at some much later date gain support for generalized algebraic effects. 9 | 10 | 11 | ### Subtyping 12 | 13 | 1. Subtyping follows from the set-theoretic rules. (TODO: longer doucmentation in a non-overview) 14 | 2. It is an error to declare nominal subtypes which violate concetps of safe substitution (TODO: define safe substitution) 15 | 3. Structural subtyping in Lumi is limited to what is statically provable. 16 | 17 | ### Denotable types 18 | 19 | - All types which can be statically proven should be both expressible and denotable 20 | - Following from this, Structural types may in some cases only be denotable as type bounds 21 | - If there are a large number of cases that suffer ergonomically for this, 22 | syntax better supporting it should be the answer, not allowing it unsafely or ignoring an ergonomic issue. 23 | 24 | ### Exceptions 25 | 26 | Most academic work here has not treated Exceptions as control flow or as having values. 27 | Lumi has a partial understanding of the different kinds of Exceptions in the CPython runtime, and 28 | differentiates between the effects of a subset of them. 29 | 30 | In particular, Lumi encodes a limited amount of type information or control flow information based on 31 | each of the following python Exceptions. (N.B. This may not be an exhaustive list.) 32 | 33 | - StopIteration 34 | - KeyError 35 | - IndexError 36 | - GeneratorExit 37 | - asyncio.CancelledError 38 | - KeyboardInterrupt 39 | - OverflowError 40 | - ZeroDivisionError 41 | - LookupError 42 | - ImportError 43 | - NotImplementedError 44 | 45 | Despite having typesystem encoded knowledge about exceptions, **Lumi does not, and will not, have checked exceptions** 46 | 47 | ### Exceptions carry limited type information and are runtime values 48 | 49 | While exceptions are not checked and you are not required to catch all possible exceptions, never the less, exceptions are values that when raised trigger alternative code flow. 50 | 51 | As such, given an annotation : `T`, Lumi understands this as `T | Never[Error]` 52 | 53 | ### Why `Never[Error]` exists, and why and how Lumi has multuple understandings of `Never` 54 | 55 | Lumi has multiple kinds of "Never" categorized by a partially encoded understanding of 56 | algebraic effects. 57 | 58 | These are 59 | 60 | - `Never[Logical]` 61 | - `Never[Error]` 62 | 63 | Of these, `Never[Error]` is implicitly always possible when targeting the CPython 64 | runtime (Note: currently this is the only target) 65 | 66 | `Never[Error]` is not considered to be a subtype of any runtime type, 67 | and is essentially the effect of raising an exception. 68 | While this is always implicitly possible, you 69 | may explicitly mark functions that always raise with this return type. 70 | 71 | `Never[Logical]` is the logical abscence of a valid type, usually by exhaustive narrowing 72 | `Never[Logical]` *is not* valid as a return type in Lumi as it is impossible to return a non-existant value. 73 | `Never[Logical]` *is* a subtype of all concrete types. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # lumi 2 | A replacement for python's type system. 3 | 4 | ## What? 5 | 6 | Write code that looks and feels like python in a type safe manner, 7 | leverage existing python code, get a python module that is type checked. 8 | Have best effort type annotations for the existing type system as well. 9 | 10 | 11 | ## Why? 12 | 13 | All projects worth pursuing need to first answer "is this needed?" 14 | 15 | Python's type system is built on a foundation of "pragmatic lies". 16 | The current leadership surrounding typing decisions for python sees this as 17 | a good thing and that there is just too much depending on this to change it, 18 | but when issues with this are raised, concerns about type safety are often 19 | dismissed as "merely academic" or by dismissing that users want more type safety 20 | than is currently provided or even possible. 21 | 22 | One pragmatic answer to this as a user would be to go use a language that 23 | enables users to have what they want from it, but this ignores existing code, 24 | the cost of converting, and a wealth of python libraries. 25 | 26 | There is no strong statically checkable type safety to be had through python's 27 | type system. Those who care about it must by neccessity ignore the specification, 28 | and the specification being treated in this way prevents any 29 | "specification-compliant" type checker from fixing the problems. 30 | This goes so deep as to have lies about the basic structure of builtin types specified. 31 | 32 | So the answer to why, is that I've found this to be a large enough hole in 33 | what exists in python that does not seem possible to resolve by 34 | cooperation with those involved as members of CPython. 35 | 36 | 37 | ### A measured followup to the above 38 | 39 | Many of the issues with python's type system are old, or in some cases even 40 | predate the type system. ABC registration, python's float behavior, 41 | and a few others apply here. 42 | 43 | Many further issues with python's type system are deep seated and would have 44 | excessive costs to fix to existing code bases. 45 | 46 | Some of them are just really hard problems that even other languages with a 47 | focus on soundness have gotten wrong or partially wrong before (variance especially) 48 | 49 | There are tradeoffs that have to be considered when making decisions at the 50 | language level, and right now, the balance on some of these issues has been 51 | to keep certain kinds of unsoundness in favor of stability of existing systems. 52 | 53 | I hope this becomes a useful tool that people can rely on, and I think it also 54 | can help assist CPython upstream in having another lens to view some of the 55 | problems in that isn't just academic, but implemented and ready to use. 56 | 57 | 58 | ## Primary Goals 59 | 60 | - Typed code is checked for type safety. 61 | - Typed code may be called from untyped code. 62 | - Typed code may call untyped code, with some caveats. 63 | - Replace python's type system with an external one. 64 | - Provide a few additional implemented base types 65 | - For it to be easy to write the correct type. 66 | - Provide additional syntax supporting the ideas that enable people to write type safe code with less effort. 67 | - Distinguish between library and application code such that patterns that are safe if not further extended are 68 | allowed in code not intended to be further extended. 69 | 70 | ## Long term goals 71 | 72 | - Providing type information should allow emitting optimized compiled modules. 73 | - Pure Lumi code should be possible to emit a binary which does not require the python runtime. 74 | 75 | ## Non-goals 76 | 77 | - Making all valid python code possible to type. 78 | - Upstream this (At least at this point in time.) 79 | -------------------------------------------------------------------------------- /code_generation.md: -------------------------------------------------------------------------------- 1 | 2 | ## Guiding principles of code generation 3 | 4 | 1. If it can be safely statically eliminated, do so. 5 | 2. Generated python code should remain understandable to those who known python 6 | 3. Generated code should behave in an obvious manner. 7 | Said obviousness is allowed to rely on the reader needing to know what Lumi's purpose is. 8 | 4. Methods of code generation should be easy to understand. 9 | 10 | 11 | 12 | Example: 13 | 14 | ``` 15 | type Bitfield = uint64 16 | type TrustRole = Literal["admin", "moderator", "member"] 17 | 18 | lumi record User: 19 | fields: 20 | id: uint64 21 | permissions: Bitfield 22 | role: TrustRole | None 23 | equality: {id, permissions, role} 24 | hashable: True 25 | ordering: False 26 | frozen: True 27 | repr: {id} 28 | 29 | 30 | def filter_users_by_permissions(users: list[User] => [], permissions: Bitfield = Bitfield(0)) -> Iterator[User]: 31 | for user in users: 32 | if permissions & user.permissions = permissions: 33 | yield user 34 | ``` 35 | 36 | Should generate python that looks like: 37 | 38 | ```py 39 | from typing import Generator, Any, Never 40 | 41 | from lumi.types import uint64, MISSING 42 | from lumi.exceptions import FrozenRecordError 43 | 44 | type Bitfield = uint64 45 | type TrustRole = Literal["admin", "moderator", "member"] 46 | 47 | 48 | class User: 49 | __slots__ = ("id", "permissions", "role") 50 | id: uint64 51 | permissions: Bitfield 52 | role: TrustRole | None 53 | 54 | def __init__(self, id_: uint64, permissions: Bitfield, role: TrustRole | None): 55 | object.__setattr__(self, "id", id_) 56 | object.__setattr__(self, "permissions", permissions) 57 | object.__setattr__(self, "role", role) 58 | 59 | def __setattr__(self, name: str, value: Any) -> Never: 60 | raise FrozenRecordError(f"Cannot assign to field {name}") 61 | 62 | def __delattr__(self, name: str) -> Never: 63 | raise FrozenRecordError(f"Cannot delete field {name}") 64 | 65 | def __repr__(self) -> str: 66 | return f"" 67 | 68 | def __eq__(self, other: object) -> bool: 69 | if not isinstance(other, User): 70 | return NotImplemented 71 | return (self.id, self.permissions, self.role) == (other.id, other.permissions, other.role) 72 | 73 | def __hash__(self) -> int: 74 | type_hash = hash(f"Lumi Generated {type(self).__module__} {type(self).__qualname__}") 75 | return hash((type_hash, self.id, self.permissions, self.role)) 76 | 77 | 78 | def filter_users_by_permissions( 79 | users: list[User] = MISSING, permissions: Bitfield = Bitfield(0) 80 | ) -> Generator[User, None, None]: 81 | if users is MISSING: 82 | users = [] 83 | for user in users: 84 | if permissions & user.permissions = permissions: 85 | yield user 86 | ``` 87 | 88 | 89 | A few things to note about this example 90 | 91 | 1. Currently, this is a handwritten example. Once code generation is going, the example should be replaced with a real generation. 92 | 2. The code generation should continue to function in an obvious manner as if it were handwritten 93 | 3. Lumi replaces `Iterator[yield_type]` with `Generator[yield_type, None, None]` when implementing generator functions. This produces better results for python's specified typesystem, but this is due to a few unfortunate issues in python's typeshed and how Iterator and Generator are specified. 94 | 4. One of the principles should have changed the late bind to list to just return there. While that's intended, I anticipate the 95 | initial generation method to not be that advanced, this also allows the example to show how this feature would function. 96 | 5. lumi record type generation are still being worked on for what they will support and how. At a later date, they may end up implemented natively -------------------------------------------------------------------------------- /inference.md: -------------------------------------------------------------------------------- 1 | ## Inference in Lumi 2 | 3 | ### Basic principles 4 | 5 | 1. The default type for an unannotated type is not `Any` but `auto` 6 | 2. Operator based inference errs towards a specific mathematical perspective which is more restrictive. 7 | 3. Lumi will prompt for more type information in some cases if `auto` cannot produce a reasonable type. 8 | 9 | 10 | ### Operator resolution 11 | 12 | Given the following: 13 | 14 | ``` 15 | def add(a, b) -> int: 16 | return a + b 17 | ``` 18 | 19 | 20 | Lumi will allow use of add such that a + b -> int is valid 21 | 22 | Without types specified on either the LHS or RHS, some operators are 23 | restricted based on mathematical assumptions. 24 | 25 | This may prevent some types from being accepted, for instance 26 | 27 | ``` 28 | def add(a + b): 29 | print(a + b) 30 | ``` 31 | 32 | is allowed any commutative addition between a and b. 33 | The default behavior for operators and inferenence 34 | when both LHS and RHS is to consider if the operator 35 | would typically be commutative for numeric use. 36 | (TODO: table) 37 | 38 | example {`+`, `*`} are assumed commutative when LHS and RHS are absent, 39 | but {`-`, `/`} are assumed not 40 | 41 | In general, at least one of LHS, RHS, or the resulting type needs to be 42 | determinable if the result of the operator use would impact the return type 43 | of a function. 44 | 45 | ### TypeVariable use and constraint solving 46 | 47 | TypeVariables do not necessarily need to correspond to another TypeVariable use 48 | 49 | TypeVariables generally can have 4 ways of appearing: 50 | 51 | - 1 to 1 ie: 52 | 53 | `def foo(x: T) -> T: ...` 54 | 55 | - many to 1 56 | 57 | `def foo(x: T, y: T) -> T: ...` 58 | 59 | - 1 to many 60 | 61 | `class Foo[T]: ... # multiple uses of T in body` 62 | 63 | or 64 | 65 | `def foo[T](x: T, y: T): ...` 66 | 67 | (or 1 to many to 1): 68 | 69 | `def foo[T](x: T, y: T) -> T: ...` 70 | 71 | - free standing, no clear relation 72 | 73 | `def foo (x: T, y: T) -> None: ...` or even just `def foo(x: T) -> None: ...` 74 | 75 | In the 1:1 case, the input type is clearly the output type 76 | In the many to 1 case, the direction of code flow is many inputs, 1 output, so the types are collected into a union. 77 | In the one to many (and by extension, the one to many to one) case the initial subscripted type is used. 78 | In the freestanding case, lumi does not assume a direct association between these types, but does still require that there be a type that satisfies the presented constraints. 79 | 80 | This becomes clearer when looking at the following python example: 81 | 82 | ```py 83 | T = TypeVar("T") 84 | 85 | def foo(x: T, y: T) -> T: 86 | ... 87 | 88 | #vs 89 | IntStr = TypeVar("IntStr", int, str) 90 | 91 | def bar(x: IntStr, y: IntStr): 92 | ... 93 | 94 | reveal_type(foo(1, "two")) # Should be int | str or object, depending on inference model 95 | reveal_type(bar(1, "two")) # should be rejected at call, there is no type which satisfies these constraints 96 | ``` 97 | 98 | Of current (2024-06-27) "mainstream, specification participating typecheckers", 99 | 100 | - mypy and pytype each fail at some part of this this. 101 | - pyright fails at other examples in the thread this recently arose in (see link below) 102 | - Pyre gets this correct. 103 | 104 | 105 | The "Correct" behavior is currently not specified within Cpython. 106 | 107 | 108 | > Constraint solving can be very costly, so implementations take certain shortcuts and make certain assumptions. These can fail to find certain solutions. I suspect that’s what’s happening in this case for mypy. 109 | > Constraint solving behaviors are not discussed in the typing spec currently, and I think it will be a long time (if ever) before they are. Spec’ing this behavior would be very difficult as it involves many heuristics, edge cases, behaviors that differ between type checkers, and limitations dictated by internal implementation choices. It also relies on other concepts (like value-constrained TypeVars) that are not yet well spec’ed. If you want to pursue standardization in this space, it will take significant time and effort. 110 | 111 | 112 | See discussion of the topic [here](https://discuss.python.org/t/constraining-generic-argument-types/56809) 113 | 114 | 115 | Lumi has a specified behavior (TODO: definitions this specification depends on need to be mroe rigorous) 116 | 117 | 118 | Constraints should be solved by analyzing the directional flow of code to determine if there is a set-theoretic type which satisfies the constraints. If so, that's the type, otherwise the code is invalid. 119 | -------------------------------------------------------------------------------- /differences_from_python.md: -------------------------------------------------------------------------------- 1 | ## major TODOs 2 | 3 | There's a lot here that if you find alarming may just be that not everything here important is laid out yet. 4 | feel free to open a discussion asking about it if so. 5 | 6 | ### isinstance 7 | 8 | lumi replaces isinstance with a type-safe implementation that tracks certain things. 9 | 10 | ### composition vs inheritence 11 | 12 | - Lumi encourages composition over inheritence and functional patterns where applicable. 13 | - Lumi will by default disallow unsafe override of behavior. 14 | - Lumi will allow a directive that says "I want the behavior of this, but am okay with losing it as a supertype" This must be explicitly stated. This results in Lumi generating a new type. 15 | 16 | ### Hashability 17 | 18 | - Lumi knows that object implements hash, and that users are allowed to remove hashability in python. 19 | - Lumi knows that hash needs to be explicitly defined when eq is defined to retain hashability 20 | - Lumi requires *explicitly* setting hash to None or defining it when defining equality. 21 | - Lumi treats removal of hashability as an LSP violation, except if removed in the initial class definition. 22 | - The addition of hashability is not an LSP violation, an absent hash method is still considered to be Optional 23 | 24 | ### Use of super 25 | 26 | - (Undecided, requires exploration) Lumi will wither reject all uses or reject unsafe uses of super 27 | 28 | ### Gradual typing 29 | 30 | - While Lumi allows *accepting* a a gradual type, a function defined in Lumi may not return a gradual type. 31 | - Lumi has directives for allowing safe, checked use to be generated when partially applying functions recieved from python 32 | 33 | ### Never 34 | 35 | - Lumi has multiple concepts of Never. While Never should always indicate a lack of a return, Lumi differentiates between reasons for that. This allows Lumi to determine when functions are suitable replacements in subclasses. 36 | 37 | Never is not generic over specific exceptions. 38 | 39 | Generated Python code will re-reduce all special kinds of Never to just `Never`, as this is not a concept python's type system supports. 40 | 41 | The pathological case this prevents is below, see the section on Never in the theory overview for more details. 42 | 43 | ```py 44 | class A: 45 | def foo(self) -> Literal[1]: 46 | return 1 47 | 48 | class B: 49 | def foo(self) -> Literal["this"]: 50 | return "this" 51 | 52 | 53 | class C(A, B): 54 | def foo(self) -> Never: 55 | raise RuntimeError() 56 | ``` 57 | 58 | A strict interpretation of subtyping without accounting for the concept that 59 | subtypes should remain compatible from the perspective of intent to use the method would allow 60 | C to have a foo that isn't a suitable replacement for either A or B, let alone both. 61 | 62 | 63 | ### Structural types 64 | 65 | - Lumi does not allow structural types as return types 66 | - Lumi does allow type variables bound to structural types as return types 67 | - Structural types do not have their own variance. 68 | Variance is checked as if the static type qualifying 69 | as having that structure would have appropriate variance. 70 | 71 | ### ABCs, and other means of lying about subtyping 72 | 73 | - Lumi does not support python ABCs or the ABC.register method from Lumi code. 74 | Lumi *will* emit use of some collections.abc.register methods to allow interoperability 75 | with existing python code. 76 | - Lumi does not allow implementing `__instancecheck__` or `__subclasscheck__` 77 | 78 | ### ParamSpec + Callable (may need some workshopping of specifics) 79 | 80 | - `ParamSpec.copy_params` 81 | - `ParamSpec.copy_return` 82 | - `Callable.from_callable` 83 | 84 | Useful for generating good expectations of python types Lumi may recieve 85 | ```py 86 | type TypeConstructor[T] = Callable.from_callable[T] 87 | ``` 88 | forces treating a type T as a callable type constructor with specific expectations 89 | of input parameters. 90 | 91 | ### builtins 92 | 93 | - Some python builtins will be replaced by default in Lumi. 94 | You may access the original python builtin via the Python.builtins namespace, 95 | but these recieve additional scrutiny around narrowing behaviors. 96 | 97 | ### typing features 98 | 99 | - Unsafe coercions are not supported by Lumi 100 | - Lumi's behavior for `async def` de-sugaring may differer from cpython. 101 | This depends on which resolution in a currently ongoing disucssion cpython goes with. 102 | - A few additional tools will exist in lumi to support describing certain kinds of APIs that already exist, 103 | but cover cases where it may not strictly desirable to support continued development of new code like it. 104 | 105 | Examples: `VarArgsReturnList` (planned) 106 | 107 | - This is only allowed in Lumi in cases that do not retain a reference to the returned list 108 | - CPython code described with this must not mutate the list once it is returned. 109 | - You are allowed to access each element of it or destructure it on an individual basis, or treat it as a normal list, but not both. 110 | - If Lumi sees this passed to a non-Lumi function or sees you mutate it, it is not allowed to be treated more similarly to a tuple with known individual elements. 111 | - Lumi's error messages will reflect where this occured. 112 | - Lumi allows describing Lumi code with `VarArgsReturnList` only when what goes in is what goes out. 113 | 114 | This is a common occurance in various Cpython apis and libraries. The best example of this is `asyncio.gather` 115 | 116 | 117 | ## Copied from discord, needs formatting and explanations (TODO) 118 | 119 | builtins to keep: 120 | ``` 121 | abs() 122 | all() 123 | any() 124 | bin() 125 | bool() 126 | chr() 127 | divmod() 128 | enumerate() 129 | filter() 130 | format() 131 | hex() 132 | len() 133 | map() 134 | max() 135 | min() 136 | oct() 137 | ord() 138 | pow() 139 | reversed() 140 | round() 141 | sum() 142 | zip() 143 | aiter() 144 | anext() 145 | ascii() 146 | classmethod() 147 | dir() 148 | globals() 149 | hash() 150 | id() 151 | input() 152 | iter() 153 | locals() 154 | next() 155 | print() 156 | property() 157 | range() 158 | repr() 159 | slice() 160 | sorted() 161 | staticmethod() 162 | str() 163 | vars() 164 | 165 | Unchanged (for now) Data types 166 | -------------------- 167 | bytearray() 168 | bytes() 169 | callable() 170 | dict() 171 | frozenset() 172 | list() 173 | memoryview() 174 | object() 175 | set() 176 | tuple() 177 | complex() 178 | ``` 179 | Modified builtins 180 | ``` 181 | 182 | int() -> int subclass 183 | float() -> numpy.float64 (for now, temp hack), float literals replaced with numpy.float64("literal") 184 | isinstance() 185 | issubclass() 186 | type() (single parameter only when used as a function) 187 | open() (mode parameter changes, not yet implemented) 188 | ``` 189 | 190 | Removed Builtins: 191 | ``` 192 | compile() 193 | delattr() 194 | getattr() 195 | setattr() 196 | eval() 197 | exec() 198 | help() 199 | ``` 200 | 201 | Temp(?) removed builtins 202 | ``` 203 | breakpoint() 204 | super() 205 | __import__() 206 | hasattr() 207 | ``` -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Mozilla Public License Version 2.0 2 | ================================== 3 | 4 | 1. Definitions 5 | -------------- 6 | 7 | 1.1. "Contributor" 8 | means each individual or legal entity that creates, contributes to 9 | the creation of, or owns Covered Software. 10 | 11 | 1.2. "Contributor Version" 12 | means the combination of the Contributions of others (if any) used 13 | by a Contributor and that particular Contributor's Contribution. 14 | 15 | 1.3. "Contribution" 16 | means Covered Software of a particular Contributor. 17 | 18 | 1.4. "Covered Software" 19 | means Source Code Form to which the initial Contributor has attached 20 | the notice in Exhibit A, the Executable Form of such Source Code 21 | Form, and Modifications of such Source Code Form, in each case 22 | including portions thereof. 23 | 24 | 1.5. "Incompatible With Secondary Licenses" 25 | means 26 | 27 | (a) that the initial Contributor has attached the notice described 28 | in Exhibit B to the Covered Software; or 29 | 30 | (b) that the Covered Software was made available under the terms of 31 | version 1.1 or earlier of the License, but not also under the 32 | terms of a Secondary License. 33 | 34 | 1.6. "Executable Form" 35 | means any form of the work other than Source Code Form. 36 | 37 | 1.7. "Larger Work" 38 | means a work that combines Covered Software with other material, in 39 | a separate file or files, that is not Covered Software. 40 | 41 | 1.8. "License" 42 | means this document. 43 | 44 | 1.9. "Licensable" 45 | means having the right to grant, to the maximum extent possible, 46 | whether at the time of the initial grant or subsequently, any and 47 | all of the rights conveyed by this License. 48 | 49 | 1.10. "Modifications" 50 | means any of the following: 51 | 52 | (a) any file in Source Code Form that results from an addition to, 53 | deletion from, or modification of the contents of Covered 54 | Software; or 55 | 56 | (b) any new file in Source Code Form that contains any Covered 57 | Software. 58 | 59 | 1.11. "Patent Claims" of a Contributor 60 | means any patent claim(s), including without limitation, method, 61 | process, and apparatus claims, in any patent Licensable by such 62 | Contributor that would be infringed, but for the grant of the 63 | License, by the making, using, selling, offering for sale, having 64 | made, import, or transfer of either its Contributions or its 65 | Contributor Version. 66 | 67 | 1.12. "Secondary License" 68 | means either the GNU General Public License, Version 2.0, the GNU 69 | Lesser General Public License, Version 2.1, the GNU Affero General 70 | Public License, Version 3.0, or any later versions of those 71 | licenses. 72 | 73 | 1.13. "Source Code Form" 74 | means the form of the work preferred for making modifications. 75 | 76 | 1.14. "You" (or "Your") 77 | means an individual or a legal entity exercising rights under this 78 | License. For legal entities, "You" includes any entity that 79 | controls, is controlled by, or is under common control with You. For 80 | purposes of this definition, "control" means (a) the power, direct 81 | or indirect, to cause the direction or management of such entity, 82 | whether by contract or otherwise, or (b) ownership of more than 83 | fifty percent (50%) of the outstanding shares or beneficial 84 | ownership of such entity. 85 | 86 | 2. License Grants and Conditions 87 | -------------------------------- 88 | 89 | 2.1. Grants 90 | 91 | Each Contributor hereby grants You a world-wide, royalty-free, 92 | non-exclusive license: 93 | 94 | (a) under intellectual property rights (other than patent or trademark) 95 | Licensable by such Contributor to use, reproduce, make available, 96 | modify, display, perform, distribute, and otherwise exploit its 97 | Contributions, either on an unmodified basis, with Modifications, or 98 | as part of a Larger Work; and 99 | 100 | (b) under Patent Claims of such Contributor to make, use, sell, offer 101 | for sale, have made, import, and otherwise transfer either its 102 | Contributions or its Contributor Version. 103 | 104 | 2.2. Effective Date 105 | 106 | The licenses granted in Section 2.1 with respect to any Contribution 107 | become effective for each Contribution on the date the Contributor first 108 | distributes such Contribution. 109 | 110 | 2.3. Limitations on Grant Scope 111 | 112 | The licenses granted in this Section 2 are the only rights granted under 113 | this License. No additional rights or licenses will be implied from the 114 | distribution or licensing of Covered Software under this License. 115 | Notwithstanding Section 2.1(b) above, no patent license is granted by a 116 | Contributor: 117 | 118 | (a) for any code that a Contributor has removed from Covered Software; 119 | or 120 | 121 | (b) for infringements caused by: (i) Your and any other third party's 122 | modifications of Covered Software, or (ii) the combination of its 123 | Contributions with other software (except as part of its Contributor 124 | Version); or 125 | 126 | (c) under Patent Claims infringed by Covered Software in the absence of 127 | its Contributions. 128 | 129 | This License does not grant any rights in the trademarks, service marks, 130 | or logos of any Contributor (except as may be necessary to comply with 131 | the notice requirements in Section 3.4). 132 | 133 | 2.4. Subsequent Licenses 134 | 135 | No Contributor makes additional grants as a result of Your choice to 136 | distribute the Covered Software under a subsequent version of this 137 | License (see Section 10.2) or under the terms of a Secondary License (if 138 | permitted under the terms of Section 3.3). 139 | 140 | 2.5. Representation 141 | 142 | Each Contributor represents that the Contributor believes its 143 | Contributions are its original creation(s) or it has sufficient rights 144 | to grant the rights to its Contributions conveyed by this License. 145 | 146 | 2.6. Fair Use 147 | 148 | This License is not intended to limit any rights You have under 149 | applicable copyright doctrines of fair use, fair dealing, or other 150 | equivalents. 151 | 152 | 2.7. Conditions 153 | 154 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted 155 | in Section 2.1. 156 | 157 | 3. Responsibilities 158 | ------------------- 159 | 160 | 3.1. Distribution of Source Form 161 | 162 | All distribution of Covered Software in Source Code Form, including any 163 | Modifications that You create or to which You contribute, must be under 164 | the terms of this License. You must inform recipients that the Source 165 | Code Form of the Covered Software is governed by the terms of this 166 | License, and how they can obtain a copy of this License. You may not 167 | attempt to alter or restrict the recipients' rights in the Source Code 168 | Form. 169 | 170 | 3.2. Distribution of Executable Form 171 | 172 | If You distribute Covered Software in Executable Form then: 173 | 174 | (a) such Covered Software must also be made available in Source Code 175 | Form, as described in Section 3.1, and You must inform recipients of 176 | the Executable Form how they can obtain a copy of such Source Code 177 | Form by reasonable means in a timely manner, at a charge no more 178 | than the cost of distribution to the recipient; and 179 | 180 | (b) You may distribute such Executable Form under the terms of this 181 | License, or sublicense it under different terms, provided that the 182 | license for the Executable Form does not attempt to limit or alter 183 | the recipients' rights in the Source Code Form under this License. 184 | 185 | 3.3. Distribution of a Larger Work 186 | 187 | You may create and distribute a Larger Work under terms of Your choice, 188 | provided that You also comply with the requirements of this License for 189 | the Covered Software. If the Larger Work is a combination of Covered 190 | Software with a work governed by one or more Secondary Licenses, and the 191 | Covered Software is not Incompatible With Secondary Licenses, this 192 | License permits You to additionally distribute such Covered Software 193 | under the terms of such Secondary License(s), so that the recipient of 194 | the Larger Work may, at their option, further distribute the Covered 195 | Software under the terms of either this License or such Secondary 196 | License(s). 197 | 198 | 3.4. Notices 199 | 200 | You may not remove or alter the substance of any license notices 201 | (including copyright notices, patent notices, disclaimers of warranty, 202 | or limitations of liability) contained within the Source Code Form of 203 | the Covered Software, except that You may alter any license notices to 204 | the extent required to remedy known factual inaccuracies. 205 | 206 | 3.5. Application of Additional Terms 207 | 208 | You may choose to offer, and to charge a fee for, warranty, support, 209 | indemnity or liability obligations to one or more recipients of Covered 210 | Software. However, You may do so only on Your own behalf, and not on 211 | behalf of any Contributor. You must make it absolutely clear that any 212 | such warranty, support, indemnity, or liability obligation is offered by 213 | You alone, and You hereby agree to indemnify every Contributor for any 214 | liability incurred by such Contributor as a result of warranty, support, 215 | indemnity or liability terms You offer. You may include additional 216 | disclaimers of warranty and limitations of liability specific to any 217 | jurisdiction. 218 | 219 | 4. Inability to Comply Due to Statute or Regulation 220 | --------------------------------------------------- 221 | 222 | If it is impossible for You to comply with any of the terms of this 223 | License with respect to some or all of the Covered Software due to 224 | statute, judicial order, or regulation then You must: (a) comply with 225 | the terms of this License to the maximum extent possible; and (b) 226 | describe the limitations and the code they affect. Such description must 227 | be placed in a text file included with all distributions of the Covered 228 | Software under this License. Except to the extent prohibited by statute 229 | or regulation, such description must be sufficiently detailed for a 230 | recipient of ordinary skill to be able to understand it. 231 | 232 | 5. Termination 233 | -------------- 234 | 235 | 5.1. The rights granted under this License will terminate automatically 236 | if You fail to comply with any of its terms. However, if You become 237 | compliant, then the rights granted under this License from a particular 238 | Contributor are reinstated (a) provisionally, unless and until such 239 | Contributor explicitly and finally terminates Your grants, and (b) on an 240 | ongoing basis, if such Contributor fails to notify You of the 241 | non-compliance by some reasonable means prior to 60 days after You have 242 | come back into compliance. Moreover, Your grants from a particular 243 | Contributor are reinstated on an ongoing basis if such Contributor 244 | notifies You of the non-compliance by some reasonable means, this is the 245 | first time You have received notice of non-compliance with this License 246 | from such Contributor, and You become compliant prior to 30 days after 247 | Your receipt of the notice. 248 | 249 | 5.2. If You initiate litigation against any entity by asserting a patent 250 | infringement claim (excluding declaratory judgment actions, 251 | counter-claims, and cross-claims) alleging that a Contributor Version 252 | directly or indirectly infringes any patent, then the rights granted to 253 | You by any and all Contributors for the Covered Software under Section 254 | 2.1 of this License shall terminate. 255 | 256 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all 257 | end user license agreements (excluding distributors and resellers) which 258 | have been validly granted by You or Your distributors under this License 259 | prior to termination shall survive termination. 260 | 261 | ************************************************************************ 262 | * * 263 | * 6. Disclaimer of Warranty * 264 | * ------------------------- * 265 | * * 266 | * Covered Software is provided under this License on an "as is" * 267 | * basis, without warranty of any kind, either expressed, implied, or * 268 | * statutory, including, without limitation, warranties that the * 269 | * Covered Software is free of defects, merchantable, fit for a * 270 | * particular purpose or non-infringing. The entire risk as to the * 271 | * quality and performance of the Covered Software is with You. * 272 | * Should any Covered Software prove defective in any respect, You * 273 | * (not any Contributor) assume the cost of any necessary servicing, * 274 | * repair, or correction. This disclaimer of warranty constitutes an * 275 | * essential part of this License. No use of any Covered Software is * 276 | * authorized under this License except under this disclaimer. * 277 | * * 278 | ************************************************************************ 279 | 280 | ************************************************************************ 281 | * * 282 | * 7. Limitation of Liability * 283 | * -------------------------- * 284 | * * 285 | * Under no circumstances and under no legal theory, whether tort * 286 | * (including negligence), contract, or otherwise, shall any * 287 | * Contributor, or anyone who distributes Covered Software as * 288 | * permitted above, be liable to You for any direct, indirect, * 289 | * special, incidental, or consequential damages of any character * 290 | * including, without limitation, damages for lost profits, loss of * 291 | * goodwill, work stoppage, computer failure or malfunction, or any * 292 | * and all other commercial damages or losses, even if such party * 293 | * shall have been informed of the possibility of such damages. This * 294 | * limitation of liability shall not apply to liability for death or * 295 | * personal injury resulting from such party's negligence to the * 296 | * extent applicable law prohibits such limitation. Some * 297 | * jurisdictions do not allow the exclusion or limitation of * 298 | * incidental or consequential damages, so this exclusion and * 299 | * limitation may not apply to You. * 300 | * * 301 | ************************************************************************ 302 | 303 | 8. Litigation 304 | ------------- 305 | 306 | Any litigation relating to this License may be brought only in the 307 | courts of a jurisdiction where the defendant maintains its principal 308 | place of business and such litigation shall be governed by laws of that 309 | jurisdiction, without reference to its conflict-of-law provisions. 310 | Nothing in this Section shall prevent a party's ability to bring 311 | cross-claims or counter-claims. 312 | 313 | 9. Miscellaneous 314 | ---------------- 315 | 316 | This License represents the complete agreement concerning the subject 317 | matter hereof. If any provision of this License is held to be 318 | unenforceable, such provision shall be reformed only to the extent 319 | necessary to make it enforceable. Any law or regulation which provides 320 | that the language of a contract shall be construed against the drafter 321 | shall not be used to construe this License against a Contributor. 322 | 323 | 10. Versions of the License 324 | --------------------------- 325 | 326 | 10.1. New Versions 327 | 328 | Mozilla Foundation is the license steward. Except as provided in Section 329 | 10.3, no one other than the license steward has the right to modify or 330 | publish new versions of this License. Each version will be given a 331 | distinguishing version number. 332 | 333 | 10.2. Effect of New Versions 334 | 335 | You may distribute the Covered Software under the terms of the version 336 | of the License under which You originally received the Covered Software, 337 | or under the terms of any subsequent version published by the license 338 | steward. 339 | 340 | 10.3. Modified Versions 341 | 342 | If you create software not governed by this License, and you want to 343 | create a new license for such software, you may create and use a 344 | modified version of this License if you rename the license and remove 345 | any references to the name of the license steward (except to note that 346 | such modified license differs from this License). 347 | 348 | 10.4. Distributing Source Code Form that is Incompatible With Secondary 349 | Licenses 350 | 351 | If You choose to distribute Source Code Form that is Incompatible With 352 | Secondary Licenses under the terms of this version of the License, the 353 | notice described in Exhibit B of this License must be attached. 354 | 355 | Exhibit A - Source Code Form License Notice 356 | ------------------------------------------- 357 | 358 | This Source Code Form is subject to the terms of the Mozilla Public 359 | License, v. 2.0. If a copy of the MPL was not distributed with this 360 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 361 | 362 | If it is not possible or desirable to put the notice in a particular 363 | file, then You may include the notice in a location (such as a LICENSE 364 | file in a relevant directory) where a recipient would be likely to look 365 | for such a notice. 366 | 367 | You may add additional accurate notices of copyright ownership. 368 | 369 | Exhibit B - "Incompatible With Secondary Licenses" Notice 370 | --------------------------------------------------------- 371 | 372 | This Source Code Form is "Incompatible With Secondary Licenses", as 373 | defined by the Mozilla Public License, v. 2.0. 374 | --------------------------------------------------------------------------------