745 def post(self, request, format=None):
746 organization = parse_organization(request)
747 source = request.data["source"]
748 assert source in [choice[0] for choice in PAYMENT_PROVIDERS.choices] 749 connector = PAYMENT_PROVIDER_MAP[source]
750 try:
751 num = connector.import_customers(organization)
796 def post(self, request, format=None):
797 organization = parse_organization(request)
798 source = request.data["source"]
799 assert source in [choice[0] for choice in PAYMENT_PROVIDERS.choices] 800 connector = PAYMENT_PROVIDER_MAP[source]
801 try:
802 num = connector.import_payment_objects(organization)
849 def post(self, request, format=None):
850 organization = parse_organization(request)
851 source = request.data["source"]
852 assert source in [choice[0] for choice in PAYMENT_PROVIDERS.choices] 853 end_now = request.data.get("end_now", False)
854 connector = PAYMENT_PROVIDER_MAP[source]
855 try:
500 def validate(self, data):
501 data = super().validate(data)
502 rs = data.get("range_start", None)
503 assert rs is not None and rs >= Decimal(0), "range_start must be >= 0" 504 re = data.get("range_end", None)
505 if not re:
506 re = Decimal("Infinity")
504 re = data.get("range_end", None)
505 if not re:
506 re = Decimal("Infinity")
507 assert re > rs 508 if data.get("type") == PRICE_TIER_TYPE.FLAT:
509 assert data.get("cost_per_batch") is not None
510 data["metric_units_per_batch"] = None
506 re = Decimal("Infinity")
507 assert re > rs
508 if data.get("type") == PRICE_TIER_TYPE.FLAT:
509 assert data.get("cost_per_batch") is not None 510 data["metric_units_per_batch"] = None
511 data["batch_rounding_type"] = None
512 elif data.get("type") == PRICE_TIER_TYPE.FREE:
514 data["metric_units_per_batch"] = None
515 data["batch_rounding_type"] = None
516 elif data.get("type") == PRICE_TIER_TYPE.PER_UNIT:
517 assert data.get("metric_units_per_batch") 518 assert data.get("cost_per_batch") is not None
519 data["batch_rounding_type"] = data.get(
520 "batch_rounding_type", BATCH_ROUNDING_TYPE.NO_ROUNDING
515 data["batch_rounding_type"] = None
516 elif data.get("type") == PRICE_TIER_TYPE.PER_UNIT:
517 assert data.get("metric_units_per_batch")
518 assert data.get("cost_per_batch") is not None 519 data["batch_rounding_type"] = data.get(
520 "batch_rounding_type", BATCH_ROUNDING_TYPE.NO_ROUNDING
521 )
565 data = super().validate(data)
566 try:
567 tiers = data.get("tiers")
568 assert len(tiers) > 0, "Must have at least one price tier" 569 tiers_sorted = sorted(tiers, key=lambda x: x["range_start"])
570 assert tiers_sorted[0]["range_start"] == 0, "First tier must start at 0"
571 assert all(
567 tiers = data.get("tiers")
568 assert len(tiers) > 0, "Must have at least one price tier"
569 tiers_sorted = sorted(tiers, key=lambda x: x["range_start"])
570 assert tiers_sorted[0]["range_start"] == 0, "First tier must start at 0" 571 assert all(
572 x["range_end"] for x in tiers_sorted[:-1]
573 ), "All tiers must have an end, last one is the only one allowed to have open end"
568 assert len(tiers) > 0, "Must have at least one price tier"
569 tiers_sorted = sorted(tiers, key=lambda x: x["range_start"])
570 assert tiers_sorted[0]["range_start"] == 0, "First tier must start at 0"
571 assert all( 572 x["range_end"] for x in tiers_sorted[:-1] 573 ), "All tiers must have an end, last one is the only one allowed to have open end" 574 for i, tier in enumerate(tiers_sorted[:-1]):
575 assert tiers_sorted[i + 1]["range_start"] - tier[
576 "range_end"
572 x["range_end"] for x in tiers_sorted[:-1]
573 ), "All tiers must have an end, last one is the only one allowed to have open end"
574 for i, tier in enumerate(tiers_sorted[:-1]):
575 assert tiers_sorted[i + 1]["range_start"] - tier[ 576 "range_end" 577 ] <= Decimal(1), "All tiers must be contiguous" 578
579 pr_gran = data.get("proration_granularity")
580 metric_granularity = data.get("billable_metric").granularity
582 if metric_granularity == METRIC_GRANULARITY.SECOND:
583 data["proration_granularity"] = METRIC_GRANULARITY.TOTAL
584 elif pr_gran == METRIC_GRANULARITY.MINUTE:
585 assert metric_granularity not in [ 586 METRIC_GRANULARITY.SECOND, 587 ], "Metric granularity cannot be finer than proration granularity" 588 if metric_granularity == METRIC_GRANULARITY.MINUTE:
589 data["proration_granularity"] = METRIC_GRANULARITY.TOTAL
590 elif pr_gran == METRIC_GRANULARITY.HOUR:
588 if metric_granularity == METRIC_GRANULARITY.MINUTE:
589 data["proration_granularity"] = METRIC_GRANULARITY.TOTAL
590 elif pr_gran == METRIC_GRANULARITY.HOUR:
591 assert metric_granularity not in [ 592 METRIC_GRANULARITY.SECOND, 593 METRIC_GRANULARITY.MINUTE, 594 ], "Metric granularity cannot be finer than proration granularity" 595 if metric_granularity == METRIC_GRANULARITY.HOUR:
596 data["proration_granularity"] = METRIC_GRANULARITY.TOTAL
597 elif pr_gran == METRIC_GRANULARITY.DAY:
595 if metric_granularity == METRIC_GRANULARITY.HOUR:
596 data["proration_granularity"] = METRIC_GRANULARITY.TOTAL
597 elif pr_gran == METRIC_GRANULARITY.DAY:
598 assert metric_granularity not in [ 599 METRIC_GRANULARITY.SECOND, 600 METRIC_GRANULARITY.MINUTE, 601 METRIC_GRANULARITY.HOUR, 602 ], "Metric granularity cannot be finer than proration granularity" 603 if metric_granularity == METRIC_GRANULARITY.DAY:
604 data["proration_granularity"] = METRIC_GRANULARITY.TOTAL
605 elif pr_gran == METRIC_GRANULARITY.MONTH:
603 if metric_granularity == METRIC_GRANULARITY.DAY:
604 data["proration_granularity"] = METRIC_GRANULARITY.TOTAL
605 elif pr_gran == METRIC_GRANULARITY.MONTH:
606 assert metric_granularity not in [ 607 METRIC_GRANULARITY.SECOND, 608 METRIC_GRANULARITY.MINUTE, 609 METRIC_GRANULARITY.HOUR, 610 METRIC_GRANULARITY.DAY, 611 ], "Metric granularity cannot be finer than proration granularity" 612 if metric_granularity == METRIC_GRANULARITY.MONTH:
613 data["proration_granularity"] = METRIC_GRANULARITY.TOTAL
614 elif pr_gran == METRIC_GRANULARITY.QUARTER:
612 if metric_granularity == METRIC_GRANULARITY.MONTH:
613 data["proration_granularity"] = METRIC_GRANULARITY.TOTAL
614 elif pr_gran == METRIC_GRANULARITY.QUARTER:
615 assert metric_granularity not in [ 616 METRIC_GRANULARITY.SECOND, 617 METRIC_GRANULARITY.MINUTE, 618 METRIC_GRANULARITY.HOUR, 619 METRIC_GRANULARITY.DAY, 620 METRIC_GRANULARITY.MONTH, 621 ], "Metric granularity cannot be finer than proration granularity" 622 if metric_granularity == METRIC_GRANULARITY.QUARTER:
623 data["proration_granularity"] = METRIC_GRANULARITY.TOTAL
624 elif pr_gran == METRIC_GRANULARITY.YEAR:
622 if metric_granularity == METRIC_GRANULARITY.QUARTER:
623 data["proration_granularity"] = METRIC_GRANULARITY.TOTAL
624 elif pr_gran == METRIC_GRANULARITY.YEAR:
625 assert metric_granularity not in [ 626 METRIC_GRANULARITY.SECOND, 627 METRIC_GRANULARITY.MINUTE, 628 METRIC_GRANULARITY.HOUR, 629 METRIC_GRANULARITY.DAY, 630 METRIC_GRANULARITY.MONTH, 631 METRIC_GRANULARITY.QUARTER, 632 ], "Metric granularity cannot be finer than proration granularity" 633 if metric_granularity == METRIC_GRANULARITY.YEAR:
634 data["proration_granularity"] = METRIC_GRANULARITY.TOTAL
635 except AssertionError as e:
641 pc = PlanComponent.objects.create(**validated_data)
642 for tier in tiers:
643 tier = PriceTierSerializer().create(tier)
644 assert type(tier) == PriceTier 645 tier.plan_component = pc
646 tier.save()
647 return pc
692 def validate(self, data):
693 transition_to_plan_id = data.get("transition_to_plan_id")
694 transition_to_plan_version_id = data.get("transition_to_plan_version_id")
695 assert not ( 696 transition_to_plan_id and transition_to_plan_version_id 697 ), "Can't specify both transition_to_plan_id and transition_to_plan_version_id" 698 data = super().validate(data)
699 if (
700 data.get("status") == PLAN_VERSION_STATUS.ARCHIVED
872 components_data = validated_data.pop("plan_components", [])
873 if len(components_data) > 0:
874 components = PlanComponentSerializer(many=True).create(components_data)
875 assert type(components[0]) == PlanComponent 876 else:
877 components = []
878 features_data = validated_data.pop("features", [])
1063 proration_granularity = component.proration_granularity
1064 metric_granularity = component.metric.granularity
1065 if plan_version.plan_duration == PLAN_DURATION.MONTHLY:
1066 assert metric_granularity not in [1067 METRIC_GRANULARITY.YEAR,1068 METRIC_GRANULARITY.QUARTER,1069 ]1070 elif plan_version.plan_duration == PLAN_DURATION.QUARTERLY:
1071 assert metric_granularity not in [METRIC_GRANULARITY.YEAR]
1072 if initial_external_links:
1068 METRIC_GRANULARITY.QUARTER,
1069 ]
1070 elif plan_version.plan_duration == PLAN_DURATION.QUARTERLY:
1071 assert metric_granularity not in [METRIC_GRANULARITY.YEAR]1072 if initial_external_links:
1073 data["initial_external_links"] = initial_external_links
1074 return data
328 org_stripe_acct = customer.organization.payment_provider_ids.get(
329 PAYMENT_PROVIDERS.STRIPE, ""
330 )
331 assert (332 org_stripe_acct != ""333 ), "Organization does not have a Stripe account ID"334 invoice_kwargs["stripe_account"] = org_stripe_acct
335
336 for line_item in invoice.inv_line_items.all():
314 stripe_customer_id = customer.integrations.get(
315 PAYMENT_PROVIDERS.STRIPE, {}
316 ).get("id")
317 assert stripe_customer_id is not None, "Customer does not have a Stripe ID"318 invoice_kwargs = {
319 "auto_advance": True,
320 "customer": stripe_customer_id,
Usage of assert
statement in application logic is discouraged. assert
is removed with compiling to optimized byte code. Consider raising an exception instead. Ideally, assert
statement should be used only in tests.
Python has an option to compile the optimized bytecode and create the respective .pyo
files by using the options -O
and -OO
. When used, these basic optimizations are done:
- All the assert statements are removed
- All docstrings are removed (when -OO is selected)
- Value of the
__debug__
built-in variable is set toFalse
It is recommended not to use assert
in non-test files. A better way for internal self-checks is to check explicitly and raise respective error using an if statement.
Tip: Make sure test_patterns
are defined in .deepsource.toml
to avoid false-positives. Please check the documentation to know more.
Consider this code snippet:
def read_secret(self):
assert self.is_admin, "You are unauthorized to read this"
return self._secret
If python
is run with the -O
flag, the check for self.is_admin
is
completely ignored, which can cause secrets to be leaked.
This is how you can ensure the code always works:
def read_secret(self):
if not self.is_admin:
raise AssertionError("You are unauthorized to read this")
return self._secret
Here's a more detailed example. Consider the following script foo.py
:
import sys
def run():
assert len(sys.argv) == 5 # Insecure, statement will be removed when compiled to optimized byte code
print("Argument variables are: ", sys.argv)
run()
When optimization is disabled:
$ python foo.py 1 2 3 4 5
Traceback (most recent call last):
File "foo.py", line 7, in <module>
run()
File "foo.py", line 4, in run
assert len(sys.argv) == 5 # Insecure, statement will be removed when compiled to optimized byte code
AssertionError
When optimization is enabled:
$ python -O foo.pyo 1 2 3 4 5 6
Argument variables are: ['foo.pyo', '1', '2', '3', '4', '5', '6']
Here, all the internal self-checks using the assert statements are removed, as we can see. Therefore, there's a chance for an application to behave strangely in this case. It is better do raise the Exception explicitly:
import sys
def run():
if not len(sys.argv) == 5:
raise ValueError
print("Argument variables are: ", sys.argv)
run()
Note: During autofix, DeepSource will change the assert
statements to if
statements raising AssertionError
.
This is done to replicate the existing behavior.
References:
- -O flag in python
- -OO flag in python
- Discuss blogpost - Using assert outside tests