My instance variable ID is changing each time I print the instance. The if statement I've written doesn't fix it. Code included - python-3.x

I'm trying to use UUID4 to create an ID for each instance of a class, User, however each time I print the instance a new UUID is generated. I'd thought that the if statement would mean it's only generated once but this isn't the case. Any help/guidance will be much appreciated, thanks.
This is my first time posting so please let me know if i can improve the post or add more info.
class User:
def __init__(self) -> None:
self.user_id = None
self.auth_key = None
if self.user_id == None: self.user_id = uuid4()
def __repr__(self) -> str:
return f"""User ID: {self.user_id}
Authorisation Key: {self.auth_key}"""
new_user = User()
print(new_user)

I've just tried your code without problems. You probably are executing your script many times over and getting different ID's because of that. Each time you run it, new instances will be created by your current Python session and those are totally independent from each other.
from uuid import uuid4
class User:
def __init__(self) -> None:
self.user_id = uuid4()
self.auth_key = None
def __repr__(self) -> str:
return f"User ID: {self.user_id}\nAuthorization Key: {self.auth_key}"
def __eq__(self, other):
return self.user_id == other.user_id
new_user = User()
# Same instance on same session:
print(new_user)
print(new_user)
print(new_user)
# Different instance on same session:
another_user = User()
# Comparing them:
print(f"new_user: {new_user.user_id}")
print(f"another_user: {another_user.user_id}")
# Identity test:
print(f"new_user is new_user: {new_user is new_user}")
print(f"new_user is another_user: {new_user is another_user}")

Related

Error when I call a method within a python class

When I run the code below, I get a NameError that bbo is not defined.
from typing import Tuple
import requests
import os
class Level:
__slots__ = ['price', 'amount']
def __init__(self, price: float, amount: float):
self.price = price
self.amount = amount
def initialize(trading_pair: str):
pass
def bbo(trading_pair: str) -> Tuple:
endpt = "https://api.binance.com"
api = "/api/v3/depth"
response = requests.get(endpt + api + trading_pair)
bids_str, asks_str = response.json()["bids"], response.json()["asks"]
bids = [[float(x) for x in row] for row in bids_str]
asks = [[float(x) for x in row] for row in asks_str]
return (Level(max(bids)[0],max(bids)[1]), Level(min(asks)[0],min(asks)[1]))
def main(trading_pair: str):
while True:
time.sleep(5)
bb, ba = bbo(trading_pair)
print(f"Best Bid: {bb.amount}#{bb.price} Best Ask: {ba.amount}#{ba.price}")
if __name__=='__main__':
trading_pair = os.getenv("TRADING_PAIR", "BTCUSDT")
initialize(trading_pair)
main(trading_pair)
When I added self to main()
def main(self, trading_pair: str):
while True:
time.sleep(1)
bb, ba = self.bbo(trading_pair)
print(f"Best Bid: {bb.amount}#{bb.price} Best Ask: {ba.amount}#{ba.price}")
I got a TypeError saying main() missing 1 required positional argument: 'trading_pair'. How do I fix this?
There are a couple of issues that you're having, even if you've included
the self parameter in your methods.
Firstly, your __main__ call:
trading_pair = os.getenv("TRADING_PAIR", "BTCUSDT")
initialize(trading_pair)
main(trading_pair)
This isn't going to work since initialize is supposed to be a method within the Level class. So you will get an undeclared variable in initialize. But since it doesn't do anything right now, I'm only guessing you're going to use it to do some initializing. Will get to this later.
The main method bbo seems to be the (for lack of a better word) actual initializer, so I'll concentrate on that.
Here's my take on your code:
from typing import Tuple
import requests
import os
import time
class Level:
__slots__ = ['price', 'amount']
def __init__(self, price: float, amount: float):
self.price = price
self.amount = amount
def initialize(self, trading_pair: str):
pass
#staticmethod
def bbo(trading_pair: str) -> Tuple:
endpt = "https://api.binance.com"
api = "/api/v3/depth"
response = requests.get(endpt + api + trading_pair)
bids_str, asks_str = response.json()["bids"], response.json()["asks"]
bids = [[float(x) for x in row] for row in bids_str]
asks = [[float(x) for x in row] for row in asks_str]
return (Level(max(bids)[0],max(bids)[1]),
Level(min(asks)[0],min(asks)[1]))
def main(trading_pair: str):
while True:
time.sleep(5)
bb, ba = Level.bbo(trading_pair)
print(f"Best Bid: {bb.amount}#{bb.price} Best Ask: {ba.amount}#{ba.price}")
if __name__=='__main__':
trading_pair = os.getenv("TRADING_PAIR", "BTCUSDT")
main(trading_pair)
Your initialize method does nothing but if it's just a
place holder for future use, I'll just keep it at that. However,
you need to bear in mind that if you do need to use it,
you will need to place it where you've already instantiated
the Level class. Something along the lines of (but
not exactly, since I don't know what the initialize
will do):
#staticmethod
def bbo(self, trading_pair: str) -> Tuple:
endpt = "https://api.binance.com"
api = "/api/v3/depth"
response = requests.get(endpt + api + trading_pair)
bids_str, asks_str = response.json()["bids"], response.json()["asks"]
bids = [[float(x) for x in row] for row in bids_str]
asks = [[float(x) for x in row] for row in asks_str]
bid_level = Level(max(bids)[0],max(bids)[1])
ask_level = Level(min(asks)[0],min(asks)[1])
bid_level.initialize(trading_pair)
ask_level.initialize(trading_pair)
return (bid_level, ask_level)
That said, you'll also need to include error checking
just in case the response.json() ends up being invalid,
or the response being invalid. (again, just a suggestion).
I've tested the code, but I'm getting a 404 error, so I"m
not sure if the url is correct or I'm missing some
credentials.

