You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Code should adhere to [PEP 8](https://peps.python.org/pep-0008/#fn-hi), unless otherwise noted.
349
+
348
350
#### Python Standard
349
351
1. The code developed for TensorRT-LLM should conform to Python 3.8+.
350
352
351
-
#### Indentation
352
-
1. Indent code with 4 spaces. Do not use tabs.
353
-
354
-
#### Imports
355
-
1. Always maintain the namespace when importing, even if only one class or function from a module is used.
356
-
357
-
For example instead of:
353
+
#### Formatting
358
354
359
-
```python
360
-
from package.subpackage.foo import SomeClass
361
-
SomeClass()
362
-
```
363
-
or
364
-
```python
365
-
import package
366
-
package.subpackage.foo.SomeClass()
367
-
```
355
+
1. Indent code with 4 spaces. Do not use tabs.
356
+
2. Code formatting is largely handled by the automatic tooling. Do not override it unless it substantially improves readability.
357
+
3. Note we have "legacy" files and "new" files that are formatted by different toolchains, see <pyproject.toml>. This results in somewhat different formatting between the two classes of files. Most notably legacy files are 80 characters wide while new files are 100.
368
358
369
-
Do:
370
359
371
-
```python
372
-
from package.subpackage importfoo
373
-
foo.SomeClass()
374
-
```
360
+
#### Imports
361
+
1. The linter will have opinions on import ordering. Please follow them.
362
+
2. Do not use wildcard imports.
363
+
3. Despite the prohibition on wildcard imports, keep `__all__` updated to keep the public interface clearly documented.
375
364
376
365
#### Naming
377
366
@@ -385,26 +374,29 @@ foo.SomeClass()
385
374
3. Functions and Methods
386
375
- snake_case: `def my_awesome_function():`
387
376
388
-
4. Local Variables
377
+
4. Local Variables or Mutable Global Variables
389
378
- snake_case: `my_variable = ...`
390
-
- prefix `k` for variable names that start with a number: `k_99th_percentile = ...`
379
+
- Single-letter variables may also be uppercase, e.g. `N`, `T`.
380
+
- Variables should not start with a number, but if you must, prefix with `k`, e.g. `k_99th_percentile = ...`
391
381
392
-
5.Global Variables
393
-
-upper snake_case and prefix `G`: `G_MY_GLOBAL = ...`
382
+
5.Constants (any scope)
383
+
-UPPER\_SNAKE\_CASE: `MY_CONSTANT = ...`
394
384
395
-
6. Constants
396
-
- upper snake_case: `MY_CONSTANT = ...`
385
+
Variables and functions not part of a class’s or module’s public interface should be prefixed with an underscore. Double underscores are permitted only if necessary to avoid name conflicts with inherited classes, and even then you should pursue alternatives.
397
386
398
387
##### Identifier Guidelines
399
388
1. Avoid shadowing variables declared in an outer scope.
400
-
2. Initialize all externally visible memberes of a class in the constructor.
389
+
2. Initialize all externally visible members of a class in the constructor.
390
+
3. For variables referencing “container” type objects that could live explicitly on the host or a GPU, e.g. referencing a Tensor, consider appending `_host` or `_device`/`_cuda` suffixes if the location is ambiguous. Particularly if copies of the data exist in both locations.
401
391
402
392
#### Comments
403
393
404
394
1. For interfaces that may be used outside a file, prefer docstrings over comments.
405
395
2. Comments should be reserved for code within a function, or interfaces that are local to a file.
396
+
3. Avoid overcommenting. Reserve comments for things that need explaining, or breaking up long sections of code into functional parts. But in that case, consider helper functions.
397
+
4. For arguments to functions in the public interface to a file, documentation of Tensor-like arguments should include the expected dimensions, e.g. `[batch, seq_len, hdim]`, and the allowed dtype options if dtype is constrained.
406
398
407
-
### Pydantic Guidelines
399
+
####Pydantic Guidelines
408
400
409
401
When defining any user-facing configuration classes (particularly `LlmArgs` or any class used in its fields), **always** use Pydantic classes rather than dataclasses or vanilla classes.
410
402
@@ -445,7 +437,7 @@ When defining any user-facing configuration classes (particularly `LlmArgs` or a
445
437
##### Classes and Functions
446
438
Use the [Google style](https://google.github.io/styleguide/pyguide.html), which can be parsed by Sphinx.
447
439
448
-
##### Attributes and Variables
440
+
##### Attributes and Variables
449
441
Attributes and variables can be documented inline. Attribute docstrings will be rendered under the docstring for the class. For example:
450
442
```python
451
443
classMyClass:
@@ -460,6 +452,9 @@ y = 2
460
452
"""<type>: Description of 'y'"""
461
453
```
462
454
455
+
However, attribute docstrings are relatively rare and not expected. Externally called functions should have docstrings, and their arguments should be documented. Class initializer arguments especially should be documented.
456
+
457
+
463
458
#### Avoid Reflection
464
459
Avoid using reflection when functionality can be easily achieved without reflection.
465
460
@@ -524,6 +519,126 @@ else:
524
519
f.read()
525
520
```
526
521
522
+
Except in exceptional circumstances, use the built-in exception types. For which type to use when, see [https://docs.python.org/3/library/exceptions.html](https://docs.python.org/3/library/exceptions.html). Use exceptions for error handling, not return values. And despite the example above, prefer isinstance() to duck typing where possible.
523
+
524
+
#### Static Typing
525
+
526
+
1. Static type checking at pre-commit time is opt-in by submodule PICs. This is highly recommended because static type checking eliminates an entire class of bugs and makes your code more readable and maintainable overall.
527
+
2. The presubmit system currently uses mypy. However, many developers use pyright variants in their editors, so the code also has some `#pyright:` annotations. As we don’t currently enforce pyright, maintaining these is best effort. But if you notice they are broken, please fix them.
528
+
3. Do not use `typing.Any` if you can avoid it. Similarly, avoid bypassing the type checker with `# type: ignore` annotations.
529
+
4. Always annotate functions. Make the return type `None` if the function does not return anything (if you leave it empty, the type checker will infer the return type as `Any`).
530
+
5. Annotate class members and other variables when necessary. Always annotate `dataclass` and `NamedTuple` members.
531
+
532
+
```py
533
+
classFoo:
534
+
def__init__(self, x: int) -> None:
535
+
self.x = x # inferred as int, no extra annotation required
536
+
self.y: Optional[int] =None# annotation required to prevent NoneType from being inferred
537
+
```
538
+
539
+
6. Prefer using the built-in types `list`, `dict`, and `tuple` to the legacy `typing.List`, `typing.Dict`, and `typing.Tuple`. Similarly, use the `|` syntax instead of `typing.Union`.
10. Use `@overload` when a return type depends on an input type. If the return type can be expressed using the input type, you can alternatively use a `TypeVar`.
580
+
581
+
```py
582
+
@overload
583
+
deffoo(a: str) -> int:
584
+
pass
585
+
586
+
@overload
587
+
deffoo(a: float) -> float:
588
+
pass
589
+
590
+
deffoo(a: str|float) -> int|float:
591
+
ifisinstance(a, str):
592
+
return42
593
+
return42.0
594
+
595
+
defbar(a: float) -> None: pass
596
+
597
+
bar(foo(1.0)) # This will type check thanks to @overload
598
+
599
+
# In this example, the return type can be expressed as
600
+
T = TypeVar("T")
601
+
defbaz(x: T) -> dict[str, T]:
602
+
return {"key": x}
603
+
```
604
+
605
+
11. Use a bounded TypeVar only when the type parameter appears in both input and return positions to preserve specific type information; if it appears only in the parameters, use the bound type directly.
606
+
607
+
```py
608
+
classFoo:
609
+
deff(self) -> None: pass
610
+
611
+
classBar(Foo): pass
612
+
613
+
# Instead of:
614
+
# T = TypeVar("T", bound=Foo)
615
+
# def func(x: T) -> None:
616
+
# x.f()
617
+
618
+
# We can just do:
619
+
deffunc(x: Foo) -> None:
620
+
x.f()
621
+
622
+
# Here, using a bound type var is actually useful. We prevent
623
+
# func2 from losing type information.
624
+
# def func2(x: Foo) -> Foo:
625
+
# return x
626
+
# x = func2(Bar()) # Return type is Foo
627
+
628
+
T = TypeVar("T", bound=Foo)
629
+
deffunc2(x: T) -> T:
630
+
return x
631
+
x = func2(Bar()) # Return type is Bar
632
+
```
633
+
634
+
12. Use typing.Protocol for duck typing. Prefer it when
635
+
* You need an interface that third-party or unrelated classes can satisfy without inheriting from a base class.
636
+
* You want to type-check that an object has specific methods/attributes without coupling to a class hierarchy.
637
+
638
+
Do not use Protocol when a shared base class or ABC already exists and implementations naturally inherit from it — use the ABC directly. Also do not use it when you only need a union of concrete types — use Union or a type alias instead.
639
+
640
+
Note that TypeVars can also be bound to `Protocol`s. Use this feature to specify the expected interface for an argument to a generic function if duck typing is desired.
0 commit comments