-
What the right way to add multiple components like one PREF+WORK phone + one HOME phone number? j = vobject.vCard()
j.add('fn')
j.fn.value = "Foo"
j.add('tel')
j.tel.value = "+12345"
j.tel.type_param = "WORK"
# Add a HOME phone
# j.add('tel') # won't work: override the existing tel
# j.tel.value = "+67890"
# j.tel.type_param = "HOME" I found nothing in the doc or the tests and the code itself didn't make it self-explanatory either. I also wonder about Line 30 in 43223ae |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 4 replies
-
Let me answer the second part first. There are three versions of the vCard specification in use: 2.1, 3.0, and 4.0. In vCard 2.1, the "TEL" element can have type parameters, whose names can be "HOME", "WORK", etc, but also "PREF", indicating a "preferred number". The example from the spec is:
In vCard 3.0, this was changed. To quote the spec,
So rather than the old syntax with a list of semi-colon separated values after the TEL, there's now either "TYPE=foo,bar,baz" OR "TYPE=foo;TYPE=bar;TYPE=baz" styles. The example from the 3.0 spec shows that "PREF" is still a type of number, like "HOME", etc.
In vCard 4.0, this was changed again. A preferred number is now indicated by a separate parameter. The example from the 4.0 spec is (ignore the "VALUE=uri" bit, and the quotes around the TYPE parameter's values -- those are different changes):
The key thing is that PREF is now an independent parameter, a peer of TYPE, rather than a possible value of TYPE. The first test case you cited is testing the 2.1-era syntax (for email, but they're the same). The second example is 3.0 syntax, using two TYPE parameters each with a single value, including the one with "pref". We don't yet support vCard 4.0, but it's on the list ... I hope this helps clarify the context. I appreciate that it's a bit of a nightmare :-) |
Beta Was this translation helpful? Give feedback.
-
Firstly, allow me to say that the programmer's API for vObject is, well ... awful. I have plans to improve that, but for now we're stuck with 21 year old decisions that don't seem too good from this end of history (no disrespect to Jeffrey Harris, but Python style in 2025 is a little different!) Now, the practical: I suggest a slightly different pattern when adding components to a card, which makes this easier: save the created component as a local variable.
This has no real value over the Step 1, using that syntax, it's easy to create and populate a second TEL component:
Step 2, the syntax for parameters is non-intuitive, but it does (mostly) work. The value of a parameter is actually a list. For example, reflecting "TYPE=WORK,HOME" the internal value is
With that understanding, your example can become:
The first caveat is that the parameter's value list doesn't exist unless you assign to it. So, for instance,
will throw a The second caveat is that internally, vObject stores the parameters of a component as a standard Python dictionary, with string keys (like, Sorry for the long-winded response, but I hope this both explains both how to make it work, and why that's needed! |
Beta Was this translation helpful? Give feedback.
Firstly, allow me to say that the programmer's API for vObject is, well ... awful. I have plans to improve that, but for now we're stuck with 21 year old decisions that don't seem too good from this end of history (no disrespect to Jeffrey Harris, but Python style in 2025 is a little different!)
Now, the practical:
I suggest a slightly different pattern when adding components to a card, which makes this easier: save the created component as a local variable.
This has no real value over the
j.tel.value = "Foo"
syntax in simple cases, but it does make access easier when dealing with multiple same-named components.Step 1, using that syn…