Django Rest Framework - to_internal_value Error Inconsistency

I have a model, User, in which the primary unique field is email. I have a separate Organization model which allows users to map to organizations through a many-to-many mapping.
I want the serializer to allow users to be created if they have an existing email but no organization association (organization is taken from the user making the request so is not in the payload).
The standard ModelSerializer includes a check against the field in to_internal_value(). I am consequently trying to override it like so:
def to_internal_value(self, data):
"""
Dict of native values <- Dict of primitive datatypes.
"""
fields = self._writable_fields
for field in fields:
validate_method = getattr(self, 'validate_' + field.field_name, None)
primitive_value = field.get_value(data)
try:
if validate_method == self.validate_email:
if User.objects.filter(email=primitive_value).exists():
if not self.active_organization.members.filter(email=primitive_value).exists():
continue
else:
validated_value = field.run_validation(primitive_value)
if validate_method is not None:
validated_value = validate_method(validated_value)
except ValidationError as exc:
errors[field.field_name] = exc.detail
except DjangoValidationError as exc:
errors[field.field_name] = get_error_detail(exc)
except SkipField:
pass
else:
set_value(ret, field.source_attrs, validated_value)
return super().to_internal_value(data)
This works, but the error that is returned if the object already has a record in User and Organization does not correctly map as a dictionary. For example, the validation error shows this:
[ErrorDetail(string='User with this Email already exists.', code='unique')]
Instead of what it should show, this:
{'email': [ErrorDetail(string='User with this Email already exists.', code='unique')]}
I tested by overriding the method and trying both my custom called code vs. the original, and it replicates the above findings:
def to_internal_value(self, data):
"""
Dict of native values <- Dict of primitive datatypes.
"""
try:
print('trying custom')
for field in self._writable_fields:
if field.field_name == 'email':
print(field.run_validation)
validated_value = field.run_validation(field.get_value(data))
except Exception as e:
print('error custom')
print(str(e))
try:
print('Trying original')
value = super().to_internal_value(data)
except Exception as e:
print('Exception - original')
print(str(e))
Output:
trying custom
<bound method CharField.run_validation of EmailField(max_length=254, validators=[<UniqueValidator(queryset=User.objects.all())>])>
error custom
[ErrorDetail(string='User with this Email already exists.', code='unique')]
Trying original
Exception - original
{'email': [ErrorDetail(string='User with this Email already exists.', code='unique')]}
Can anyone help me understand why this is happening please? I'm really stuck as to how this is happening.
I was not able to figure out why exactly the errors generated by to_internal_value(self, data) change when I copy the code from the underlying ModelSerializer vs calling super(). However, I did find a kind-of hackish workaround.
Because I strip out all the other related info (nested serializers, kind of) before hand, I'm really just worried about the email. Therefore, I traverse the _writable_fields twice: the first time I look for an existing email where it isn't in the organization. If those conditions are true, I return a dictionary and proceed to the create() method. If they fail, I call super. So far this seems to work. Here is my simplified class.
def to_internal_value(self, data):
"""
Dict of native values <- Dict of primitive datatypes.
"""
try:
for field in self._writable_fields:
if field.field_name == 'email':
primitive_value = field.get_value(data)
validator = EmailValidator()
validator(primitive_value)
if User.objects.filter(email=primitive_value).exists():
if not self.active_organization.members.filter(email=primitive_value).exists():
self.email_already_exists = True
return {'email': primitive_value}
except:
pass
return super().to_internal_value(data)
For reference, this is the complete ViewSet and Serializer I'm using:
class AdminUsersSerializer(serializers.ModelSerializer):
"""User serializer for the admin user view"""
groups = GenericGroupSerializer(source='group_set', many=True, required=False)
permission_sets = GenericPermissionSetSerializer(source='permissionset_set', many=True, required=False)
active_organization = None
email_already_exists = False
class Meta:
model = User
fields = ['pk', 'email', 'groups', 'permission_sets'] # , 'permissions']
def set_active_organization(self, organization):
self.active_organization = organization
def create(self, validated_data):
if not self.email_already_exists:
user = User.objects.create(
email=validated_data['email']
)
user.set_password(None)
user.save()
else:
user = User.objects.get(email=validated_data['email'])
return user
def to_internal_value(self, data):
"""
Dict of native values <- Dict of primitive datatypes.
"""
try:
for field in self._writable_fields:
if field.field_name == 'email':
primitive_value = field.get_value(data)
validator = EmailValidator()
validator(primitive_value)
if User.objects.filter(email=primitive_value).exists():
if not self.active_organization.members.filter(email=primitive_value).exists():
self.email_already_exists = True
return {'email': primitive_value}
except:
pass
return super().to_internal_value(data)
class AdminUsersViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = AdminUsersSerializer
permission_classes = [account_permissions.IsAdminRequired]
http_method_names = ['get', 'post']
active_organization = None
def create(self, request, *args, **kwargs):
self.active_organization = self.request.user.activeorganization.organization
groups = None
permission_sets = None
serializer = self.get_serializer(data=request.data)
serializer.set_active_organization(self.active_organization)
if 'groups' in serializer.initial_data:
if serializer.initial_data.get('groups'):
groups = serializer.initial_data.pop('groups')
else:
serializer.initial_data.pop('groups')
if 'permission_sets' in serializer.initial_data:
if serializer.initial_data.get('permission_sets'):
permission_sets = serializer.initial_data.pop('permission_sets')
else:
serializer.initial_data.pop('permission_sets')
# Normal method functions
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
# Created user
user = User.objects.get(email=serializer.data['email'])
# Add user to organization
self.active_organization.members.add(user)
# Make sure to format the ajax groups data properly
if groups:
try:
group = Group.objects.get(
id=groups,
organization=self.active_organization
)
group.members.add(user)
except:
pass
if permission_sets:
try:
permission_set = PermissionSet.objects.get(
id=permission_sets,
organization=self.active_organization
)
permission_set.members.add(user)
except:
pass
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
def get_queryset(self):
return self.queryset.filter(
userorganizationmembership__organization=self.request.user.activeorganization.organization
).all()
It does feel hackish, but it seems to be getting the job done.

Unit test initializes class without calling parameters, how do I get the parameters into the class?

So I'm working with Linked Lists in python, and the UnitTest our professor gave us calls C = Course(), but asserts the values after. This is what they use to grade, but I can't find a way to call the class then wait for the variables, and apply them to the class without parameters so it doesn't crash. Thoughts? Am I missing something obvious?
Tried to only include the relevant code. If people need full code for clarification or just for kicks/giggles let me know.
import courselist
import course
def load_data(data):
with open(data) as f:
for line in f:
dline = line.strip().split(",")
C = course.Course(dline[0],dline[1],dline[2],dline[3])
course_list = courselist.CourseList()
course_list.insert(C)
return course_list
def main():
data = "data.txt"
full_list = load_data(data)
print(full_list.__str__())
main()
class Course:
def __init__(self, c_num, c_name, c_hour, c_grade):
self.c_num = c_num
self.c_name = c_name
self.c_hour = c_hour
self.c_grade = c_grade
self.next = None
class TestEmptyCourse(unittest.TestCase):
def test_course_creation(self):
# make sure that an empty course is correct
c = Course()
self.assertEqual(c.name(), "")
self.assertEqual(c.number(), 0)
self.assertEqual(c.credit_hr(), 0.0)
self.assertEqual(c.grade(), 0.0)
self.assertEqual(c.next, None)
I was missing something obvious... Hangs head in shame For those interested here's how to fix it. It's always when you ask for help that you get it just in time to look like an idiot haha. Thanks to those to checked it out. If someone has an alternate solution I'll be sure to upvote you
class Course:
def __init__(self, num=0, cname="", c_hr=0.0, cgrade=0.0, next=None):
self.num = num
self.cname = cname
self.c_hr = c_hr
self.cgrade = cgrade
self.next = None
def number(self):
return int(self.num)
def name(self):
return str(self.cname)
def credit_hr(self):
return self.c_hr
def grade(self):
return self.cgrade
def __str__(self):
return f"cs{self.num} {self.cname} Grade:{self.cgrade} Credit Hours: {self.c_hr}"

Can we skip explicit object creation in Python

When I do not crate object for CP class, the operations are not captured. I am referring to the code below, Can somebody help me understand why we need obj creation in this case
from abc import ABC, abstractmethod
class P(ABC):
def __init__(self):
super().__init__()
self._pre_map = {}
self._pre_order = []
def set_pre(self, tag_value):
index = len(self._pre_map)
print(index)
self._pre_map[index] = tag_value
self._pre_order.append(index)
def execute(self):
pass
class CP(P):
def __init__(self):
super().__init__()
def execute(self):
self.prnt()
def prnt(self):
print (self._pre_map)
print (self._pre_order)
#Working
print("\n++++++++ working")
obj = CP()
obj.set_pre("test string added")
obj.execute()
#Not Working
print("\n+++++++ not working")
CP().set_pre("test string added")
CP().execute()
It produces,
++++++++working
0
{0: 'test string added'}
[0]
+++++++not working
0
{}
[]
When you call the class the second time with CP.execute(), you have created a completely new instance of the CP class. It is not going to have the text string you specified.
If you actually wanted it to print the values like the working one you can make the functions return self after each call in the P class. If you did that you could do something like this.
from abc import ABC, abstractmethod
class P(ABC):
def __init__(self):
super().__init__()
self._pre_map = {}
self._pre_order = []
def set_pre(self, tag_value):
index = len(self._pre_map)
print(index)
self._pre_map[index] = tag_value
self._pre_order.append(index)
##need to return self here
return self
def execute(self):
pass
class CP(P):
def __init__(self):
super().__init__()
def execute(self):
self.prnt()
def prnt(self):
print (self._pre_map)
print (self._pre_order)
#Working
print("\n++++++++ working")
obj = CP()
obj.set_pre("test string added")
obj.execute()
#Not Working
print("\n+++++++ not working: but now working after returning self in the P class")
CP().set_pre("test string added").execute()
++++++++ working
0
{0: 'test string added'}
[0]
+++++++ not working: but now working after returning self in the P class
0
{0: 'test string added'}
[0]
This would print the result you want.
The reason for the difference is the fact that in the first one, you are creating an instance, and using that instance the whole way through, whereas in the second one, you are using two different instances of your class.
The two different instances cannot share their attributes, so you are unable to recall what happened. If you really don't want to use a dedicated variable, change your P class to look like this:
class P(ABC):
...
def set_pre(self, tag_value):
index = len(self._pre_map)
print(index)
self._pre_map[index] = tag_value
self._pre_order.append(index)
return self
...
And use CP().set_pre("test string added").execute()

Python - How to return a the details of each Room instance in a list, from inside of a Map instance

I am working on a small text adventure in python, and am attempting to use classes. I'm not very well versed in OOP and although I feel like I'm slowly gaining a greater understanding...I know that I still have a ways to go.
This is my room class
#!usr/bin/env python3
"""
A room class and a method to load room data from json files
"""
import json
class Room():
def __init__(
self,
id = "0",
name = "An empty room",
desc = "There is nothing here",
items = {},
exits = {},
):
self.id = id
self.name = name
self.desc = desc
self.items = items
self.exits = exits
def __str__(self):
return "{}\n{}\n{}\n{}".format(self.name, self.desc, self.items, self.exits)
# Create method to verify exits
def _exits(self, dir):
if dir in self.exits:
return self.exits[dir]
else:
return None
def north(self):
return self._exits('n')
def south(self):
return self._exits('s')
def east(self):
return self._exits('e')
def west(self):
return self._exits('w')
# Create method to get room info from json file
def get_room(id):
ret = None
with open("data/{}.json".format(str(id)) , "r") as f:
jsontext = f.read()
d = json.loads(jsontext, strict = False)
d['id'] = id
ret = Room(**d)
return ret
This is my map class
#!/usr/bin/env python3
from rooms import *
"""
Map class used to build a map from all of the rooms
"""
class Map():
def __init__(self, rooms = {}):
self.rooms = rooms
def __str__(self):
return map(str, rooms)
def build_map(id, num_of_rooms):
rooms = {}
room_count = 0
while room_count < num_of_rooms:
rooms[id] = get_room(id)
id += 1
room_count += 1
return rooms
a_map = Map(build_map(1, 3))
def test_map(map):
return map.rooms
print(test_map(a_map))
I'm not understanding why test_map only returns a list of objects, and was wondering how I might be able to receive the actual list of rooms so that I can confirm that they were created properly. I'm sure that I'm just going about this the COMPLETE wrong way...which is why I've come here with the issue.
For general information about __str__ and __repr__, Check out this answer.
In this case, here's what's happening:
Your __str__ function on Map doesn't return a string, it returns a map object. __str__ must return a string.
That's not causing an error because the function isn't getting called, here: test_map returns the given Map's rooms attribute, which is a dictionary. If you tried to do print(a_map) you'd get an exception.
Dictionaries have their own __str__ method, which is getting called here but the dictionary's __str__ method calls __repr__ on its members, which you haven't defined. (See the linked answer for details on why this is so.)
When you haven't defined a __repr__ for your class, you get the __repr__ from object, which is why your print(test_map(a_map)) gives you output like {1: <__main__.Room instance at 0x7fca06a5b6c8>, 2: <__main__.Room instance at 0x7fca06ac3098>, 3: <__main__.Room instance at 0x7fca06ac36c8>}.
What I'd suggest:
Write __repr__ functions for both Map and Room.
Have Map.__repr__ return a string that indirectly relies on Room.__repr__, something like the following:
def __repr__(self):
return '<Map: {}>'.format(self.rooms)
This isn't maybe the best long-term approach - what if you have a map with a hundred rooms? - but it should get you going and you can experiment with what works best for you.

Resources